add new
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package cihook
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func Parse(b []byte) (*PipelineEvent, error) {
|
||||
p := &PipelineEvent{}
|
||||
if err := json.Unmarshal(b, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package cihook
|
||||
|
||||
import "time"
|
||||
|
||||
type PipelineEvent struct {
|
||||
ID string `json:"id"`
|
||||
EventType string `json:"eventType"`
|
||||
PublisherID string `json:"publisherId"`
|
||||
Message struct {
|
||||
Text string `json:"text"`
|
||||
HTML string `json:"html"`
|
||||
Markdown string `json:"markdown"`
|
||||
} `json:"message"`
|
||||
DetailedMessage struct {
|
||||
Text string `json:"text"`
|
||||
HTML string `json:"html"`
|
||||
Markdown string `json:"markdown"`
|
||||
} `json:"detailedMessage"`
|
||||
Resource struct {
|
||||
Run struct {
|
||||
Links struct {
|
||||
Self struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"self"`
|
||||
Web struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"web"`
|
||||
PipelineWeb struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"pipeline.web"`
|
||||
Pipeline struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"pipeline"`
|
||||
} `json:"_links"`
|
||||
Pipeline struct {
|
||||
URL string `json:"url"`
|
||||
ID int `json:"id"`
|
||||
Revision int `json:"revision"`
|
||||
Name string `json:"name"`
|
||||
Folder string `json:"folder"`
|
||||
} `json:"pipeline"`
|
||||
State string `json:"state"`
|
||||
Result string `json:"result"`
|
||||
CreatedDate time.Time `json:"createdDate"`
|
||||
FinishedDate time.Time `json:"finishedDate"`
|
||||
URL string `json:"url"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"run"`
|
||||
Pipeline struct {
|
||||
URL string `json:"url"`
|
||||
ID int `json:"id"`
|
||||
Revision int `json:"revision"`
|
||||
Name string `json:"name"`
|
||||
Folder string `json:"folder"`
|
||||
} `json:"pipeline"`
|
||||
} `json:"resource"`
|
||||
ResourceVersion string `json:"resourceVersion"`
|
||||
ResourceContainers struct {
|
||||
Collection struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"collection"`
|
||||
Account struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"account"`
|
||||
Project struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"project"`
|
||||
} `json:"resourceContainers"`
|
||||
CreatedDate time.Time `json:"createdDate"`
|
||||
}
|
||||
@@ -1,16 +1,75 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.trj.tw/golang/utils"
|
||||
"github.com/jesseduffield/yaml"
|
||||
"github.com/otakukaze/envconfig"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Port int `yaml:"port" env:"SERVER_PORT"`
|
||||
}
|
||||
|
||||
type Remote struct {
|
||||
WSLoc string `yaml:"ws_loc" env:"REMOTE_WS_LOC"`
|
||||
}
|
||||
|
||||
type LED struct {
|
||||
Count int `yaml:"count" env:"LED_COUNT"`
|
||||
Pin int `yaml:"pin" env:"LED_PIN"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Server Server `yaml:"server"`
|
||||
Remote Remote `yaml:"remote"`
|
||||
LED LED `yaml:"led"`
|
||||
}
|
||||
|
||||
var c *Config
|
||||
|
||||
func Load(p ...string) error {
|
||||
var fp string
|
||||
if len(p) > 0 && p[0] != "" {
|
||||
fp = p[0]
|
||||
} else {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fp = path.Join(wd, "config.yml")
|
||||
}
|
||||
|
||||
fp = utils.ParsePath(fp)
|
||||
|
||||
if !utils.CheckExists(fp, false) {
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
// read config file
|
||||
b, err := ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c = &Config{}
|
||||
|
||||
if err := yaml.Unmarshal(b, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
envconfig.Parse(c)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Get() *Config {
|
||||
if c == nil {
|
||||
panic(errors.New("config not init"))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.trj.tw/golang/utils"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
var db *bbolt.DB
|
||||
|
||||
func New(dbPath ...string) error {
|
||||
var err error
|
||||
var fp string
|
||||
|
||||
if len(dbPath) > 0 && dbPath[0] != "" {
|
||||
fp = dbPath[0]
|
||||
} else {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fp = path.Join(wd, "store.db")
|
||||
}
|
||||
|
||||
fp = utils.ParsePath(fp)
|
||||
|
||||
db, err = bbolt.Open(fp, 0664, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Get() *bbolt.DB {
|
||||
if db == nil {
|
||||
panic(errors.New("database not init"))
|
||||
}
|
||||
return db
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package led
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"rpi-ci-led/pkg/ws2812b"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LEDSvc struct {
|
||||
pin int
|
||||
count int
|
||||
blink map[int]chan struct{}
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
var led *LEDSvc
|
||||
|
||||
func Init(pin, count int) (*LEDSvc, error) {
|
||||
_, err := ws2812b.Init(pin, count, 255)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LEDSvc{
|
||||
pin: pin,
|
||||
count: count,
|
||||
blink: make(map[int]chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func Get() *LEDSvc {
|
||||
if led == nil {
|
||||
panic(errors.New("not init"))
|
||||
}
|
||||
return led
|
||||
}
|
||||
|
||||
func (p *LEDSvc) SetColor(pos int, color uint32) error {
|
||||
if pos < 0 || pos > p.count {
|
||||
return errors.New("out of range")
|
||||
}
|
||||
if ch, ok := p.blink[pos]; ok {
|
||||
close(ch)
|
||||
delete(p.blink, pos)
|
||||
}
|
||||
ws2812b.WriteColor(pos, color)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LEDSvc) StopBlink(pos int) {
|
||||
if ch, ok := p.blink[pos]; ok {
|
||||
close(ch)
|
||||
delete(p.blink, pos)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *LEDSvc) SetBlink(pos int, color uint32, interval time.Duration) {
|
||||
if ch, ok := p.blink[pos]; ok {
|
||||
close(ch)
|
||||
delete(p.blink, pos)
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
ws2812b.WriteColor(pos, 0)
|
||||
delete(p.blink, pos)
|
||||
}()
|
||||
|
||||
ch := make(chan struct{})
|
||||
p.blink[pos] = ch
|
||||
timer := time.NewTicker(interval)
|
||||
on := false
|
||||
for {
|
||||
select {
|
||||
case <-ch:
|
||||
return
|
||||
case <-timer.C:
|
||||
if on {
|
||||
ws2812b.WriteColor(pos, 0)
|
||||
} else {
|
||||
ws2812b.WriteColor(pos, color)
|
||||
}
|
||||
on = !on
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *LEDSvc) Run() {
|
||||
ticker := time.NewTicker(time.Millisecond * 100)
|
||||
for {
|
||||
select {
|
||||
case <-p.done:
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type Socket struct {
|
||||
*websocket.Conn
|
||||
Listeners map[string](chan<- []byte)
|
||||
done chan struct{}
|
||||
errd bool
|
||||
errsig chan error
|
||||
}
|
||||
|
||||
var client *Socket
|
||||
|
||||
func NewClient(remote string) (*Socket, error) {
|
||||
if remote == "" {
|
||||
return nil, errors.New("remote url is empty")
|
||||
}
|
||||
var err error
|
||||
|
||||
headers := http.Header{}
|
||||
|
||||
headers.Set(
|
||||
textproto.CanonicalMIMEHeaderKey("X-Auth-Key"),
|
||||
"rpi",
|
||||
)
|
||||
c, resp, err := websocket.DefaultDialer.Dial(remote, headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
client = &Socket{
|
||||
Conn: c,
|
||||
Listeners: make(map[string](chan<- []byte)),
|
||||
done: make(chan struct{}, 0),
|
||||
errd: false,
|
||||
errsig: make(chan error),
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (p *Socket) Listen() error {
|
||||
go func() {
|
||||
defer close(p.done)
|
||||
for {
|
||||
_, msg, err := p.ReadMessage()
|
||||
if err != nil {
|
||||
p.errsig <- err
|
||||
}
|
||||
|
||||
for _, v := range p.Listeners {
|
||||
v <- msg
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-p.done:
|
||||
return nil
|
||||
case err := <-p.errsig:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Socket) AddListener(alias string, c chan<- []byte) error {
|
||||
if _, ok := p.Listeners[alias]; ok {
|
||||
return errors.New("listener name exists")
|
||||
}
|
||||
p.Listeners[alias] = c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Socket) RemoveListener(alias string) error {
|
||||
if v, ok := p.Listeners[alias]; !ok {
|
||||
return errors.New("listener not exists")
|
||||
} else {
|
||||
close(v)
|
||||
delete(p.Listeners, alias)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -23,6 +23,7 @@ func Init(gpio, count, brightness int) (*LED, error) {
|
||||
|
||||
err := ws2811.Init(gpio, count, brightness)
|
||||
if err != nil {
|
||||
led = nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -36,15 +37,30 @@ func Init(gpio, count, brightness int) (*LED, error) {
|
||||
return led, nil
|
||||
}
|
||||
|
||||
func IsInit() bool {
|
||||
if led == nil {
|
||||
return false
|
||||
}
|
||||
return led.IsInit
|
||||
}
|
||||
|
||||
func Close() {
|
||||
ws2811.Clear()
|
||||
ws2811.Fini()
|
||||
led.IsInit = false
|
||||
}
|
||||
|
||||
func ClearAll() {
|
||||
ws2811.Clear()
|
||||
}
|
||||
|
||||
func Len() int {
|
||||
if led == nil {
|
||||
return 0
|
||||
}
|
||||
return led.Count
|
||||
}
|
||||
|
||||
func WriteColor(pos int, color uint32) error {
|
||||
if pos < 0 || pos > led.Count {
|
||||
return errors.New("position out of range")
|
||||
|
||||
Reference in New Issue
Block a user