diff --git a/go.mod b/go.mod index c5cf2d0..b1a9fbe 100644 --- a/go.mod +++ b/go.mod @@ -3,26 +3,27 @@ module game-driver go 1.23.2 require ( + github.com/adrg/libvlc-go/v3 v3.1.6 github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1 github.com/eclipse/paho.golang v0.22.0 github.com/go-pkgz/cronrange v0.2.0 github.com/go-rod/rod v0.116.2 - github.com/gopxl/beep/v2 v2.1.0 - github.com/grid-x/modbus v0.0.0-20241004123532-f6c6fb5201b3 - github.com/spf13/cobra v1.8.1 + github.com/gopxl/beep/v2 v2.1.1 + github.com/grid-x/modbus v0.0.0-20250219144522-2b18d136199f + github.com/spf13/cobra v1.9.1 github.com/spf13/viper v1.19.0 + github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.11 github.com/warthog618/go-gpiocdev v0.9.1 go.uber.org/zap v1.27.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( - github.com/adrg/libvlc-go/v3 v3.1.6 // indirect - github.com/aliyun/alibaba-cloud-sdk-go v1.63.76 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.63.92 // indirect github.com/ebitengine/oto/v3 v3.3.2 // indirect - github.com/ebitengine/purego v0.8.1 // indirect + github.com/ebitengine/purego v0.8.2 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect github.com/hajimehoshi/go-mp3 v0.3.4 // indirect @@ -30,7 +31,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.2 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -39,27 +40,26 @@ require ( github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/sagikazarmark/locafero v0.6.0 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.11 // indirect github.com/ysmood/fetchup v0.2.4 // indirect github.com/ysmood/goob v0.4.0 // indirect github.com/ysmood/got v0.40.0 // indirect github.com/ysmood/gson v0.7.3 // indirect github.com/ysmood/leakless v0.9.0 // indirect - go.uber.org/atomic v1.9.0 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/exp v0.0.0-20250228200357-dead58393ab7 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 54b7e8d..210c440 100644 --- a/go.sum +++ b/go.sum @@ -7,9 +7,12 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3 github.com/aliyun/alibaba-cloud-sdk-go v1.61.1376/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ= github.com/aliyun/alibaba-cloud-sdk-go v1.63.76 h1:mg/+23+/gAw6zdxv9I5dPCj666WJPLk8S1nXm0dOumQ= github.com/aliyun/alibaba-cloud-sdk-go v1.63.76/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.92 h1:qespx4b6EexlXkvQUow9x0v1GnWUJYGU5FWYw3a4Wlg= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.92/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1 h1:LjItoNZuu5xHlsByFo+kr3nGa4LRIESCGWhfurayxBg= github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1/go.mod h1:4BDMUKpEaP/Ct79w0ozR0nbnEj49g1k3mrgX/IKG5I4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -19,6 +22,8 @@ github.com/ebitengine/oto/v3 v3.3.2 h1:VTWBsKX9eb+dXzaF4jEwQbs4yWIdXukJ0K40KgkpY github.com/ebitengine/oto/v3 v3.3.2/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U= github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= +github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/eclipse/paho.golang v0.22.0 h1:JhhUngr8TBlyUZDZw/L6WVayPi9qmSmdWeki48i5AVE= github.com/eclipse/paho.golang v0.22.0/go.mod h1:9ZiYJ93iEfGRJri8tErNeStPKLXIGBHiqbHV74t5pqI= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -37,6 +42,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -46,11 +53,15 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopxl/beep/v2 v2.1.0 h1:Jv95iHw3aNWoAa/J78YyXvOvMHH2ZGeAYD5ug8tVt8c= github.com/gopxl/beep/v2 v2.1.0/go.mod h1:sQvj2oSsu8fmmDWH3t0DzIe0OZzTW6/TJEHW4Ku+22o= +github.com/gopxl/beep/v2 v2.1.1 h1:6FYIYMm2qPAdWkjX+7xwKrViS1x0Po5kDMdRkq8NVbU= +github.com/gopxl/beep/v2 v2.1.1/go.mod h1:ZAm9TGQ9lvpoiFLd4zf5B1IuyxZhgRACMId1XJbaW0E= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grid-x/modbus v0.0.0-20241004123532-f6c6fb5201b3 h1:TfBJ561lUg0i0GLsxKeRaWoBGN8nyCLNt0OMGRx7R2M= github.com/grid-x/modbus v0.0.0-20241004123532-f6c6fb5201b3/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc= +github.com/grid-x/modbus v0.0.0-20250219144522-2b18d136199f h1:i5NSZj4IehIvyDSIa2CLbqSeglX8Ngre8Qck64Wr63Q= +github.com/grid-x/modbus v0.0.0-20250219144522-2b18d136199f/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc= github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa h1:Rsn6ARgNkXrsXJIzhkE4vQr5Gbx2LvtEMv4BJOK4LyU= github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa/go.mod h1:kdOd86/VGFWRrtkNwf1MPk0u1gIjc4Y7R2j7nhwc7Rk= github.com/hajimehoshi/go-mp3 v0.3.4 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68= @@ -73,6 +84,8 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -112,6 +125,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -122,12 +137,18 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -163,6 +184,8 @@ github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -178,6 +201,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250228200357-dead58393ab7 h1:aWwlzYV971S4BXRS9AmqwDLAD85ouC6X+pocatKY58c= +golang.org/x/exp v0.0.0-20250228200357-dead58393ab7/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -188,6 +213,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -195,9 +222,13 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -214,6 +245,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= diff --git a/internal/common/pause.go b/internal/common/pause.go index c157207..792710d 100644 --- a/internal/common/pause.go +++ b/internal/common/pause.go @@ -3,13 +3,10 @@ package common import "sync" type CtrlWait struct { - // 用于暂停的chan - P chan struct{} - // 用于恢复的chan - R chan struct{} + C chan int8 + // 状态 s bool - m sync.RWMutex } @@ -18,7 +15,7 @@ func (c *CtrlWait) Pause() { c.m.RLock() defer c.m.RUnlock() if c.s { - c.P <- struct{}{} + c.C <- 1 } } @@ -27,7 +24,7 @@ func (c *CtrlWait) Resume() { c.m.RLock() defer c.m.RUnlock() if c.s { - c.R <- struct{}{} + c.C <- 0 } } @@ -46,8 +43,7 @@ func (c *CtrlWait) Close() { // NewCtrlWait 创建一个控制等待 func NewCtrlWait() *CtrlWait { return &CtrlWait{ - P: make(chan struct{}), - R: make(chan struct{}), + C: make(chan int8), s: false, } } diff --git a/internal/common/pause_sub.go b/internal/common/pause_sub.go new file mode 100644 index 0000000..1b211a8 --- /dev/null +++ b/internal/common/pause_sub.go @@ -0,0 +1,53 @@ +package common + +import "sync" + +type PauseSub struct { + ctrl *CtrlWait + // 回调函数 + items []chan int8 + m sync.RWMutex +} + +// Add 添加一个暂停项 +func (p *PauseSub) Add(item chan int8) { + p.m.Lock() + defer p.m.Unlock() + p.items = append(p.items, item) +} + +// Remove 移除一个暂停项 +func (p *PauseSub) Remove(item chan int8) { + p.m.Lock() + defer p.m.Unlock() + for i, v := range p.items { + if v == item { + p.items = append(p.items[:i], p.items[i+1:]...) + } + } +} + +// Run 开始监听 +func (p *PauseSub) Run() { + p.ctrl.Open() + defer p.ctrl.Close() + + for { + select { + case <-p.ctrl.C: + go func() { + p.m.RLock() + defer p.m.RUnlock() + for _, item := range p.items { + item <- 1 + } + }() + } + } +} + +func NewPauseSub(c *CtrlWait) *PauseSub { + return &PauseSub{ + ctrl: c, + } +} diff --git a/internal/middleware/pause.go b/internal/middleware/pause.go deleted file mode 100644 index 0fd2c49..0000000 --- a/internal/middleware/pause.go +++ /dev/null @@ -1,69 +0,0 @@ -package middleware - -import ( - "context" - "game-driver/internal/common" - "game-driver/leaf" - "go.uber.org/zap" - "sync" -) - -func Pause(ctrl *common.CtrlWait) leaf.HandlerFunc { - return func(c *leaf.Context) { - var cancel context.CancelFunc - - // 保存原始的 Context - originalCtx := c.Context - - // 获取锚点 - holdPoint := c.Hold() - - // 等待组 - var wait sync.WaitGroup - defer wait.Wait() - - run := true - - wait.Add(1) - go func() { - defer wait.Done() - zap.S().Infoln("待机控制器") - - ctrl.Open() - defer ctrl.Close() - - for { - select { - case <-originalCtx.Done(): - cancel() - zap.S().Infoln("待机控制器监听结束") - return - case <-ctrl.R: - { - zap.S().Infoln("待机控制器 Resume 触发") - c.Context = originalCtx - run = true - } - case <-ctrl.P: - { - zap.S().Infoln("待机控制器 Pause 触发") - run = false - cancel() - } - } - } - }() - - for { - select { - case <-originalCtx.Done(): - return - default: - if run { - cancel = leaf.WithCancel(c) - c.Resume(holdPoint) - } - } - } - } -} diff --git a/internal/routes/standby/audio.go b/internal/routes/standby/audio.go new file mode 100644 index 0000000..44c6178 --- /dev/null +++ b/internal/routes/standby/audio.go @@ -0,0 +1,40 @@ +package standby + +import ( + "context" + "fmt" + "game-driver/internal/schema" + "game-driver/pkg/audio" + "game-driver/pkg/utils" + "github.com/gopxl/beep/v2/speaker" + "go.uber.org/zap" +) + +func Audio(item schema.WaitItemModel) func(c context.Context) error { + return func(c context.Context) error { + data, err := utils.LinkAudio(item.Data) + if err != nil { + return fmt.Errorf("音频数据获取异常: %w", err) + } + if data == nil { + return fmt.Errorf("音频数据获取为空") + } + + zap.S().Infoln("播放待机音乐") + defer zap.S().Infoln("结束待机音乐") + + ctrl, closer, e := audio.PlayBgmMP3(data) + defer closer() + if e != nil { + return fmt.Errorf("播放待机音乐异常: %w", e) + } + + <-c.Done() + + speaker.Lock() + ctrl.Streamer = nil + speaker.Unlock() + + return nil + } +} diff --git a/internal/routes/standby/pjlink.go b/internal/routes/standby/pjlink.go new file mode 100644 index 0000000..bfed900 --- /dev/null +++ b/internal/routes/standby/pjlink.go @@ -0,0 +1,35 @@ +package standby + +import ( + "context" + "fmt" + "game-driver/config/wait" + "game-driver/internal/schema" + "game-driver/pkg/pjlink" + "go.uber.org/zap" +) + +func PJLink(_ schema.WaitItemModel) func(c context.Context) error { + return func(c context.Context) error { + cfg := (wait.C).(wait.PJLink) + pjc := pjlink.NewClient(cfg.Ip, cfg.Port, cfg.Password, cfg.Id) + + zap.S().Infoln("打开待机投影仪") + resp, err := pjc.PowerOn() + if err != nil { + return fmt.Errorf("打开投影仪异常: %w", err) + } + zap.S().Infoln("投影仪返回报文:", resp) + + <-c.Done() + + zap.S().Infoln("关闭待机投影仪") + resp, err = pjc.PowerOff() + if err != nil { + return fmt.Errorf("关闭投影仪异常: %w", err) + } + zap.S().Infoln("投影仪返回报文:", resp) + + return nil + } +} diff --git a/internal/routes/standby/relay.go b/internal/routes/standby/relay.go new file mode 100644 index 0000000..a910d6f --- /dev/null +++ b/internal/routes/standby/relay.go @@ -0,0 +1,28 @@ +package standby + +import ( + "context" + "fmt" + "game-driver/internal/schema" + "game-driver/pkg/relay" + "go.uber.org/zap" +) + +func Relay(item schema.WaitItemModel) func(c context.Context) error { + return func(c context.Context) error { + r, err := relay.New(item.Data) + if err != nil { + return fmt.Errorf("继电器初始化异常: %w", err) + } + defer r.Close() + + zap.S().Infoln("待机继电器供电") + defer zap.S().Infoln("待机继电器断电") + + _ = r.On(0) + <-c.Done() + _ = r.Off(0) + + return nil + } +} diff --git a/internal/routes/standby/tts.go b/internal/routes/standby/tts.go new file mode 100644 index 0000000..3539d90 --- /dev/null +++ b/internal/routes/standby/tts.go @@ -0,0 +1,32 @@ +package standby + +import ( + "context" + "fmt" + "game-driver/internal/schema" + "game-driver/pkg/audio" + "game-driver/pkg/tts" + "go.uber.org/zap" + "time" +) + +func TTS(item schema.WaitItemModel) func(c context.Context) error { + return func(c context.Context) error { + reader, err := tts.DefaultTTS.Get(item.Data) + if err != nil { + return fmt.Errorf("语音合成异常: %w", err) + } + + zap.S().Infoln("播放待机 TTS 语音") + defer zap.S().Infoln("结束待机 TTS 语音") + + for { + audio.PlayWav(c, reader) + select { + case <-c.Done(): + return nil + case <-time.After(time.Duration(item.Interval) * time.Second): + } + } + } +} diff --git a/internal/routes/standby/video.go b/internal/routes/standby/video.go new file mode 100644 index 0000000..6cf1846 --- /dev/null +++ b/internal/routes/standby/video.go @@ -0,0 +1,38 @@ +package standby + +import ( + "context" + "fmt" + "game-driver/internal/schema" + "game-driver/pkg/utils" + "game-driver/pkg/video" + "go.uber.org/zap" + "time" +) + +func Video(item schema.WaitItemModel) func(c context.Context) error { + return func(c context.Context) error { + local, err := utils.LinkVideo(item.Data) + if err != nil { + return fmt.Errorf("视频文件获取异常: %w", err) + } + + zap.S().Infoln("播放待机视频") + defer zap.S().Infoln("结束待机视频") + + utils.BlankOpen() + defer utils.BlankClose() + + for { + err := video.Play(c, local) + if err != nil { + return fmt.Errorf("视频播放异常: %w", err) + } + select { + case <-c.Done(): + return nil + case <-time.After(time.Duration(item.Interval) * time.Second): + } + } + } +} diff --git a/internal/routes/standby/web.go b/internal/routes/standby/web.go new file mode 100644 index 0000000..4bb488f --- /dev/null +++ b/internal/routes/standby/web.go @@ -0,0 +1,22 @@ +package standby + +import ( + "context" + "game-driver/internal/schema" + "game-driver/pkg/browser" + "game-driver/pkg/utils" + "go.uber.org/zap" +) + +func Web(item schema.WaitItemModel) func(c context.Context) error { + return func(c context.Context) error { + zap.S().Infoln("打开待机网页") + + // 控制背光 + utils.BlankOpen() + defer utils.BlankClose() + + browser.OpenApp(c, item.Data) + return nil + } +} diff --git a/internal/routes/standby_ctrl/pause.go b/internal/routes/standby_ctrl/pause.go new file mode 100644 index 0000000..82ba5da --- /dev/null +++ b/internal/routes/standby_ctrl/pause.go @@ -0,0 +1,66 @@ +package standby_ctrl + +import ( + "context" + "game-driver/internal/common" + "go.uber.org/zap" + "sync" +) + +func Pause(ps *common.PauseSub, isPause bool, play func(c context.Context) error) func(c context.Context) error { + return func(c context.Context) error { + var cancel context.CancelFunc + run := true + + if isPause { + p := make(chan int8) + defer close(p) + + ps.Add(p) + defer ps.Remove(p) + + zap.S().Infoln("待机控制器") + defer zap.S().Infoln("待机控制器结束") + + // 等待组 + var wait sync.WaitGroup + defer wait.Wait() + + wait.Add(1) + go func() { + defer wait.Done() + for { + select { + case <-c.Done(): + return + case v := <-p: + if v == 1 { + zap.S().Infoln("待机控制器 Pause 触发") + run = false + cancel() + } else { + zap.S().Infoln("待机控制器 Resume 触发") + run = true + } + } + } + }() + } + + for { + select { + case <-c.Done(): + return nil + default: + if run { + nc, cc := context.WithCancel(c) + cancel = cc + err := play(nc) + if err != nil { + zap.S().Infoln("执行后续操作异常: ", err) + } + } + } + } + } +} diff --git a/internal/routes/standby_ctrl/time.go b/internal/routes/standby_ctrl/time.go new file mode 100644 index 0000000..3bd2e0e --- /dev/null +++ b/internal/routes/standby_ctrl/time.go @@ -0,0 +1,91 @@ +package standby_ctrl + +import ( + "context" + "github.com/go-pkgz/cronrange" + "go.uber.org/zap" + "sync" + "time" +) + +// Time 时间控制器 +func Time(rootRules []cronrange.Rule, cron string, play func(c context.Context) error) func(c context.Context) error { + // 设定默认时间规则 + if cron == "" { + cron = "* * * *" + } + + rules, err := cronrange.Parse(cron) + if err != nil { + zap.S().Errorln("解析时间规则异常: ", err) + return nil + } + + return func(c context.Context) error { + a := make(chan bool) + defer close(a) + + // 等待组 + var waitGroup sync.WaitGroup + defer waitGroup.Wait() + + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + waitGroup.Add(1) + go func() { + defer waitGroup.Done() + for { + select { + case <-c.Done(): + return + case <-ticker.C: + if cronrange.Match(rules, time.Now()) && cronrange.Match(rootRules, time.Now()) { + a <- true + } else { + a <- false + } + } + } + }() + + var cancel context.CancelFunc + var m sync.Mutex + for { + select { + case <-c.Done(): + if cancel != nil { + cancel() + cancel = nil + } + return nil + case r := <-a: + if r { + if ok := m.TryLock(); ok { + ctx, cc := context.WithCancel(context.TODO()) + cancel = cc + waitGroup.Add(1) + go func() { + defer waitGroup.Done() + defer m.Unlock() + defer func() { cancel = nil }() + + err := play(ctx) + if err != nil { + zap.S().Errorln("执行动作异常: ", err) + select { + case <-ctx.Done(): + return + case <-time.After(time.Minute): + } + } + }() + } + } else if cancel != nil { + cancel() + cancel = nil + } + } + } + } +} diff --git a/internal/routes/wait.go b/internal/routes/wait.go index 5bf5903..c5476bf 100644 --- a/internal/routes/wait.go +++ b/internal/routes/wait.go @@ -2,291 +2,85 @@ package routes import ( "context" - "fmt" - "game-driver/config/wait" + "game-driver/internal/common" "game-driver/internal/middleware" + "game-driver/internal/routes/standby" + "game-driver/internal/routes/standby_ctrl" "game-driver/internal/schema" "game-driver/leaf" - "game-driver/pkg/audio" - "game-driver/pkg/browser" - "game-driver/pkg/pjlink" - "game-driver/pkg/relay" - "game-driver/pkg/tts" - "game-driver/pkg/utils" - "game-driver/pkg/video" "github.com/go-pkgz/cronrange" - "github.com/gopxl/beep/v2/speaker" "go.uber.org/zap" "sync" - "time" ) -func runAction(c *leaf.Context, item schema.WaitItemModel, rootRules []cronrange.Rule, play func(c context.Context, item schema.WaitItemModel) error) { - // 设定默认时间规则 - if item.Cron == "" { - item.Cron = "* * * *" - } +func WaitAction(ctrl *common.CtrlWait) leaf.HandlerFunc { + ps := common.NewPauseSub(ctrl) - rules, err := cronrange.Parse(item.Cron) - if err != nil { - zap.S().Errorln("解析时间规则异常: ", err) - return - } + return func(c *leaf.Context) { + payload := leaf.Value[*schema.WaitModel](c, middleware.PayloadJSONKey) - a := make(chan bool) - defer close(a) - - // 等待组 - var wait sync.WaitGroup - defer wait.Wait() - - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - wait.Add(1) - go func() { - defer wait.Done() - for { - select { - case <-c.Done(): - return - case <-ticker.C: - if cronrange.Match(rules, time.Now()) && cronrange.Match(rootRules, time.Now()) { - a <- true - } else { - a <- false - } - } + // 设定默认时间规则,ctrl + if payload.Cron == "" { + payload.Cron = "* * * *" } - }() - var cancel context.CancelFunc - var m sync.Mutex - for { - select { - case <-c.Done(): - if cancel != nil { - cancel() - } - return - case r := <-a: - if r { - if ok := m.TryLock(); ok { - ctx, cc := context.WithCancel(context.TODO()) - cancel = cc - wait.Add(1) - go func() { - defer wait.Done() - defer m.Unlock() - defer func() { cancel = nil }() - - err := play(ctx, item) - if err != nil { - zap.S().Errorln("执行动作异常: ", err) - select { - case <-ctx.Done(): - return - case <-time.After(time.Minute): - } - } - }() - } - } else if cancel != nil { - cancel() - cancel = nil - } - } - } -} - -func WaitAction(c *leaf.Context) { - payload := leaf.Value[*schema.WaitModel](c, middleware.PayloadJSONKey) - - // 设定默认时间规则 - if payload.Cron == "" { - payload.Cron = "* * * *" - } - - rules, err := cronrange.Parse(payload.Cron) - if err != nil { - zap.S().Errorln("解析时间规则异常: ", err) - return - } - - // 等待组 - var wait sync.WaitGroup - defer wait.Wait() - for _, item := range payload.Items { - switch item.Type { - case schema.WaitAudio: - // 执行音乐播放 - wait.Add(1) - go func() { - defer wait.Done() - runAction(c, item, rules, audioAction) - }() - case schema.WaitTTS: - // 执行TTS播放 - wait.Add(1) - go func() { - defer wait.Done() - runAction(c, item, rules, ttsAction) - }() - case schema.WaitRelay: - // 执行继电器供电 - wait.Add(1) - go func() { - defer wait.Done() - runAction(c, item, rules, relayAction) - }() - case schema.WaitVideo: - // 执行视频播放 - wait.Add(1) - go func() { - defer wait.Done() - runAction(c, item, rules, videoAction) - }() - case schema.WaitWeb: - // 执行网页打开 - wait.Add(1) - go func() { - defer wait.Done() - runAction(c, item, rules, webAction) - }() - case schema.WaitPJLink: - // 执行投影仪打开 - wait.Add(1) - go func() { - defer wait.Done() - runAction(c, item, rules, pjlinkAction) - }() - default: - zap.S().Infof("不支持的类型: %d\n", item.Type) - } - } -} - -func audioAction(c context.Context, item schema.WaitItemModel) error { - data, err := utils.LinkAudio(item.Data) - if err != nil { - return fmt.Errorf("音频数据获取异常: %w", err) - } - if data == nil { - return fmt.Errorf("音频数据获取为空") - } - - zap.S().Infoln("播放待机音乐") - defer zap.S().Infoln("结束待机音乐") - - ctrl, closer, e := audio.PlayBgmMP3(data) - defer closer() - if e != nil { - return fmt.Errorf("播放待机音乐异常: %w", e) - } - - <-c.Done() - - speaker.Lock() - ctrl.Streamer = nil - speaker.Unlock() - - return nil -} - -func ttsAction(c context.Context, item schema.WaitItemModel) error { - reader, err := tts.DefaultTTS.Get(item.Data) - if err != nil { - return fmt.Errorf("语音合成异常: %w", err) - } - - zap.S().Infoln("播放待机 TTS 语音") - defer zap.S().Infoln("结束待机 TTS 语音") - - for { - audio.PlayWav(c, reader) - select { - case <-c.Done(): - return nil - case <-time.After(time.Duration(item.Interval) * time.Second): - } - } -} - -func relayAction(c context.Context, item schema.WaitItemModel) error { - r, err := relay.New(item.Data) - if err != nil { - return fmt.Errorf("继电器初始化异常: %w", err) - } - defer r.Close() - - zap.S().Infoln("待机继电器供电") - defer zap.S().Infoln("待机继电器断电") - - _ = r.On(0) - <-c.Done() - _ = r.Off(0) - - return nil -} - -func videoAction(c context.Context, item schema.WaitItemModel) error { - local, err := utils.LinkVideo(item.Data) - if err != nil { - return fmt.Errorf("视频文件获取异常: %w", err) - } - - zap.S().Infoln("播放待机视频") - defer zap.S().Infoln("结束待机视频") - - utils.BlankOpen() - defer utils.BlankClose() - - for { - err := video.Play(c, local) + rules, err := cronrange.Parse(payload.Cron) if err != nil { - return fmt.Errorf("视频播放异常: %w", err) + zap.S().Errorln("解析时间规则异常: ", err) + return } - select { - case <-c.Done(): - return nil - case <-time.After(time.Duration(item.Interval) * time.Second): + + // 等待组 + var waitGroup sync.WaitGroup + defer waitGroup.Wait() + + // 开启暂停监听 + waitGroup.Add(1) + go func() { + defer waitGroup.Done() + ps.Run() + }() + + // 处理每个待机控制 + handleItem := func(title string, item schema.WaitItemModel, f func(c context.Context) error) { + waitGroup.Add(1) + go func() { + defer waitGroup.Done() + if f == nil { + return + } + f = standby_ctrl.Time(rules, item.Cron, f) + if f == nil { + return + } + f = standby_ctrl.Pause(ps, item.Pause, f) + if f == nil { + return + } + e := f(c) + if e != nil { + zap.S().Errorf("%s异常: %s\n", title, e) + } + }() + } + + for _, item := range payload.Items { + switch item.Type { + case schema.WaitAudio: + handleItem("音乐待机控制", item, standby.Audio(item)) + case schema.WaitTTS: + handleItem("TTS待机控制", item, standby.TTS(item)) + case schema.WaitRelay: + handleItem("继电器待机控制", item, standby.Relay(item)) + case schema.WaitVideo: + handleItem("视频待机控制", item, standby.Video(item)) + case schema.WaitWeb: + handleItem("视频待机控制", item, standby.Web(item)) + case schema.WaitPJLink: + handleItem("视频待机控制", item, standby.PJLink(item)) + default: + zap.S().Infof("不支持的类型: %d\n", item.Type) + } } } } - -func webAction(c context.Context, item schema.WaitItemModel) error { - zap.S().Infoln("打开待机网页") - - // 控制背光 - utils.BlankOpen() - defer utils.BlankClose() - - browser.OpenApp(c, item.Data) - return nil -} - -func pjlinkAction(c context.Context, _ schema.WaitItemModel) error { - cfg := (wait.C).(wait.PJLink) - pjc := pjlink.NewClient(cfg.Ip, cfg.Port, cfg.Password, cfg.Id) - err := pjc.Connect() - if err != nil { - return fmt.Errorf("连接 PJLink 设备异常: %w", err) - } - defer pjc.Close() - - zap.S().Infoln("打开待机投影仪") - err = pjc.PowerOn() - if err != nil { - return fmt.Errorf("打开投影仪异常: %w", err) - } - - <-c.Done() - - zap.S().Infoln("关闭待机投影仪") - err = pjc.PowerOff() - if err != nil { - return fmt.Errorf("关闭投影仪异常: %w", err) - } - - return nil -} diff --git a/internal/schema/wait.go b/internal/schema/wait.go index a263603..d1b8692 100644 --- a/internal/schema/wait.go +++ b/internal/schema/wait.go @@ -16,6 +16,7 @@ type WaitItemModel struct { Type WaitType `json:"type"` Data string `json:"data"` Interval int64 `json:"interval"` + Pause bool `json:"pause"` } type WaitModel struct { diff --git a/internal/server.go b/internal/server.go index 7229b96..79e7434 100644 --- a/internal/server.go +++ b/internal/server.go @@ -154,8 +154,7 @@ func Run() { middleware.PayloadJSON[schema.WaitModel](), middleware.Unique(common.GlobalBgStopper), middleware.EmergencyStop(common.GlobalBgStopper), - middleware.Pause(common.PassCtrl), - routes.WaitAction, + routes.WaitAction(common.PassCtrl), ) // 处理指令 router.RegisterHandler(topicPrefix+"command", diff --git a/pkg/pjlink/pjlink.go b/pkg/pjlink/pjlink.go index 60000ae..bb926fc 100644 --- a/pkg/pjlink/pjlink.go +++ b/pkg/pjlink/pjlink.go @@ -32,11 +32,11 @@ func NewClient(host, port, password, id string) *Client { } } -func (c *Client) Connect() error { +func (c *Client) connect() error { address := net.JoinHostPort(c.Host, c.Port) conn, err := net.DialTimeout("tcp", address, 5*time.Second) if err != nil { - return err + return fmt.Errorf("连接异常: %w", err) } c.conn = conn @@ -44,14 +44,14 @@ func (c *Client) Connect() error { reader := bufio.NewReader(c.conn) response, err := reader.ReadString('\r') if err != nil { - c.Close() - return err + c.close() + return fmt.Errorf("读取异常: %w", err) } // Handle authentication if strings.HasPrefix(response, "PJLINK 1") { if c.Password == "" { - c.Close() + c.close() return ErrAuthFailed } @@ -62,13 +62,13 @@ func (c *Client) Connect() error { _, err = fmt.Fprintf(c.conn, "%s\r", authHash) if err != nil { - c.Close() - return err + c.close() + return fmt.Errorf("写入异常: %w", err) } authResponse, err := reader.ReadString('\r') if err != nil || !strings.Contains(authResponse, "OK") { - c.Close() + c.close() return ErrAuthFailed } } @@ -104,36 +104,54 @@ func (c *Client) sendCommand(command string) (string, error) { return "", ErrAuthFailed } else if result == "ERR2" { return "", ErrCommandError + } else if result == "ERR3" { + return "YES", nil } return result, nil } -func (c *Client) PowerOn() error { +func (c *Client) PowerOn() (string, error) { + err := c.connect() + if err != nil { + return "", fmt.Errorf("连接异常: %w", err) + } + defer c.close() + response, err := c.sendCommand("POWR 1") if err != nil { - return err + return "", err } - if response != "OK" { - return fmt.Errorf("unexpected response: %s", response) + if response == "YES" { + return response, nil + } else if response != "OK" { + return response, fmt.Errorf("unexpected response: %s", response) } - return nil + return response, nil } -func (c *Client) PowerOff() error { +func (c *Client) PowerOff() (string, error) { + err := c.connect() + if err != nil { + return "", fmt.Errorf("连接异常: %w", err) + } + defer c.close() + response, err := c.sendCommand("POWR 0") if err != nil { - return err + return "", err } - if response != "OK" { - return fmt.Errorf("unexpected response: %s", response) + if response == "YES" { + return response, nil + } else if response != "OK" { + return response, fmt.Errorf("unexpected response: %s", response) } - return nil + return response, nil } -func (c *Client) Close() { +func (c *Client) close() { if c.conn != nil { c.conn.Close() c.conn = nil diff --git a/todo.md b/todo.md index 1007d1f..9b1c954 100644 --- a/todo.md +++ b/todo.md @@ -1,22 +1,34 @@ # 技术点记录 + +### ubuntu 24 开机慢优化 + +```bash +# 在 systemd-networkd-wait-online.service Service 加入 TImeoutStartSec=2sec +sudo vim /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service +``` + ## linux 下播放音频 + ```bash sudo apt install libasound2-dev alsa-utils ``` + ## linux 下播放视频 + ```bash -sudo apt install ffmpeg +sudo apt install libvlc-dev vlc ``` -显示安装 +## 显示安装 ```bash sudo apt install xorg ``` ### 当前用户加入播放音频与视频的组中 + ```bash -sudo usermod -aG audio,video $USER +sudo usermod -aG audio,video,dialout $USER ``` ### 关闭背光 @@ -28,12 +40,8 @@ xset dpms force off xset dpms force on ``` -### 播放视频 -```bash -ffplay -autoexit -fs -i video.mp4 -``` - ### 注册为 service ,并开机启动 + ```bash sudo cp /script/game-driver.service /etc/systemd/system/ sudo systemctl enable game-driver @@ -41,11 +49,13 @@ sudo systemctl start game-driver ``` ## 编译 arm64 架构 + ```bash CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o game-driver-arm64 . ``` ## J8引脚 + ```bash J8: 3V3 (1) (2) 5V @@ -73,6 +83,7 @@ GPIO26 (37) (38) GPIO20 ## 极简桌面环境并自动登录 ### 安装 xorg i3 + ```bash sudo apt install xorg i3-wm ``` @@ -80,6 +91,7 @@ sudo apt install xorg i3-wm ### 自动启动 Xorg 和窗口管理器 编辑 `.bashrc`文件,在文件的末尾添加以下行: + ```bash if [ -z "$DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then startx @@ -90,16 +102,20 @@ fi ### 自动登录 -编辑 `/etc/systemd/system/getty.target.wants/getty@tty1.service` 文件,将 `ExecStart` 行修改为: +编辑 `/etc/systemd/system/getty.target.wants/getty@tty1.service` 文件,将 `ExecStart` 行修改为: + ```bash ExecStart=-/sbin/agetty --autologin --noclear %I $TERM ``` + 其中: - - :替换为你想自动登录的用户名。 + +- :替换为你想自动登录的用户名。 ### 禁用 i3bar 状态栏 编辑 `~/.config/i3/config`,将如下行注释掉: + ```bash # bar { # status_command i3status @@ -111,11 +127,13 @@ ExecStart=-/sbin/agetty --autologin --noclear %I $TERM ### 配置 i3 安装 `unclutter`: + ```bash sudo apt install unclutter ``` 编辑 `~/.config/i3/config`,添加如下行: + ```bash exec --no-startup-id unclutter -root # 隐藏鼠标 exec --no-startup-id xset dpms 0 0 0 # 关闭屏幕自动关闭 @@ -136,13 +154,17 @@ sudo apt install fonts-noto-cjk fonts-noto-color-emoji ```bash sudo add-apt-repository ppa:xtradeb/apps -sudo apt update sudo apt install ungoogled-chromium ``` ### 设置默认启动页面 编辑 `~/.config/i3/config`,添加如下行: + ```bash exec --no-startup-id ungoogled-chromium --kiosk --disable-extensions --disable-translate --app= ``` + +### 设置系统默认音量 + +`alsamixer` `sudo alsactl store`