add new
This commit is contained in:
parent
d7f1b47860
commit
31150c8280
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.env
|
7
config/config.yml
Normal file
7
config/config.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
server:
|
||||||
|
port: 10230
|
||||||
|
remote:
|
||||||
|
ws_loc: ''
|
||||||
|
led:
|
||||||
|
pin: 18
|
||||||
|
count: 2
|
15
go.mod
15
go.mod
@ -2,4 +2,17 @@ module rpi-ci-led
|
|||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require github.com/jgarff/rpi_ws281x v0.0.0-20200319211106-6a720cbd42d3
|
require (
|
||||||
|
git.trj.tw/golang/argparse v1.0.1
|
||||||
|
git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349
|
||||||
|
github.com/gorilla/websocket v1.4.2
|
||||||
|
github.com/jesseduffield/yaml v2.1.0+incompatible
|
||||||
|
github.com/jgarff/rpi_ws281x v0.0.0-20200319211106-6a720cbd42d3
|
||||||
|
github.com/joho/godotenv v1.3.0
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
|
github.com/otakukaze/envconfig v1.0.4
|
||||||
|
go.etcd.io/bbolt v1.3.4
|
||||||
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 // indirect
|
||||||
|
)
|
||||||
|
28
go.sum
28
go.sum
@ -1,2 +1,30 @@
|
|||||||
|
git.trj.tw/golang/argparse v1.0.1 h1:fLXwn8EUEXBwJEYvFgz0JTyy1q/UhucN6pIDIND87lI=
|
||||||
|
git.trj.tw/golang/argparse v1.0.1/go.mod h1:Ao2nzs4Fv+W/KgI8pDBgrcAC24IYE7DAzzUEOkTmqT4=
|
||||||
|
git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 h1:V6ifeiJ3ExnjaUylTOz37n6z5uLwm6fjKjnztbTCaQI=
|
||||||
|
git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349/go.mod h1:yE+qbsUsijCTdwsaQRkPT1CXYk7ftMzXsCaaYx/0QI0=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
||||||
|
github.com/jesseduffield/yaml v2.1.0+incompatible/go.mod h1:w0xGhOSIJCGYYW+hnFPTutCy5aACpkcwbmORt5axGqk=
|
||||||
github.com/jgarff/rpi_ws281x v0.0.0-20200319211106-6a720cbd42d3 h1:Gmtr3J666u+wiChtQ49FYzcdd6UgX0aWoLciRPo3His=
|
github.com/jgarff/rpi_ws281x v0.0.0-20200319211106-6a720cbd42d3 h1:Gmtr3J666u+wiChtQ49FYzcdd6UgX0aWoLciRPo3His=
|
||||||
github.com/jgarff/rpi_ws281x v0.0.0-20200319211106-6a720cbd42d3/go.mod h1:xbXlgWZjA66nkwNqkT4ol2EqY7jL8v+1efK5ZnOT/MU=
|
github.com/jgarff/rpi_ws281x v0.0.0-20200319211106-6a720cbd42d3/go.mod h1:xbXlgWZjA66nkwNqkT4ol2EqY7jL8v+1efK5ZnOT/MU=
|
||||||
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/otakukaze/envconfig v1.0.4 h1:/rZ8xq1vFpgWzqsqUkk61doDGNv9pIXqrog/mCvSx8Y=
|
||||||
|
github.com/otakukaze/envconfig v1.0.4/go.mod h1:v2dNv5NX1Lakw3FTAkbxYURyaiOy68M8QpMTZz+ogfs=
|
||||||
|
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||||
|
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
|
||||||
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
50
main.go
50
main.go
@ -2,11 +2,17 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"rpi-ci-led/pkg/config"
|
||||||
|
"rpi-ci-led/pkg/database"
|
||||||
|
"rpi-ci-led/pkg/led"
|
||||||
|
"rpi-ci-led/pkg/websocket"
|
||||||
"rpi-ci-led/pkg/ws2812b"
|
"rpi-ci-led/pkg/ws2812b"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"git.trj.tw/golang/argparse"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,14 +21,56 @@ func main() {
|
|||||||
|
|
||||||
godotenv.Load()
|
godotenv.Load()
|
||||||
|
|
||||||
ws2812b.Init(18, 20, 255)
|
var configFile string
|
||||||
|
var dbPath string
|
||||||
|
|
||||||
|
// argument parser
|
||||||
|
argParser := argparse.New()
|
||||||
|
argParser.Help("h", "help")
|
||||||
|
argParser.StringVar(&configFile, "", "f", "config", "config yaml file path", nil)
|
||||||
|
argParser.StringVar(&dbPath, "", "d", "db", "database file path", nil)
|
||||||
|
if err := argParser.Parse(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.Load(configFile); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := database.New(dbPath); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conf := config.Get()
|
||||||
|
|
||||||
|
socket, err := websocket.NewClient(conf.Remote.WSLoc)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ledsvc, err := led.Init(conf.LED.Pin, conf.LED.Count)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
lock := make(chan os.Signal)
|
lock := make(chan os.Signal)
|
||||||
signal.Notify(lock, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(lock, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
// main
|
// main
|
||||||
|
go func() {
|
||||||
|
if err := socket.Listen(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
lock <- syscall.SIGQUIT
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() { ledsvc.Run() }()
|
||||||
|
|
||||||
|
// start ws client connect to server
|
||||||
|
|
||||||
<-lock
|
<-lock
|
||||||
|
|
||||||
|
fmt.Printf("Before process exit, close all connection\n")
|
||||||
|
socket.Close()
|
||||||
ws2812b.Close()
|
ws2812b.Close()
|
||||||
}
|
}
|
||||||
|
11
pkg/cihook/cihook.go
Normal file
11
pkg/cihook/cihook.go
Normal file
@ -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
|
||||||
|
}
|
71
pkg/cihook/types.go
Normal file
71
pkg/cihook/types.go
Normal file
@ -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
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"git.trj.tw/golang/utils"
|
||||||
|
"github.com/jesseduffield/yaml"
|
||||||
|
"github.com/otakukaze/envconfig"
|
||||||
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Port int `yaml:"port" env:"SERVER_PORT"`
|
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 {
|
type Config struct {
|
||||||
Server Server `yaml:"server"`
|
Server Server `yaml:"server"`
|
||||||
|
Remote Remote `yaml:"remote"`
|
||||||
|
LED LED `yaml:"led"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var c *Config
|
var c *Config
|
||||||
|
|
||||||
func Load(p ...string) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Get() *Config {
|
||||||
|
if c == nil {
|
||||||
|
panic(errors.New("config not init"))
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
43
pkg/database/database.go
Normal file
43
pkg/database/database.go
Normal file
@ -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
|
||||||
|
}
|
97
pkg/led/led.go
Normal file
97
pkg/led/led.go
Normal file
@ -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:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
pkg/websocket/websocket.go
Normal file
91
pkg/websocket/websocket.go
Normal file
@ -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)
|
err := ws2811.Init(gpio, count, brightness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
led = nil
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,15 +37,30 @@ func Init(gpio, count, brightness int) (*LED, error) {
|
|||||||
return led, nil
|
return led, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsInit() bool {
|
||||||
|
if led == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return led.IsInit
|
||||||
|
}
|
||||||
|
|
||||||
func Close() {
|
func Close() {
|
||||||
ws2811.Clear()
|
ws2811.Clear()
|
||||||
ws2811.Fini()
|
ws2811.Fini()
|
||||||
|
led.IsInit = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClearAll() {
|
func ClearAll() {
|
||||||
ws2811.Clear()
|
ws2811.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Len() int {
|
||||||
|
if led == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return led.Count
|
||||||
|
}
|
||||||
|
|
||||||
func WriteColor(pos int, color uint32) error {
|
func WriteColor(pos int, color uint32) error {
|
||||||
if pos < 0 || pos > led.Count {
|
if pos < 0 || pos > led.Count {
|
||||||
return errors.New("position out of range")
|
return errors.New("position out of range")
|
||||||
|
Loading…
Reference in New Issue
Block a user