16 Commits

Author SHA1 Message Date
Adrian Zuercher
a34f93e169 add status server for driver state
All checks were successful
Build ArtNet Driver / build (amd64, .exe, windows) (push) Successful in 3m49s
Build ArtNet Driver / build (amd64, , linux) (push) Successful in 3m58s
Build ArtNet Driver / build (arm, 6, , linux) (push) Successful in 3m30s
Build ArtNet Driver / build (arm64, , linux) (push) Successful in 3m31s
2025-09-07 14:22:44 +02:00
Adrian Zuercher
ede86b71ef repo name change
All checks were successful
Build ArtNet Driver / build (amd64, , linux) (push) Successful in 1m40s
Build ArtNet Driver / build (amd64, .exe, windows) (push) Successful in 1m41s
Build ArtNet Driver / build (arm, 6, , linux) (push) Successful in 1m39s
Build ArtNet Driver / build (arm64, , linux) (push) Successful in 1m38s
2025-08-06 22:41:34 +02:00
Adrian Zuercher
67f25c76ae rename folder .github t .gitea
Some checks failed
Build Go Binaries / build (arm, linux) (push) Has been cancelled
Build Go Binaries / build (arm64, linux) (push) Has been cancelled
Build Go Binaries / build (amd64, linux) (push) Has been cancelled
Build Go Binaries / build (amd64, windows) (push) Has been cancelled
2025-08-02 09:58:12 +02:00
Adrian Zuercher
7ef6e614cc update to newest json_data model 2025-07-31 12:27:53 +02:00
Adrian Zuercher
49dff4f609 update json_data and model so more than one address can be revieved from server 2025-07-30 17:16:50 +02:00
Adrian Zuercher
3704edebd5 fix wrong call and missing send set 2025-07-27 13:07:16 +02:00
Adrian Zuercher
a503b71fb6 add read write lock to dmx data 2025-07-26 07:18:26 +02:00
Adrian Zuercher
05409c2544 change send data to dmx as 23 millisecond ticker when new data 2025-07-25 22:37:35 +02:00
Adrian Zuercher
b484745ed1 increase timeout of ping from 10 to 40 2025-07-25 20:59:17 +02:00
Adrian Zuercher
04e306c6da update to latest json_data 2025-07-24 09:57:16 +02:00
Adrian Zuercher
239e0050a1 change ping pong handler and fix blocking channel 2025-07-23 08:56:43 +02:00
Adrian Zuercher
de4758c563 fix mmissing defer for close channel and move make channel up earlier 2025-07-20 09:03:45 +02:00
Adrian Zuercher
a85c9ccd66 Merge branch 'main' of https://github.com/tecamino/tecamino-driver-artNet 2025-07-16 22:00:53 +02:00
Adrian Zuercher
da78a00446 add heartbeat send data every 30 Seconds 2025-07-16 21:53:47 +02:00
Adrian Zuercher
ba3c55dc34 add mac DS_Store 2025-07-16 21:52:31 +02:00
zuadi
e0950b44ee Update build.yml add flags for smaller executable 2025-07-13 20:07:44 +02:00
15 changed files with 349 additions and 238 deletions

View File

@@ -0,0 +1,89 @@
name: Build ArtNet Driver
on:
push:
tags:
- '*'
env:
APP_NAME: tecamino-driver-artNet
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- os: windows
arch: amd64
ext: .exe
- os: linux
arch: amd64
ext: ""
- os: linux
arch: arm64
ext: ""
- os: linux
arch: arm
arm_version: 6
ext: ""
steps:
- uses: actions/checkout@v4
- name: Ensure latest Go is installed in /data/go
run: |
export GOROOT=/data/go/go
export PATH=$GOROOT/bin:$PATH
export GOCACHE=/data/gocache
export GOMODCACHE=/data/gomodcache
mkdir -p $GOCACHE $GOMODCACHE
if [ ! -x "$GOROOT/bin/go" ]; then
echo "Go not found in $GOROOT, downloading latest stable..."
GO_VERSION=$(curl -s https://go.dev/VERSION?m=text | head -n1)
echo "Latest version is $GO_VERSION"
mkdir -p /data/go
curl -sSL "https://go.dev/dl/${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tar.gz
tar -C /data/go -xzf /tmp/go.tar.gz
else
echo "Using cached Go from $GOROOT"
fi
go version
- name: Download Go dependencies
run: |
export GOROOT=/data/go/go
export PATH=$GOROOT/bin:$PATH
export GOCACHE=/data/gocache
export GOMODCACHE=/data/gomodcache
mkdir -p $GOCACHE $GOMODCACHE
go mod download
- name: Build binary
run: |
export GOROOT=/data/go/go
export PATH=$GOROOT/bin:$PATH
export GOCACHE=/data/gocache
export GOMODCACHE=/data/gomodcache
mkdir -p $GOCACHE $GOMODCACHE
OUTPUT="bin/${APP_NAME}-${{ matrix.os }}-${{ matrix.arch }}"
if [ -n "${{ matrix.arm_version }}" ]; then
OUTPUT="${OUTPUT}v${{ matrix.arm_version }}"
export GOARM=${{ matrix.arm_version }}
fi
OUTPUT="${OUTPUT}${{ matrix.ext }}"
echo "Building $OUTPUT"
GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} go build -ldflags="-s -w" -trimpath -o "$OUTPUT"
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ env.APP_NAME }}-${{ matrix.os }}-${{ matrix.arch }}
path: bin/

View File

@@ -1,48 +0,0 @@
name: Build Go Binaries
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, windows]
goarch: [amd64, arm, arm64]
exclude:
- goos: windows
goarch: arm
- goos: windows
goarch: arm64
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.24.0'
- name: Set up Git credentials for private modules
run: |
git config --global url."https://${{ secrets.GH_PAT }}@github.com/".insteadOf "https://github.com/"
echo "GOPRIVATE=github.com/tecamino/*" >> $GITHUB_ENV
- name: Build binary
run: |
mkdir -p build
if [ "${{ matrix.goos }}" == "windows" ]; then
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o build/tecamino-driver-artNet-${{ matrix.goos }}-${{ matrix.goarch }}.exe main.go
else
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o build/tecamino-driver-artNet-${{ matrix.goos }}-${{ matrix.goarch }} main.go
fi
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: binaries-${{ matrix.goos }}-${{ matrix.goarch }}
path: build/

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.DS_Store
*.cfg *.cfg
*.log *.log
artNetDriver-arm64 artNetDriver-arm64

View File

@@ -5,25 +5,29 @@ import (
"artNet/models" "artNet/models"
ws "artNet/websocket" ws "artNet/websocket"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"path" "path"
json_data "github.com/tecamino/tecamino-json_data" "gitea.tecamino.com/paadi/statusServer"
"github.com/tecamino/tecamino-logger/logging" json_data "gitea.tecamino.com/paadi/tecamino-json_data"
"gitea.tecamino.com/paadi/tecamino-logger/logging"
"github.com/gin-gonic/gin"
) )
type ArtNetDriver struct { type ArtNetDriver struct {
Name string `yaml:"driver" json:"driver"` statusServer *statusServer.StatusClient `yaml:"-" json:"-"`
Buses map[string]*models.Bus `yaml:"buses,omitempty" json:"buses,omitempty"` Name string `yaml:"driver" json:"driver"`
cfgHandler *cfg.Cfg `yaml:"-" json:"-"` Buses map[string]*models.Bus `yaml:"buses,omitempty" json:"buses,omitempty"`
Subscriptions models.Subscriptions `yaml:"-" json:"-"` cfgHandler *cfg.Cfg `yaml:"-" json:"-"`
Log *logging.Logger `yaml:"-" json:"-"` Subscriptions models.Subscriptions `yaml:"-" json:"-"`
Log *logging.Logger `yaml:"-" json:"-"`
} }
// initialize new Art-Net driver // initialize new Art-Net driver
// cfgDir config directory // cfgDir config directory
// name name of driver // name name of driver
func NewDriver(cfgDir, name string, debug bool) (*ArtNetDriver, error) { func NewDriver(cfgDir, name, ip string, port uint, debug bool) (*ArtNetDriver, error) {
if cfgDir == "" { if cfgDir == "" {
cfgDir = "./cfg" cfgDir = "./cfg"
} }
@@ -39,12 +43,18 @@ func NewDriver(cfgDir, name string, debug bool) (*ArtNetDriver, error) {
panic(err) panic(err)
} }
statusS, err := statusServer.NewStatusClient(name, ip, "api/status", port, false)
if err != nil {
return nil, errors.New("status server: " + err.Error())
}
logger.Debug("artNet.NewDriver", "initialize "+name+" driver") logger.Debug("artNet.NewDriver", "initialize "+name+" driver")
d := ArtNetDriver{ d := ArtNetDriver{
Name: name, statusServer: statusS,
Buses: make(map[string]*models.Bus), Name: name,
cfgHandler: cfg.NewCfgHandler(cfgDir, name), Buses: make(map[string]*models.Bus),
Log: logger, cfgHandler: cfg.NewCfgHandler(cfgDir, name),
Log: logger,
} }
if err := d.LoadCfg(); err != nil { if err := d.LoadCfg(); err != nil {
@@ -78,10 +88,10 @@ func (d *ArtNetDriver) SetValue(bus string, address uint, value uint8) error {
if _, ok := d.Buses[bus]; !ok { if _, ok := d.Buses[bus]; !ok {
return fmt.Errorf("no bus '%s' found", bus) return fmt.Errorf("no bus '%s' found", bus)
} }
if d.Buses[bus].Data == nil { if d.Buses[bus].DMX.Data == nil {
return fmt.Errorf("no dmx data on bus '%s' found", bus) return fmt.Errorf("no dmx data on bus '%s' found", bus)
} }
d.Buses[bus].Data.SetValue(address, value) d.Buses[bus].SetDMXData(address, value)
return nil return nil
} }
@@ -90,33 +100,49 @@ func (d *ArtNetDriver) SetValue(bus string, address uint, value uint8) error {
// id: id of driver // id: id of driver
// port: port of server // port: port of server
func (d *ArtNetDriver) Connect(ip, id string, port uint) error { func (d *ArtNetDriver) Connect(ip, id string, port uint) error {
topic := "status/" + id
d.statusServer.Publish(topic, gin.H{
"state": "Starting",
})
defer d.statusServer.Publish(topic, gin.H{
"state": "Stopped",
})
errChan := make(chan error) errChan := make(chan error)
client, err := ws.NewClient(ip, id, port) client, err := ws.NewClient(ip, id, port)
if err != nil { if err != nil {
d.statusServer.Publish(topic, gin.H{
"state": "Error",
"message": err.Error()})
return err return err
} }
client.OnError = func(err error) { client.OnError = func(err error) {
d.statusServer.Publish(topic, gin.H{"state": "Error", "message": err.Error()})
d.Log.Error("websocket connection", err) d.Log.Error("websocket connection", err)
errChan <- err errChan <- err
} }
client.OnMessage = func(data []byte) { client.OnMessage = func(data []byte) {
request := json_data.NewResponse() request := json_data.NewResponse()
err = json.Unmarshal(data, &request) err = json.Unmarshal(data, &request)
if err != nil { if err != nil {
d.statusServer.Publish(topic, gin.H{"state": "Error", "message": err.Error()})
return return
} }
if request.Subscribe != nil { if request.Subscribe != nil {
d.Subscribe(request.Subscribe...) d.Subscribe(request.Subscribe...)
} }
if request.Publish != nil { if request.Publish != nil {
d.Publish(request.Publish...) d.Publish(request.Publish...)
} }
} }
if err != nil { if err != nil {
d.statusServer.Publish("error", err.Error())
d.Log.Error("artNet.Connect", err) d.Log.Error("artNet.Connect", err)
return err return err
} }
@@ -129,15 +155,19 @@ func (d *ArtNetDriver) Connect(ip, id string, port uint) error {
d.Log.Error("websocket send data", err) d.Log.Error("websocket send data", err)
} }
d.statusServer.Publish(topic, gin.H{"state": "Running"})
for err := range errChan { for err := range errChan {
d.statusServer.Publish(topic, gin.H{"state": "Error", "message": err.Error()})
return err return err
} }
return nil return nil
} }
// send data to all buses that the send flage is true // send data to all buses that the send flage is true
func (d *ArtNetDriver) SendData() { func (d *ArtNetDriver) SendData() {
for _, bus := range d.Buses { for _, bus := range d.Buses {
bus.Send <- bus.Data bus.Send = bus.Reachable
} }
} }

View File

@@ -7,9 +7,9 @@ import (
"net" "net"
"net/http" "net/http"
json_data "gitea.tecamino.com/paadi/tecamino-json_data"
json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
json_data "github.com/tecamino/tecamino-json_data"
json_dataModels "github.com/tecamino/tecamino-json_data/models"
) )
// sends a list of all buses in the driver // sends a list of all buses in the driver
@@ -110,6 +110,7 @@ func (d *ArtNetDriver) Start(c *gin.Context) {
} }
d.Buses[busPayload.Name].Start(d.Log) d.Buses[busPayload.Name].Start(d.Log)
d.statusServer.Publish(fmt.Sprintf("status/%s/%s", d.Name, busPayload.Name), "Running")
r := json_dataModels.NewResponse() r := json_dataModels.NewResponse()
r.SetMessage(fmt.Sprintf("bus '%s' running", busPayload.Name)) r.SetMessage(fmt.Sprintf("bus '%s' running", busPayload.Name))
@@ -132,6 +133,7 @@ func (d *ArtNetDriver) Stop(c *gin.Context) {
} }
d.Buses[busPayload.Name].Stop() d.Buses[busPayload.Name].Stop()
d.statusServer.Publish(fmt.Sprintf("status/%s/%s", d.Name, busPayload.Name), "Stopped")
r := json_dataModels.NewResponse() r := json_dataModels.NewResponse()
r.SetMessage(fmt.Sprintf("bus '%s' stopped", busPayload.Name)) r.SetMessage(fmt.Sprintf("bus '%s' stopped", busPayload.Name))

View File

@@ -1,7 +1,7 @@
package driver package driver
import ( import (
json_dataModels "github.com/tecamino/tecamino-json_data/models" json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models"
) )
func (d *ArtNetDriver) Publish(pubs ...json_dataModels.Publish) error { func (d *ArtNetDriver) Publish(pubs ...json_dataModels.Publish) error {
@@ -10,8 +10,12 @@ func (d *ArtNetDriver) Publish(pubs ...json_dataModels.Publish) error {
} }
for _, pub := range pubs { for _, pub := range pubs {
if drv, ok := (d.Subscriptions)[pub.Uuid]; ok { if subs, ok := (d.Subscriptions)[pub.Uuid]; ok {
d.SetValue(drv.Bus, drv.Address, uint8(pub.Value.(float64))) for _, sub := range subs {
for _, address := range sub.Address {
d.SetValue(sub.Bus, address, uint8(pub.Value.(float64)))
}
}
} }
} }
d.SendData() d.SendData()

View File

@@ -3,7 +3,7 @@ package driver
import ( import (
"artNet/models" "artNet/models"
json_dataModels "github.com/tecamino/tecamino-json_data/models" json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models"
) )
func (d *ArtNetDriver) Subscribe(subs ...json_dataModels.Subscription) { func (d *ArtNetDriver) Subscribe(subs ...json_dataModels.Subscription) {
@@ -14,7 +14,12 @@ func (d *ArtNetDriver) Subscribe(subs ...json_dataModels.Subscription) {
for _, sub := range subs { for _, sub := range subs {
if drv, ok := (*sub.Drivers)[sub.Driver]; ok { if drv, ok := (*sub.Drivers)[sub.Driver]; ok {
d.Subscriptions.AddSubscription(sub.Uuid, drv) d.Subscriptions.AddSubscription(sub.Uuid, drv)
d.SetValue(drv.Bus, drv.Address, uint8(sub.Value.(float64))) for _, bus := range drv.Buses {
for _, address := range bus.Address {
d.SetValue(bus.Name, address, uint8(sub.Value.(float64)))
}
}
} }
} }
d.SendData() d.SendData()

47
go.mod
View File

@@ -1,46 +1,47 @@
module artNet module artNet
go 1.23.0 go 1.24.0
toolchain go1.23.8
require ( require (
github.com/gin-gonic/gin v1.10.0 gitea.tecamino.com/paadi/statusServer v1.0.3
gitea.tecamino.com/paadi/tecamino-json_data v0.1.0
gitea.tecamino.com/paadi/tecamino-logger v0.2.1
github.com/gin-gonic/gin v1.10.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
github.com/tecamino/tecamino-json_data v0.0.16
github.com/tecamino/tecamino-logger v0.2.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
github.com/bytedance/sonic v1.11.6 // indirect gitea.tecamino.com/paadi/pubSub v1.0.2 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect gitea.tecamino.com/paadi/tecamino-dbm v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect github.com/bytedance/sonic v1.13.3 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/cloudwego/base64x v0.1.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/gin-contrib/cors v1.7.6 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.3.0 // indirect
go.uber.org/multierr v1.10.0 // indirect go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.8.0 // indirect golang.org/x/arch v0.18.0 // indirect
golang.org/x/crypto v0.23.0 // indirect golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.20.0 // indirect golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.15.0 // indirect golang.org/x/text v0.26.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
) )

108
go.sum
View File

@@ -1,32 +1,44 @@
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= gitea.tecamino.com/paadi/pubSub v1.0.2 h1:9Q9KLTIHRSjxrTkDyuF8mDYOLkI8DjjPNSnoS2GKflY=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= gitea.tecamino.com/paadi/pubSub v1.0.2/go.mod h1:SBPTSD/JQWRbwqsSNoSPhV81IDTreP0TMyvLhmK3P2M=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= gitea.tecamino.com/paadi/statusServer v1.0.3 h1:bRw+Jz9AIoiwqNLTBnrus2aUxq2Em2gA8NDANtqVHEA=
gitea.tecamino.com/paadi/statusServer v1.0.3/go.mod h1:kNO/ASrrmsLGgo+k49TLpVP6PpxG3I3D1moJ6Ke+ocg=
gitea.tecamino.com/paadi/tecamino-dbm v0.1.1 h1:vAq7mwUxlxJuLzCQSDMrZCwo8ky5usWi9Qz+UP+WnkI=
gitea.tecamino.com/paadi/tecamino-dbm v0.1.1/go.mod h1:+tmf1rjPaKEoNeUcr1vdtoFIFweNG3aUGevDAl3NMBk=
gitea.tecamino.com/paadi/tecamino-json_data v0.1.0 h1:zp3L8qUvkVqzuesQdMh/SgZZZbX3pGD9NYa6jtz+JvA=
gitea.tecamino.com/paadi/tecamino-json_data v0.1.0/go.mod h1:/FKhbVYuhiNlQp4552rJJQIhynjLarDzfrgXpupkwZU=
gitea.tecamino.com/paadi/tecamino-logger v0.2.1 h1:sQTBKYPdzn9mmWX2JXZBtGBvNQH7cuXIwsl4TD0aMgE=
gitea.tecamino.com/paadi/tecamino-logger v0.2.1/go.mod h1:FkzRTldUBBOd/iy2upycArDftSZ5trbsX5Ira5OzJgM=
github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -35,9 +47,13 @@ github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -47,61 +63,53 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls= github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8= github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8=
github.com/tecamino/tecamino-json_data v0.0.16 h1:aZFxnhm4g6WMDPoqy4HosUk7vl0DB0iIcVs8bbT4MzU=
github.com/tecamino/tecamino-json_data v0.0.16/go.mod h1:LLlyD7Wwqplb2BP4PeO86EokEcTRidlW5MwgPd1T2JY=
github.com/tecamino/tecamino-logger v0.2.0 h1:NPH/Gg9qRhmVoW8b39i1eXu/LEftHc74nyISpcRG+XU=
github.com/tecamino/tecamino-logger v0.2.0/go.mod h1:0M1E9Uei/qw3e3WA1x3lBo1eP3H5oeYE7GjYrMahnj8=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@@ -17,6 +17,8 @@ func main() {
// cli flags // cli flags
cfgDir := flag.String("cfg", "./cfg", "config directory") cfgDir := flag.String("cfg", "./cfg", "config directory")
workingDir := flag.String("workingDirectory", ".", "current working directory") workingDir := flag.String("workingDirectory", ".", "current working directory")
statusServerIp := flag.String("statusIp", "127.0.0.1", "ip address of status server")
statusServerPort := flag.Uint("statusPort", 9500, "port of status server")
serverIp := flag.String("serverIp", "127.0.0.1", "ip address of server") serverIp := flag.String("serverIp", "127.0.0.1", "ip address of server")
serverPort := flag.Uint("serverPort", 8100, "port of server") serverPort := flag.Uint("serverPort", 8100, "port of server")
wsPort := flag.Uint("port", 8200, "websocket port") wsPort := flag.Uint("port", 8200, "websocket port")
@@ -30,9 +32,8 @@ func main() {
} }
//initialize new ArtNet driver //initialize new ArtNet driver
artNetDriver, err := driver.NewDriver(*cfgDir, DriverName, *debug) artNetDriver, err := driver.NewDriver(*cfgDir, DriverName, *statusServerIp, *statusServerPort, *debug)
if err != nil { if err != nil {
artNetDriver.Log.Error("main", "error initialize new artnet driver "+err.Error())
panic(err) panic(err)
} }
@@ -75,6 +76,7 @@ func main() {
if err := artNetDriver.Connect(*serverIp, DriverName, *serverPort); err != nil { if err := artNetDriver.Connect(*serverIp, DriverName, *serverPort); err != nil {
artNetDriver.Log.Error("main", err) artNetDriver.Log.Error("main", err)
} }
artNetDriver.Log.Info("main", "next reconnecting attempt in 10 seconds") artNetDriver.Log.Info("main", "next reconnecting attempt in 10 seconds")
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
} }

View File

@@ -6,13 +6,14 @@ import (
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"sync"
"time" "time"
json_data "gitea.tecamino.com/paadi/tecamino-json_data"
json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models"
"gitea.tecamino.com/paadi/tecamino-logger/logging"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/tatsushid/go-fastping" "github.com/tatsushid/go-fastping"
json_data "github.com/tecamino/tecamino-json_data"
json_dataModels "github.com/tecamino/tecamino-json_data/models"
"github.com/tecamino/tecamino-logger/logging"
) )
// Art-Net constants // Art-Net constants
@@ -25,11 +26,12 @@ type Bus struct {
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Ip string `yaml:"ip" json:"ip"` Ip string `yaml:"ip" json:"ip"`
Port *int `yaml:"port" json:"port,omitempty"` Port *int `yaml:"port" json:"port,omitempty"`
Data *DMX `yaml:"-" json:"-"` DMX *DMX `yaml:"-" json:"-"`
Resubscribe *[]json_dataModels.Subscription `yaml:"-" json:"resubscribe"` Resubscribe *[]json_dataModels.Subscription `yaml:"-" json:"resubscribe"`
Watchdog context.CancelFunc `yaml:"-" json:"-"` Watchdog context.CancelFunc `yaml:"-" json:"-"`
mu sync.Mutex `yaml:"-" json:"-"`
Reachable bool `yaml:"-" json:"-"` Reachable bool `yaml:"-" json:"-"`
Send chan *DMX `yaml:"-" json:"-"` Send bool `yaml:"-" json:"-"`
} }
// adds new Art-Net interface to driver port 0 = 6454 (default art-net) // adds new Art-Net interface to driver port 0 = 6454 (default art-net)
@@ -42,7 +44,7 @@ func NewBus(name, ip string, port int) *Bus {
Name: name, Name: name,
Ip: ip, Ip: ip,
Port: &port, Port: &port,
Data: NewDMXUniverse(), DMX: NewDMXUniverse(),
} }
return &i return &i
} }
@@ -90,7 +92,7 @@ func (b *Bus) Poll(interval time.Duration) error {
} }
}() }()
_, err = conn.Write(NewArtNetPackage(b.Data)) _, err = conn.Write(NewArtNetPackage(b.DMX))
if err != nil { if err != nil {
return err return err
} }
@@ -109,7 +111,7 @@ func (b *Bus) Start(log *logging.Logger) error {
go func() { go func() {
var interval time.Duration = 10 * time.Second var interval time.Duration = 10 * time.Second
log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog stopped", b.Name, b.Ip)) log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog starting", b.Name, b.Ip))
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@@ -126,6 +128,8 @@ func (b *Bus) Start(log *logging.Logger) error {
interval = 5 * time.Second interval = 5 * time.Second
} else { } else {
b.Reachable = true b.Reachable = true
// send data as a heartbeat for she ArtNet Protocol
b.Send = true
log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog running", b.Name, b.Ip)) log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog running", b.Name, b.Ip))
interval = 30 * time.Second interval = 30 * time.Second
} }
@@ -143,20 +147,35 @@ func (b *Bus) Start(log *logging.Logger) error {
return err return err
} }
b.Send = make(chan *DMX, 1024)
go func() { go func() {
defer conn.Close() ticker := time.NewTicker(23 * time.Millisecond)
//close send channel
close(b.Send) defer func() {
for send := range b.Send { b.Send = false
_, err = conn.Write(NewArtNetPackage(send)) conn.Close()
ticker.Stop()
}()
for range ticker.C {
if !b.Send {
continue
}
b.Send = false
b.mu.Lock()
data := NewDMXUniverse()
copy(data.Data, b.DMX.GetDMXData())
b.mu.Unlock()
_, err = conn.Write(NewArtNetPackage(data))
if err != nil { if err != nil {
log.Error("bus.Start", err) log.Error("bus.Start", err)
return return
} }
time.Sleep(23 * time.Millisecond)
} }
}() }()
return nil return nil
} }
@@ -166,8 +185,8 @@ func (b *Bus) Stop() {
if b.Watchdog != nil { if b.Watchdog != nil {
//cancels context //cancels context
b.Watchdog() b.Watchdog()
//close send channel
close(b.Send) b.Send = false
} }
} }
@@ -196,6 +215,12 @@ func (b *Bus) ParsePayload(c *gin.Context) error {
return nil return nil
} }
func (b *Bus) SetDMXData(channel uint, value uint8) error {
b.DMX.SetValue(channel, value)
b.Send = true
return nil
}
func isUDPReachable(ip string) (recieved bool, err error) { func isUDPReachable(ip string) (recieved bool, err error) {
p := fastping.NewPinger() p := fastping.NewPinger()
ra, err := net.ResolveIPAddr("ip4:icmp", ip) ra, err := net.ResolveIPAddr("ip4:icmp", ip)

View File

@@ -1,12 +1,29 @@
package models package models
type DMX []byte import (
"sync"
)
type DMX struct {
Data []byte
mu sync.Mutex
}
func NewDMXUniverse() *DMX { func NewDMXUniverse() *DMX {
dmx := make(DMX, 512) return &DMX{
return &dmx Data: make([]byte, 512),
}
}
func (d *DMX) GetDMXData() (data []byte) {
d.mu.Lock()
data = d.Data
d.mu.Unlock()
return
} }
func (d *DMX) SetValue(channel uint, value uint8) { func (d *DMX) SetValue(channel uint, value uint8) {
(*d)[channel] = value d.mu.Lock()
d.Data[channel] = value
d.mu.Unlock()
} }

View File

@@ -16,14 +16,14 @@ type Package []byte
func NewArtNetPackage(data *DMX) Package { func NewArtNetPackage(data *DMX) Package {
// Build ArtDMX packet // Build ArtDMX packet
packet := &bytes.Buffer{} packet := &bytes.Buffer{}
packet.WriteString(protocolID) // Art-Net ID packet.WriteString(protocolID) // Art-Net ID
binary.Write(packet, binary.LittleEndian, uint16(opCode)) // OpCode (OpDmx) binary.Write(packet, binary.LittleEndian, uint16(opCode)) // OpCode (OpDmx)
packet.WriteByte(0x00) // Protocol Version High packet.WriteByte(0x00) // Protocol Version High
packet.WriteByte(14) // Protocol Version Low (14 for Art-Net 4) packet.WriteByte(14) // Protocol Version Low (14 for Art-Net 4)
packet.WriteByte(0x00) // Sequence packet.WriteByte(0x00) // Sequence
packet.WriteByte(0x00) // Physical packet.WriteByte(0x00) // Physical
binary.Write(packet, binary.BigEndian, uint16(0)) // Universe (net:subuni, usually 0) binary.Write(packet, binary.BigEndian, uint16(0)) // Universe (net:subuni, usually 0)
binary.Write(packet, binary.BigEndian, uint16(len(*data))) // Length binary.Write(packet, binary.BigEndian, uint16(len(data.Data))) // Length
packet.Write(*data) packet.Write(data.Data)
return packet.Bytes() return packet.Bytes()
} }

View File

@@ -1,15 +1,15 @@
package models package models
import ( import (
json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models"
"github.com/google/uuid" "github.com/google/uuid"
json_dataModels "github.com/tecamino/tecamino-json_data/models"
) )
type Subscriptions map[uuid.UUID]Subscription type Subscriptions map[uuid.UUID][]Subscription
type Subscription struct { type Subscription struct {
Bus string Bus string
Address uint Address []uint
} }
func NewSubscriptions() Subscriptions { func NewSubscriptions() Subscriptions {
@@ -17,8 +17,11 @@ func NewSubscriptions() Subscriptions {
} }
func (s *Subscriptions) AddSubscription(uid uuid.UUID, drv *json_dataModels.Driver) { func (s *Subscriptions) AddSubscription(uid uuid.UUID, drv *json_dataModels.Driver) {
(*s)[uid] = Subscription{ subs := []Subscription{}
Bus: drv.Bus, for _, bus := range drv.Buses {
Address: drv.Address, sub := Subscription{Bus: bus.Name}
sub.Address = append(sub.Address, bus.Address...)
subs = append(subs, sub)
} }
(*s)[uid] = subs
} }

View File

@@ -6,19 +6,16 @@ import (
"log" "log"
"time" "time"
json_dataModels "gitea.tecamino.com/paadi/tecamino-json_data/models"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
json_dataModels "github.com/tecamino/tecamino-json_data/models"
) )
const ( const (
// Time allowed to write a message to the peer. // Time allowed to write a message to the peer.
writeWait = 10 * time.Second writeWait = 40 * time.Second
// Time allowed to read the next pong message from the peer. // Time allowed to read the next pong message from the peer.
pongWait = 10 * time.Second pongWait = 40 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
) )
type Client struct { type Client struct {
@@ -32,7 +29,6 @@ type Client struct {
OnError func(err error) OnError func(err error)
OnPing func() OnPing func()
OnPong func() OnPong func()
sendPong chan string
send chan []byte send chan []byte
unregister chan []byte unregister chan []byte
} }
@@ -41,13 +37,13 @@ type Client struct {
// ip: ip address of server // ip: ip address of server
func NewClient(ip, id string, port uint) (*Client, error) { func NewClient(ip, id string, port uint) (*Client, error) {
url := fmt.Sprintf("ws://%s:%d/ws?id=%s", ip, port, id) url := fmt.Sprintf("ws://%s:%d/ws?id=%s", ip, port, id)
c := &Client{ c := &Client{
ip: ip, ip: ip,
port: port, port: port,
Connected: true, Connected: true,
sendPong: make(chan string), send: make(chan []byte, 256),
send: make(chan []byte), unregister: make(chan []byte, 256),
unregister: make(chan []byte),
} }
dialer := websocket.DefaultDialer dialer := websocket.DefaultDialer
@@ -60,18 +56,21 @@ func NewClient(ip, id string, port uint) (*Client, error) {
} }
c.conn = conn c.conn = conn
// Setup control handlers //Setup control handlers
conn.SetPingHandler(func(appData string) error { conn.SetPingHandler(func(appData string) error {
if c.OnPing != nil { if c.OnPing != nil {
c.OnPing() c.OnPing()
} }
conn.SetWriteDeadline(time.Now().Add(writeWait)) conn.SetReadDeadline(time.Now().Add(pongWait))
conn.SetReadDeadline(time.Now().Add(writeWait)) conn.SetWriteDeadline(time.Now().Add(pongWait))
c.sendPong <- appData if err := conn.WriteControl(websocket.PongMessage, []byte(appData), time.Now().Add(2*pongWait)); err != nil {
c.OnError(err)
return err
}
return nil return nil
}) })
conn.SetPongHandler(func(string) error { conn.SetPongHandler(func(appData string) error {
conn.SetReadDeadline(time.Now().Add(pongWait)) conn.SetReadDeadline(time.Now().Add(pongWait))
if c.OnPong != nil { if c.OnPong != nil {
c.OnPong() c.OnPong()
@@ -79,17 +78,6 @@ func NewClient(ip, id string, port uint) (*Client, error) {
return nil return nil
}) })
conn.SetCloseHandler(func(code int, text string) error {
if c.OnClose != nil {
c.OnClose(code, text)
}
return nil
})
if c.OnOpen != nil {
c.OnOpen()
}
// Start reading messages from client // Start reading messages from client
go c.Read() go c.Read()
go c.Write() go c.Write()
@@ -101,13 +89,16 @@ func (c *Client) Read() {
c.OnOpen() c.OnOpen()
} }
c.conn.SetReadDeadline(time.Now().Add(writeWait)) c.conn.SetReadDeadline(time.Now().Add(pongWait))
for c.Connected { for c.Connected {
msgType, msg, err := c.conn.ReadMessage() msgType, msg, err := c.conn.ReadMessage()
c.conn.SetReadDeadline(time.Now().Add(pongWait))
if err != nil { if err != nil {
c.handleError(fmt.Errorf("read error (id:%s:%d): %w", c.ip, c.port, err)) c.handleError(fmt.Errorf("read error (ip:%s): %w", c.ip, err))
return return
} }
switch msgType { switch msgType {
case websocket.CloseMessage: case websocket.CloseMessage:
c.Close(websocket.CloseNormalClosure, "Client closed") c.Close(websocket.CloseNormalClosure, "Client closed")
@@ -116,32 +107,29 @@ func (c *Client) Read() {
if c.OnMessage != nil { if c.OnMessage != nil {
c.OnMessage(msg) c.OnMessage(msg)
} else { } else {
log.Printf("Received message but no handler set (id:%s:%d): %s", c.ip, c.port, string(msg)) log.Printf("Received message but no handler set (ip:%s): %s", c.ip, string(msg))
} }
default: default:
log.Printf("Unhandled message type %d (id:%s:%d)", msgType, c.ip, c.port) log.Printf("Unhandled message type %d (ip:%s)", msgType, c.ip)
} }
} }
} }
func (c *Client) Write() { func (c *Client) Write() {
ticker := time.NewTicker(pingPeriod) defer c.conn.Close()
defer func() {
ticker.Stop()
c.conn.Close()
}()
for {
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
for {
select { select {
case message, ok := <-c.send: case message, ok := <-c.send:
c.conn.SetWriteDeadline(time.Now().Add(writeWait)) c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if !ok { if !ok {
// The hub closed the channel. // The hub closed the channel.
if err := c.conn.WriteMessage(websocket.CloseMessage, []byte{}); err != nil { if err := c.conn.WriteMessage(websocket.CloseMessage, []byte("ping")); err != nil {
c.handleError(err) c.handleError(err)
return return
} }
c.handleError(fmt.Errorf("server %s:%d closed channel", c.ip, c.port)) c.handleError(fmt.Errorf("server %s closed channel", c.ip))
return return
} else { } else {
if err := c.conn.WriteMessage(websocket.TextMessage, message); err != nil { if err := c.conn.WriteMessage(websocket.TextMessage, message); err != nil {
@@ -149,26 +137,10 @@ func (c *Client) Write() {
return return
} }
} }
case <-ticker.C:
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
c.handleError(err)
return
}
if c.OnPing != nil {
c.OnPing()
}
case message, ok := <-c.sendPong:
if ok {
c.conn.WriteMessage(websocket.PongMessage, []byte(message))
}
case message := <-c.unregister: case message := <-c.unregister:
c.conn.WriteMessage(websocket.CloseMessage, message) c.conn.WriteMessage(websocket.CloseMessage, message)
c.Connected = false c.Connected = false
close(c.send) close(c.send)
close(c.sendPong)
close(c.unregister) close(c.unregister)
return return
} }
@@ -217,7 +189,7 @@ func (c *Client) handleError(err error) {
if c.OnError != nil { if c.OnError != nil {
c.OnError(err) c.OnError(err)
} else { } else {
fmt.Println("error: ", err) log.Println("error:", err)
} }
} }
} }