commit
cefe5ee26c
@ -0,0 +1 @@
|
|||||||
|
/.idea/
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
module tgk-touch
|
||||||
|
|
||||||
|
go 1.26.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.16
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v5 v5.5.1
|
||||||
|
github.com/alibabacloud-go/tea v1.4.0
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.9
|
||||||
|
github.com/gogf/gf/v2 v2.10.0
|
||||||
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
|
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1
|
||||||
|
github.com/towgo/towgo v1.1.5
|
||||||
|
go.bug.st/serial v1.6.4
|
||||||
|
go.uber.org/zap v1.27.1
|
||||||
|
gorm.io/gorm v1.30.0
|
||||||
|
xorm.io/xorm v1.3.9
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||||
|
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||||
|
github.com/aliyun/credentials-go v1.4.5 // indirect
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
|
github.com/creack/goselect v0.1.2 // indirect
|
||||||
|
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||||
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.28 // indirect
|
||||||
|
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/olekukonko/errors v1.1.0 // indirect
|
||||||
|
github.com/olekukonko/ll v0.0.9 // indirect
|
||||||
|
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
|
golang.org/x/crypto v0.38.0 // indirect
|
||||||
|
golang.org/x/net v0.40.0 // indirect
|
||||||
|
golang.org/x/sync v0.14.0 // indirect
|
||||||
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
|
golang.org/x/text v0.25.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gorm.io/driver/mysql v1.5.7 // indirect
|
||||||
|
gorm.io/driver/postgres v1.6.0 // indirect
|
||||||
|
gorm.io/driver/sqlite v1.5.7 // indirect
|
||||||
|
gorm.io/driver/sqlserver v1.6.0 // indirect
|
||||||
|
xorm.io/builder v0.3.13 // indirect
|
||||||
|
)
|
||||||
@ -0,0 +1,499 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||||
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.2/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
||||||
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
||||||
|
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
||||||
|
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
||||||
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
||||||
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
||||||
|
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
||||||
|
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.14/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.16 h1:LHhjxZkNWAKWepxcWyzgFgo0X6TUVhL7sC7ANc60p8A=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.16/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
|
||||||
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||||
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||||
|
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||||
|
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||||
|
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||||
|
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
|
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
||||||
|
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v5 v5.5.1 h1:CyJ1adk5jlg7acrbG1sgdZ+EXTZNZHwhNQAf6VFfySo=
|
||||||
|
github.com/alibabacloud-go/dysmsapi-20170525/v5 v5.5.1/go.mod h1:J1zab9/VxVJGdZ5pSK/BbUot7CkaSkRXdaLKAXXRLoY=
|
||||||
|
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
||||||
|
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
|
||||||
|
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
|
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
|
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||||
|
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
|
github.com/alibabacloud-go/tea v1.4.0 h1:MSKhu/kWLPX7mplWMngki8nNt+CyUZ+kfkzaR5VpMhA=
|
||||||
|
github.com/alibabacloud-go/tea v1.4.0/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
|
||||||
|
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.9 h1:y6pUIlhjxbZl9ObDAcmA1H3c21eaAxADHTDQmBnAIgA=
|
||||||
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.9/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||||
|
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||||
|
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||||
|
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
||||||
|
github.com/aliyun/credentials-go v1.4.5 h1:O76WYKgdy1oQYYiJkERjlA2dxGuvLRrzuO2ScrtGWSk=
|
||||||
|
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||||
|
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||||
|
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||||
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
|
||||||
|
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||||
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=
|
||||||
|
github.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||||
|
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
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/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
|
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/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
||||||
|
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
|
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||||
|
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||||
|
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/microsoft/go-mssqldb v0.19.0/go.mod h1:ukJCBnnzLzpVF0qYRT+eg1e+eSwjeQ7IvenUv8QPook=
|
||||||
|
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
||||||
|
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
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/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
|
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||||
|
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||||
|
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||||
|
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||||
|
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
||||||
|
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
|
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
|
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 h1:NVK+OqnavpyFmUiKfUMHrpvbCi2VFoWTrcpI7aDaJ2I=
|
||||||
|
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
|
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||||
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
|
github.com/towgo/towgo v1.1.5 h1:WkQapUEMIvipfDVP3uQXRPddi0pEdNmVfumXszWRRt4=
|
||||||
|
github.com/towgo/towgo v1.1.5/go.mod h1:nW4bjLhlr0fapP5Cv7QsqnkiuaOsXt1sM7EwkuPX+w0=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
|
||||||
|
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
|
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||||
|
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||||
|
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||||
|
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||||
|
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||||
|
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||||
|
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.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
|
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||||
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||||
|
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||||
|
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
|
||||||
|
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||||
|
gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
|
||||||
|
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||||
|
gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc=
|
||||||
|
gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
|
||||||
|
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||||
|
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||||
|
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
|
||||||
|
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
||||||
|
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
||||||
|
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
||||||
|
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
|
||||||
|
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
|
||||||
|
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||||
|
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||||
|
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/sqlite v1.20.4 h1:J8+m2trkN+KKoE7jglyHYYYiaq5xmz2HoHJIiBlRzbE=
|
||||||
|
modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
|
||||||
|
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||||
|
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||||
|
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
||||||
|
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
|
||||||
|
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||||
|
xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
|
||||||
|
xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"os"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ZapCore struct {
|
||||||
|
level zapcore.Level
|
||||||
|
zapcore.Core
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewZapCore(level zapcore.Level) *ZapCore {
|
||||||
|
entity := &ZapCore{level: level}
|
||||||
|
syncer := entity.WriteSyncer()
|
||||||
|
levelEnabler := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
|
||||||
|
return l == level
|
||||||
|
})
|
||||||
|
entity.Core = zapcore.NewCore(g.GVA_Config.Zap.Encoder(), syncer, levelEnabler)
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZapCore) WriteSyncer(formats ...string) zapcore.WriteSyncer {
|
||||||
|
|
||||||
|
cutter := NewCutter(
|
||||||
|
g.GVA_Config.Zap.Director,
|
||||||
|
z.level.String(),
|
||||||
|
g.GVA_Config.Zap.RetentionDay,
|
||||||
|
CutterWithLayout(time.DateOnly),
|
||||||
|
CutterWithFormats(formats...),
|
||||||
|
CutterWithMaxSize(g.GVA_Config.Zap.MaxSize), // 传入最大大小(MB)
|
||||||
|
CutterWithCompress(g.GVA_Config.Zap.Compress), // 传入是否压缩
|
||||||
|
CutterWithCompressLevel(g.GVA_Config.Zap.CompressLevel),
|
||||||
|
CutterWithCheckInterval(g.GVA_Config.Zap.CheckInterval),
|
||||||
|
)
|
||||||
|
if g.GVA_Config.Zap.LogInConsole {
|
||||||
|
multiSyncer := zapcore.NewMultiWriteSyncer(os.Stdout, cutter)
|
||||||
|
return zapcore.AddSync(multiSyncer)
|
||||||
|
}
|
||||||
|
return zapcore.AddSync(cutter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZapCore) Enabled(level zapcore.Level) bool {
|
||||||
|
return z.level == level
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZapCore) With(fields []zapcore.Field) zapcore.Core {
|
||||||
|
return z.Core.With(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZapCore) Check(entry zapcore.Entry, check *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||||
|
if z.Enabled(entry.Level) {
|
||||||
|
return check.AddCore(entry, z)
|
||||||
|
}
|
||||||
|
return check
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
if fields[i].Key == "business" || fields[i].Key == "folder" || fields[i].Key == "directory" {
|
||||||
|
syncer := z.WriteSyncer(fields[i].String)
|
||||||
|
z.Core = zapcore.NewCore(g.GVA_Config.Zap.Encoder(), syncer, z.level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return z.Core.Write(entry, fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *ZapCore) Sync() error {
|
||||||
|
return z.Core.Sync()
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"tgk-touch/internal/core/internal"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
"tgk-touch/utility"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Zap 获取 zap.Logger
|
||||||
|
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||||
|
func Zap() (logger *zap.Logger) {
|
||||||
|
z := g.GVA_Config.Zap
|
||||||
|
if ok, _ := utility.PathExists(z.Director); !ok { // 判断是否有Director文件夹
|
||||||
|
fmt.Printf("create %v directory\n", z.Director)
|
||||||
|
_ = os.Mkdir(z.Director, os.ModePerm)
|
||||||
|
}
|
||||||
|
levels := z.Levels()
|
||||||
|
length := len(levels)
|
||||||
|
cores := make([]zapcore.Core, 0, length)
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
core := internal.NewZapCore(levels[i])
|
||||||
|
|
||||||
|
cores = append(cores, core)
|
||||||
|
}
|
||||||
|
logger = zap.New(
|
||||||
|
zapcore.NewTee(cores...),
|
||||||
|
zap.AddStacktrace(zapcore.ErrorLevel))
|
||||||
|
|
||||||
|
if z.ShowLine {
|
||||||
|
logger = logger.WithOptions(zap.AddCaller())
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package g
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/os/gcfg"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"net/http"
|
||||||
|
"tgk-touch/internal/model/config"
|
||||||
|
"tgk-touch/utility/timer"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
GVA_Timer timer.Timer = timer.NewTimerTask()
|
||||||
|
GVA_HttpServeMux = http.NewServeMux()
|
||||||
|
GVA_Config config.AppConfig
|
||||||
|
GVA_LOG *zap.Logger
|
||||||
|
GVA_HttpServer *http.Server
|
||||||
|
)
|
||||||
|
|
||||||
|
func HttpServerMux() *http.ServeMux {
|
||||||
|
return GVA_HttpServeMux
|
||||||
|
}
|
||||||
|
func HttpServer() *http.Server {
|
||||||
|
return GVA_HttpServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func Timer() timer.Timer {
|
||||||
|
return GVA_Timer
|
||||||
|
}
|
||||||
|
func Config() config.AppConfig {
|
||||||
|
return GVA_Config
|
||||||
|
}
|
||||||
|
func Cfg() *gcfg.Config {
|
||||||
|
return g.Cfg()
|
||||||
|
}
|
||||||
|
func Log() *zap.SugaredLogger {
|
||||||
|
if GVA_LOG == nil {
|
||||||
|
return zap.S()
|
||||||
|
}
|
||||||
|
return GVA_LOG.Sugar()
|
||||||
|
}
|
||||||
|
func JsonLog() *zap.Logger {
|
||||||
|
if GVA_LOG == nil {
|
||||||
|
return zap.L()
|
||||||
|
}
|
||||||
|
return GVA_LOG
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package g
|
||||||
|
|
||||||
|
type PageResult struct {
|
||||||
|
Rows any `json:"rows"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPageResult(c int64, r any) *PageResult {
|
||||||
|
return &PageResult{
|
||||||
|
Rows: r,
|
||||||
|
Count: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gcfg"
|
||||||
|
"github.com/gogf/gf/v2/os/gctx"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"tgk-touch/internal/core"
|
||||||
|
g "tgk-touch/internal/global"
|
||||||
|
"tgk-touch/internal/model/config"
|
||||||
|
"tgk-touch/internal/module/adl400TtyApi"
|
||||||
|
m9zTtyApi "tgk-touch/internal/module/m9zTtyApi"
|
||||||
|
"tgk-touch/internal/module/m9zTtyPwd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
CfgInit()
|
||||||
|
ZapInit()
|
||||||
|
m9zTtyPwd.Init()
|
||||||
|
m9zTtyApi.Init()
|
||||||
|
adl400TtyApi.Init()
|
||||||
|
timer()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CfgInit() {
|
||||||
|
|
||||||
|
// 读取配置文件
|
||||||
|
loader := gcfg.NewLoader[config.AppConfig](g.Cfg(), "")
|
||||||
|
// 设置配置变更回调
|
||||||
|
loader.OnChange(func(updated config.AppConfig) error {
|
||||||
|
g.GVA_Config = updated
|
||||||
|
ZapInit()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
loader.MustLoadAndWatch(gctx.New(), "app-config")
|
||||||
|
g.GVA_Config = loader.Get()
|
||||||
|
|
||||||
|
}
|
||||||
|
func ZapInit() {
|
||||||
|
// 初始化zap日志库
|
||||||
|
g.GVA_LOG = core.Zap()
|
||||||
|
zap.ReplaceGlobals(g.GVA_LOG)
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
"github.com/towgo/towgo/errors/tcode"
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"sync"
|
||||||
|
g "tgk-touch/internal/global"
|
||||||
|
m9zTtyApi "tgk-touch/internal/module/m9zTtyApi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func timer() {
|
||||||
|
go func() {
|
||||||
|
AddTaskByFunc("ScanM9z", "ScanM9z", "@every 10m", m9zTtyApi.ScanM9z)
|
||||||
|
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var cronTaskNameMap = map[string]cron.EntryID{}
|
||||||
|
var cronLock = sync.Mutex{}
|
||||||
|
|
||||||
|
func AddTaskByFunc(cronName string, taskName string, spec string, task func()) {
|
||||||
|
cronLock.Lock()
|
||||||
|
defer cronLock.Unlock()
|
||||||
|
cronTaskName := cronName + "-" + taskName
|
||||||
|
_, ok := cronTaskNameMap[cronTaskName]
|
||||||
|
if ok {
|
||||||
|
panic(terror.New("定时任务名称重复 " + cronTaskName))
|
||||||
|
}
|
||||||
|
var option []cron.Option
|
||||||
|
option = append(option, cron.WithSeconds(), cron.WithChain(cron.SkipIfStillRunning(cron.DefaultLogger)))
|
||||||
|
cronEnterId, err := g.Timer().AddTaskByFunc(cronName, spec, func() {
|
||||||
|
defer func() {
|
||||||
|
if exception := recover(); exception != nil {
|
||||||
|
if errv, ok := exception.(error); ok {
|
||||||
|
g.GVA_LOG.Sugar().Errorf("corn recovered panic err task [%s] sepc [%s] err:%+v \n", taskName, spec, terror.NewCodef(tcode.CodeInternalPanic, "%+v", errv))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
task()
|
||||||
|
|
||||||
|
}, taskName, option...)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Panicf("add timer error: [%s]", err.Error())
|
||||||
|
}
|
||||||
|
cronTaskNameMap[cronTaskName] = cronEnterId
|
||||||
|
g.GVA_LOG.Sugar().Infof("add timer success: cronName [%s] task [%s] sepc [%s]", cronName, taskName, spec)
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package ADL200
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
"tgk-touch/internal/module/maincontrollerClient"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pushCmd 发送命令到设备并获取响应
|
||||||
|
func pushCmd(commUid string, cmd []byte, detail string) ([]byte, error) {
|
||||||
|
var result []byte
|
||||||
|
err := maincontrollerClient.DeviceCallByDeviceID(commUid, "", "", cmd, &result,
|
||||||
|
func(deviceID, method string, params, result interface{}) (deviceType, cmdDetail, cmdDisplay, resultDisplay string) {
|
||||||
|
deviceType = "ADL200"
|
||||||
|
cmdDetail = detail
|
||||||
|
return
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, terror.Wrapf(err, "DeviceCallByDeviceID err ")
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readCmd 读取保持寄存器
|
||||||
|
func readCmd(commUid string, address byte, startAddr, quantity uint16, detail string) ([]uint16, error) {
|
||||||
|
cmd := ReadHoldingRegistersBuilder(address, startAddr, quantity)
|
||||||
|
g.Log().Debugf("ADL200 Modbus 下发 读取命令 = % X", cmd)
|
||||||
|
result, err := pushCmd(commUid, cmd, detail)
|
||||||
|
if err != nil {
|
||||||
|
return nil, terror.Wrapf(err, "下发[% X]", cmd)
|
||||||
|
}
|
||||||
|
g.Log().Debugf("ADL200 Modbus 响应 读取命令 = % X", result)
|
||||||
|
r, err := ReadHoldingRegisterParse(result, address, quantity)
|
||||||
|
if err != nil {
|
||||||
|
return nil, terror.Wrapf(err, "下发[% X],响应[% X]", cmd, result)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeCmd 写入多个保持寄存器
|
||||||
|
func writeCmd(commUid string, address byte, startAddr uint16, data []uint16, detail string) error {
|
||||||
|
writeData, q := WriteMultipleRegistersBuilder(address, startAddr, data)
|
||||||
|
g.Log().Debugf("ADL200 Modbus 下发 写入命令 = % X", writeData)
|
||||||
|
|
||||||
|
result, err := pushCmd(commUid, writeData, detail)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.Log().Debugf("ADL200 Modbus 响应 写入命令 = % X", result)
|
||||||
|
err = WriteMultipleRegistersParse(address, startAddr, q, result)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
package ADL400
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var (
|
||||||
|
H0000 = MeterModusCmd{startAddr: 0x00, quantity: 2}
|
||||||
|
H0002 = MeterModusCmd{startAddr: 0x02, quantity: 2}
|
||||||
|
H0004 = MeterModusCmd{startAddr: 0x04, quantity: 2}
|
||||||
|
H0006 = MeterModusCmd{startAddr: 0x06, quantity: 2}
|
||||||
|
H0008 = MeterModusCmd{startAddr: 0x08, quantity: 2}
|
||||||
|
H000A = MeterModusCmd{startAddr: 0x0A, quantity: 2, detail: "当前正向总有功电能"}
|
||||||
|
H000C = MeterModusCmd{startAddr: 0x0C, quantity: 2}
|
||||||
|
H000E = MeterModusCmd{startAddr: 0x0E, quantity: 2}
|
||||||
|
H0010 = MeterModusCmd{startAddr: 0x10, quantity: 2}
|
||||||
|
H0012 = MeterModusCmd{startAddr: 0x12, quantity: 2}
|
||||||
|
H0014 = MeterModusCmd{startAddr: 0x14, quantity: 2}
|
||||||
|
H0016 = MeterModusCmd{startAddr: 0x16, quantity: 2}
|
||||||
|
H0018 = MeterModusCmd{startAddr: 0x18, quantity: 2}
|
||||||
|
H001A = MeterModusCmd{startAddr: 0x1A, quantity: 2}
|
||||||
|
H001C = MeterModusCmd{startAddr: 0x1C, quantity: 2}
|
||||||
|
H001E = MeterModusCmd{startAddr: 0x1E, quantity: 2}
|
||||||
|
H0020 = MeterModusCmd{startAddr: 0x20, quantity: 2}
|
||||||
|
H0022 = MeterModusCmd{startAddr: 0x22, quantity: 2}
|
||||||
|
H0024 = MeterModusCmd{startAddr: 0x24, quantity: 2}
|
||||||
|
H0026 = MeterModusCmd{startAddr: 0x26, quantity: 2}
|
||||||
|
H0028 = MeterModusCmd{startAddr: 0x28, quantity: 2}
|
||||||
|
H002A = MeterModusCmd{startAddr: 0x2A, quantity: 2}
|
||||||
|
H002C = MeterModusCmd{startAddr: 0x2C, quantity: 2}
|
||||||
|
H002E = MeterModusCmd{startAddr: 0x2E, quantity: 2}
|
||||||
|
H0030 = MeterModusCmd{startAddr: 0x30, quantity: 2}
|
||||||
|
H0032 = MeterModusCmd{startAddr: 0x32, quantity: 2}
|
||||||
|
H0034 = MeterModusCmd{startAddr: 0x34, quantity: 2}
|
||||||
|
H0036 = MeterModusCmd{startAddr: 0x36, quantity: 2}
|
||||||
|
H0038 = MeterModusCmd{startAddr: 0x38, quantity: 2}
|
||||||
|
H003A = MeterModusCmd{startAddr: 0x3A, quantity: 2}
|
||||||
|
|
||||||
|
H003C = MeterModusCmd{startAddr: 0x3C, quantity: 1, cmdType: 1, detail: "秒、分"}
|
||||||
|
H003D = MeterModusCmd{startAddr: 0x3D, quantity: 1, cmdType: 1, detail: "时、日"}
|
||||||
|
H003E = MeterModusCmd{startAddr: 0x3E, quantity: 1, cmdType: 1, detail: "月、年"}
|
||||||
|
H003F = MeterModusCmd{startAddr: 0x3F, quantity: 1, cmdType: 1, detail: "通信地址"}
|
||||||
|
|
||||||
|
H0040 = MeterModusCmd{startAddr: 0x40, quantity: 1}
|
||||||
|
|
||||||
|
H0041 = MeterModusCmd{startAddr: 0x41, quantity: 1, cmdType: 1}
|
||||||
|
H0042 = MeterModusCmd{startAddr: 0x42, quantity: 1, cmdType: 1}
|
||||||
|
H0043 = MeterModusCmd{startAddr: 0x43, quantity: 1, cmdType: 1}
|
||||||
|
H0044 = MeterModusCmd{startAddr: 0x44, quantity: 1, cmdType: 1}
|
||||||
|
H0045 = MeterModusCmd{startAddr: 0x45, quantity: 1, cmdType: 1}
|
||||||
|
H0046 = MeterModusCmd{startAddr: 0x46, quantity: 1, cmdType: 1}
|
||||||
|
H0061 = MeterModusCmd{startAddr: 0x61, quantity: 1, detail: "A相电压"}
|
||||||
|
H0062 = MeterModusCmd{startAddr: 0x62, quantity: 1, detail: "B相电压"}
|
||||||
|
H0063 = MeterModusCmd{startAddr: 0x63, quantity: 1, detail: "C相电压"}
|
||||||
|
H0064 = MeterModusCmd{startAddr: 0x64, quantity: 1, detail: "A相电流"}
|
||||||
|
H0065 = MeterModusCmd{startAddr: 0x65, quantity: 1, detail: "B相电流"}
|
||||||
|
H0066 = MeterModusCmd{startAddr: 0x66, quantity: 1, detail: "C相电流"}
|
||||||
|
H0067 = MeterModusCmd{startAddr: 0x67, quantity: 1, detail: "A相有功功率"}
|
||||||
|
H0068 = MeterModusCmd{startAddr: 0x68, quantity: 1, detail: "B相有功功率"}
|
||||||
|
H0069 = MeterModusCmd{startAddr: 0x69, quantity: 1, detail: "C相有功功率"}
|
||||||
|
H006A = MeterModusCmd{startAddr: 0x6A, quantity: 1, detail: "总有功功率"}
|
||||||
|
H0087 = MeterModusCmd{startAddr: 0x87, quantity: 2, detail: "A相正向有功电能"}
|
||||||
|
H0089 = MeterModusCmd{startAddr: 0x89, quantity: 2, detail: "B相正向有功电能"}
|
||||||
|
H008B = MeterModusCmd{startAddr: 0x8B, quantity: 2, detail: "C相正向有功电能"}
|
||||||
|
H0073 = MeterModusCmd{startAddr: 0x73, quantity: 2, detail: "A相功率因数"}
|
||||||
|
H0074 = MeterModusCmd{startAddr: 0x74, quantity: 2, detail: "B相功率因数"}
|
||||||
|
H0075 = MeterModusCmd{startAddr: 0x75, quantity: 2, detail: "C相功率因数"}
|
||||||
|
H0076 = MeterModusCmd{startAddr: 0x76, quantity: 2, detail: "总功率因数"}
|
||||||
|
H0121 = MeterModusCmd{startAddr: 0x0121, quantity: 1, cmdType: 1, detail: "日冻结时间 时"}
|
||||||
|
H0122 = MeterModusCmd{startAddr: 0x0121, quantity: 1, cmdType: 1, detail: "月冻结 日时"}
|
||||||
|
H6000 = MeterModusCmd{startAddr: 0x6000, quantity: 34}
|
||||||
|
H6001 = MeterModusCmd{startAddr: 0x6001, quantity: 1}
|
||||||
|
H6022 = MeterModusCmd{startAddr: 0x6022, quantity: 34}
|
||||||
|
)
|
||||||
|
|
||||||
|
type MeterModusCmd struct {
|
||||||
|
startAddr uint16
|
||||||
|
quantity uint16
|
||||||
|
cmdType int // 0 R , 1 R/W
|
||||||
|
detail string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mcc *MeterModusCmd) SetStartAddr(s uint16) {
|
||||||
|
mcc.startAddr = s
|
||||||
|
}
|
||||||
|
func (mcc *MeterModusCmd) GetStartAddr() uint16 {
|
||||||
|
return mcc.startAddr
|
||||||
|
}
|
||||||
|
func (mcc *MeterModusCmd) SetQuantity(q uint16) {
|
||||||
|
mcc.quantity = q
|
||||||
|
}
|
||||||
|
func (mcc *MeterModusCmd) GetQuantity() uint16 {
|
||||||
|
return mcc.quantity
|
||||||
|
}
|
||||||
|
func (mcc *MeterModusCmd) SetCmdType(t int) {
|
||||||
|
mcc.cmdType = t
|
||||||
|
}
|
||||||
|
func (mcc *MeterModusCmd) GetCmdType() int {
|
||||||
|
return mcc.cmdType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mmc *MeterModusCmd) Read(commUid string, addr byte) ([]uint16, error) {
|
||||||
|
|
||||||
|
return readCmd(commUid, addr, mmc.startAddr, mmc.quantity, "读取"+mmc.detail)
|
||||||
|
|
||||||
|
}
|
||||||
|
func (mmc *MeterModusCmd) Write(commUid string, addr byte, data []uint16) error {
|
||||||
|
if mmc.cmdType == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return writeCmd(commUid, addr, mmc.startAddr, data, "写入"+mmc.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日冻结数据块地址
|
||||||
|
func GetDailyBlockAddress(day int) (*MeterModusCmd, error) {
|
||||||
|
if day < 1 || day > 90 {
|
||||||
|
return nil, fmt.Errorf("invalid day value: %d (valid range 1-90)", day)
|
||||||
|
}
|
||||||
|
MMC := &MeterModusCmd{startAddr: 0x6000 + uint16(34*(day-1)), quantity: 34}
|
||||||
|
return MMC, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取月冻结数据块地址
|
||||||
|
func GetMonthlyBlockAddress(month int) (*MeterModusCmd, error) {
|
||||||
|
if month < 1 || month > 48 {
|
||||||
|
return nil, fmt.Errorf("invalid month value: %d (valid range 1-48)", month)
|
||||||
|
}
|
||||||
|
MMC := &MeterModusCmd{startAddr: 0x7000 + uint16(34*(month-1)), quantity: 34}
|
||||||
|
|
||||||
|
return MMC, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
package ADL400
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
"tgk-touch/internal/module/maincontrollerClient"
|
||||||
|
)
|
||||||
|
|
||||||
|
func pushCmd(commUid string, cmd []byte, detail string) ([]byte, error) {
|
||||||
|
|
||||||
|
var result []byte
|
||||||
|
err := maincontrollerClient.DeviceCallByDeviceID(commUid, "", "", cmd, &result,
|
||||||
|
func(deviceID, method string, params, result interface{}) (deviceType, cmdDetail, cmdDisplay, resultDisplay string) {
|
||||||
|
deviceType = "ADL400"
|
||||||
|
cmdDetail = detail
|
||||||
|
return
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, terror.Wrapf(err, "DeviceCallByDeviceID err ")
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCmd(commUid string, address byte, startAddr, quantity uint16, detail string) ([]uint16, error) {
|
||||||
|
cmd := ReadHoldingRegistersBuilder(address, startAddr, quantity)
|
||||||
|
g.Log().Debugf("Modbus 下发 读取命令 = % X", cmd)
|
||||||
|
result, err := pushCmd(commUid, cmd, detail)
|
||||||
|
if err != nil {
|
||||||
|
return nil, terror.Wrapf(err, "下发[% X]", cmd)
|
||||||
|
}
|
||||||
|
g.Log().Debugf("Modbus 响应 读取命令 = % X", result)
|
||||||
|
r, err := ReadHoldingRegisterParse(result, address, quantity)
|
||||||
|
if err != nil {
|
||||||
|
return nil, terror.Wrapf(err, "下发[% X],响应[% X]", cmd, result)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeCmd(commUid string, address byte, startAddr uint16, data []uint16, detail string) error {
|
||||||
|
writeData, q := WriteMultipleRegistersBuilder(address, startAddr, data)
|
||||||
|
g.Log().Debugf("Modbus 下发 写入命令 = % X", writeData)
|
||||||
|
|
||||||
|
result, err := pushCmd(commUid, writeData, detail)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.Log().Debugf("Modbus 响应 写入命令 = % X", result)
|
||||||
|
err = WriteMultipleRegistersParse(address, startAddr, q, result)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package m9z
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 读取设备输出状态参数
|
||||||
|
type OutStatus struct {
|
||||||
|
BackupByte2 byte `json:"backup_byte1"` //备用字节下标2
|
||||||
|
Loops []Loop `json:"loops"` //回路数据
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeviceOutStatusRead(deviceId string) (*OutStatus, error) {
|
||||||
|
out := &OutStatus{}
|
||||||
|
readResp, err := ReadCmd(deviceId, deviceOutStatus, "读取设备输出状态参数")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析10路的继电器动作状态
|
||||||
|
relayBits := BytesToUint16LE(readResp.Data[0:2])
|
||||||
|
//log.Printf("继电器状态(二进制): %016b,% X", relayBits, readResp.Data[0:2]) // 补零显示16位
|
||||||
|
loops := make([]Loop, 10)
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
var loop Loop
|
||||||
|
bit := (relayBits >> i) & 0x01 // 取第i位的值
|
||||||
|
loop.IsOpen = bit == 1
|
||||||
|
loop.Index = i
|
||||||
|
loop.Name = fmt.Sprintf("#%+v", i+1)
|
||||||
|
loops[i] = loop
|
||||||
|
}
|
||||||
|
out.BackupByte2 = readResp.Data[2]
|
||||||
|
pwms := readResp.Data[3 : len(readResp.Data)-1]
|
||||||
|
for index, pwm := range pwms {
|
||||||
|
loops[index].Pwm = hexToPercent(pwm)
|
||||||
|
}
|
||||||
|
out.Loops = loops
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package m9z
|
||||||
|
|
||||||
|
func Restart(deviceId string) error {
|
||||||
|
WriteCmd(deviceId, restart, nil, "重启设备")
|
||||||
|
/*writeResp, err := WriteCmd(deviceId, restart, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !writeResp.Success {
|
||||||
|
return terror.New("设置失败")
|
||||||
|
}*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package m9z
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Save(deviceId string) error {
|
||||||
|
writeResp, err := WriteCmd(deviceId, save, nil, "保存设置")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !writeResp.Success {
|
||||||
|
return terror.New("设置失败")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
package m9z
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoopCommonParameters 回路分控器公共参数结构体 (15个寄存器 = 30字节)
|
||||||
|
type LoopCommonParameters struct {
|
||||||
|
DCVoltage float32 // 直流电压 (0.1V单位)
|
||||||
|
DCCurrent float32 // 直流电流 (0.1A单位)
|
||||||
|
DimmingValue float32 // 调光幅度值 (0-100%)
|
||||||
|
AlarmStatus uint16 // 告警状态 (位图形式) 告警状态寄存器 0x01欠压 0x02过压 0x08电源故障 其中:欠压=短路故障,过压=开路故障,电源故障。
|
||||||
|
AlarmCode string // 告警代码
|
||||||
|
RelayStatus uint16 // 继电器状态 (位图形式)
|
||||||
|
LoopAddress string // 回路地址
|
||||||
|
SubModuleCount uint16 // 子模块数量
|
||||||
|
Reserved [14]byte // 备用字段 (7个寄存器=14字节)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoopModuleParameters 回路子模块参数结构体 (13个寄存器 = 26字节)
|
||||||
|
type LoopModuleParameters struct {
|
||||||
|
OutputVoltage float32 // 模块输出电压值 (0.1V)
|
||||||
|
OutputCurrent float32 // 模块输出电流值 (0.01A)
|
||||||
|
CurrentPWMDuty float32 // 模块电流PWM占空比 (0-10000对应0-100%)
|
||||||
|
VoltagePWMDuty float32 // 模块电压PWM占空比 (0-10000对应0-100%)
|
||||||
|
DeviceAddress string // 模块的设备地址
|
||||||
|
ModuleLoopAddress string // 模块的回路地址
|
||||||
|
CurrentLimitPct float32 // 模块的限流百分数 (0-100对应0-100%)
|
||||||
|
OperatingMode uint16 // 模块手动/自动模式 (0=自动,1=手动)
|
||||||
|
ModuleVersion float32 // 模块的版本号
|
||||||
|
RatedVoltageDuty uint16 // 额定配置电压PWM占空比 (0-10000对应0-100%)
|
||||||
|
RatedCurrentDuty uint16 // 额定配置电流PWM占空比 (0-10000对应0-100%)
|
||||||
|
RatedOutputVoltage uint16 // 额定配置输出电压值 (0.1V)
|
||||||
|
RatedOutputCurrent uint16 // 额定配置输出电流值 (0.01A)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoopFullParameters 完整回路参数数据结构
|
||||||
|
type LoopFullParameters struct {
|
||||||
|
LoopCommonParameters // 公共参数 (30字节)
|
||||||
|
Modules []LoopModuleParameters // 8个模块的参数 (208字节)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLoopFullParameters 解析完整的238字节分控器数据
|
||||||
|
func ParseLoopFullParameters(data []byte) (*LoopFullParameters, error) {
|
||||||
|
if len(data) < 238 {
|
||||||
|
return nil, fmt.Errorf("invalid data length %d, expected 238 bytes", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &LoopFullParameters{}
|
||||||
|
offset := 0
|
||||||
|
|
||||||
|
// 解析公共参数区 (30字节)
|
||||||
|
common := ¶ms.LoopCommonParameters
|
||||||
|
|
||||||
|
common.DCVoltage = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
|
||||||
|
offset += 2
|
||||||
|
common.DCCurrent = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
|
||||||
|
offset += 2
|
||||||
|
common.DimmingValue = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01
|
||||||
|
offset += 2
|
||||||
|
//log.Debugf("AlarmStatus [% X]", data)
|
||||||
|
common.AlarmStatus = uint16(data[offset:][0])
|
||||||
|
common.AlarmCode = fmt.Sprintf("% X", data[offset:offset+2])
|
||||||
|
offset += 2
|
||||||
|
common.RelayStatus = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
if binary.LittleEndian.Uint16(data[offset:]) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
common.LoopAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:]))
|
||||||
|
|
||||||
|
offset += 2
|
||||||
|
common.SubModuleCount = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
copy(common.Reserved[:], data[offset:offset+16])
|
||||||
|
offset += 16
|
||||||
|
params.Modules = make([]LoopModuleParameters, common.SubModuleCount)
|
||||||
|
// 解析8个模块 (每个26字节)
|
||||||
|
for i := 0; i < int(common.SubModuleCount); i++ {
|
||||||
|
module := ¶ms.Modules[i]
|
||||||
|
module.OutputVoltage = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
|
||||||
|
offset += 2
|
||||||
|
module.OutputCurrent = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
|
||||||
|
offset += 2
|
||||||
|
module.CurrentPWMDuty = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01
|
||||||
|
offset += 2
|
||||||
|
module.VoltagePWMDuty = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01
|
||||||
|
offset += 2
|
||||||
|
module.DeviceAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:]))
|
||||||
|
offset += 2
|
||||||
|
module.ModuleLoopAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:]))
|
||||||
|
offset += 2
|
||||||
|
module.CurrentLimitPct = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
|
||||||
|
offset += 2
|
||||||
|
module.OperatingMode = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
version := fmt.Sprintf("%x", binary.LittleEndian.Uint16(data[offset:]))
|
||||||
|
floatVersion := gconv.Float32(version)
|
||||||
|
module.ModuleVersion = floatVersion * 0.1
|
||||||
|
offset += 2
|
||||||
|
module.RatedVoltageDuty = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
module.RatedCurrentDuty = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
module.RatedOutputVoltage = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
module.RatedOutputCurrent = binary.LittleEndian.Uint16(data[offset:])
|
||||||
|
offset += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubLoopParametersRead(device string, idx uint) (*LoopFullParameters, error) {
|
||||||
|
readRep, err := ReadCmd(device, subLoopParameters, "读取回路分控器的参数", idx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseLoopFullParameters(readRep.Data)
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package Adl200Impl
|
||||||
|
|
||||||
|
// Adl200Impl ADL200 单相电表控制器实现
|
||||||
|
type Adl200Impl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAdl200Impl 创建新的 ADL200 控制器实例
|
||||||
|
func NewAdl200Impl() *Adl200Impl {
|
||||||
|
return &Adl200Impl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adl200 单例实例
|
||||||
|
var adl200 *Adl200Impl
|
||||||
|
|
||||||
|
// GetAdl200Impl 获取 ADL200 单例实例
|
||||||
|
func GetAdl200Impl() *Adl200Impl {
|
||||||
|
if adl200 == nil {
|
||||||
|
adl200 = NewAdl200Impl()
|
||||||
|
}
|
||||||
|
return adl200
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
package Adl400Impl
|
||||||
|
|
||||||
|
type Adl400Impl struct {
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package Adl400Impl
|
||||||
|
|
||||||
|
var MeterAdl400 string = "AEM-ADL400"
|
||||||
|
var adl *Adl400Impl
|
||||||
|
|
||||||
|
func NewAdl400Impl() *Adl400Impl {
|
||||||
|
return &Adl400Impl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAdl400Impl() *Adl400Impl {
|
||||||
|
if adl == nil {
|
||||||
|
adl = NewAdl400Impl()
|
||||||
|
}
|
||||||
|
return adl
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package meterControl
|
||||||
|
|
||||||
|
import "tgk-touch/internal/library/meterControl/Adl200Impl"
|
||||||
|
import "tgk-touch/internal/library/meterControl/Adl400Impl"
|
||||||
|
|
||||||
|
type MeterFirm string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ADL200 MeterFirm = "AEM-ADL200"
|
||||||
|
ADL400 MeterFirm = "AEM-ADL400"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
meterControls = make(map[MeterFirm]IMeterControl)
|
||||||
|
readMeterControls = make(map[MeterFirm]IReadMeter)
|
||||||
|
writeMeterControls = make(map[MeterFirm]IWriteMeter)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 注册 ADL200 单相电表控制器
|
||||||
|
meterControls[ADL200] = Adl200Impl.GetAdl200Impl()
|
||||||
|
readMeterControls[ADL200] = Adl200Impl.GetAdl200Impl()
|
||||||
|
writeMeterControls[ADL200] = Adl200Impl.GetAdl200Impl()
|
||||||
|
|
||||||
|
// 注册 ADL400 三相电表控制器
|
||||||
|
meterControls[ADL400] = Adl400Impl.GetAdl400Impl()
|
||||||
|
readMeterControls[ADL400] = Adl400Impl.GetAdl400Impl()
|
||||||
|
writeMeterControls[ADL400] = Adl400Impl.GetAdl400Impl()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMeterControls(firm MeterFirm) IMeterControl {
|
||||||
|
if v, ok := meterControls[firm]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetReadMeterControls(firm MeterFirm) IReadMeter {
|
||||||
|
if v, ok := readMeterControls[firm]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWriteMeterControls(firm MeterFirm) IWriteMeter {
|
||||||
|
if v, ok := writeMeterControls[firm]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package meterControl
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type IMeterControl interface {
|
||||||
|
IReadMeter
|
||||||
|
IWriteMeter
|
||||||
|
}
|
||||||
|
type IReadMeter interface {
|
||||||
|
// 获取电表上年份
|
||||||
|
ReadYear(commUid string, addr byte) (int, error)
|
||||||
|
ReadMonth(commUid string, addr byte) (int, error)
|
||||||
|
ReadDay(commUid string, addr byte) (int, error)
|
||||||
|
ReadHour(commUid string, addr byte) (int, error)
|
||||||
|
ReadMinute(commUid string, addr byte) (int, error)
|
||||||
|
ReadSecond(commUid string, addr byte) (int, error)
|
||||||
|
ReadTime(commUid string, addr byte) (time.Time, error)
|
||||||
|
// ReadVoltage 读取电压 []float64 总电压,1相,2相,3相....
|
||||||
|
ReadVoltage(commUid string, addr byte) (totalVoltage, aVoltage, bVoltage, cVoltage float64, err error)
|
||||||
|
// ReadElectricCurrent 读取电流 []float64 总电流,1相,2相,3相....
|
||||||
|
ReadElectricCurrent(commUid string, addr byte) (totalElectricCurrent, aElectricCurrent, bElectricCurrent, cElectricCurrent float64, err error)
|
||||||
|
// ReadPower 读取功率 []float64 总功率,1相,2相,3相....
|
||||||
|
ReadPower(commUid string, addr byte) (totalPower, aPower, bPower, cPower float64, err error)
|
||||||
|
// ReadTotalPower 读取当前总功率
|
||||||
|
ReadTotalPower(commUid string, addr byte) (totalPower float64, err error)
|
||||||
|
// ReadEnergy 读取功率 []float64 总电能,1相,2相,3相....
|
||||||
|
ReadEnergy(commUid string, addr byte) (totalEnergy, aEnergy, bEnergy, cEnergy float64, err error)
|
||||||
|
// ReadPowerFactor 读取功率因数 []float64 总功率因数,1相,2相,3相....
|
||||||
|
ReadPowerFactor(commUid string, addr byte) (totalPf, aPf, bPf, cPf float64, err error)
|
||||||
|
// ReadMsgAddr 读取通信地址
|
||||||
|
ReadMsgAddr(commUid string, addr byte) (byte, error)
|
||||||
|
// ReadMainAddr 读取主控地址
|
||||||
|
ReadMainAddr(commUid string, addr byte) (byte, error)
|
||||||
|
// ReadDailyFreezingTime 读取日冻结时间
|
||||||
|
ReadDailyFreezingTime(commUid string, addr byte) (string, error)
|
||||||
|
// ReadMonthlyFreezingTime 读取月冻结时间
|
||||||
|
ReadMonthlyFreezingTime(commUid string, addr byte) (day, hour string, err error)
|
||||||
|
}
|
||||||
|
type IWriteMeter interface {
|
||||||
|
// 获取电表上年份
|
||||||
|
WriteYear(commUid string, addr byte, year int) error
|
||||||
|
WriteMonth(commUid string, addr byte, month int) error
|
||||||
|
WriteDay(commUid string, addr byte, day int) error
|
||||||
|
WriteHour(commUid string, addr byte, hour int) error
|
||||||
|
WriteMinute(commUid string, addr byte, minute int) error
|
||||||
|
WriteSecond(commUid string, addr byte, second int) error
|
||||||
|
WriteTime(commUid string, addr byte, t time.Time) error
|
||||||
|
WriteMsgAddr(commUid string, addr byte, newAddr byte) error
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
// Package adl400Api 电表接口
|
||||||
|
package adl400TtyApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
"strings"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
"tgk-touch/internal/library/meterControl"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mc meterControl.IMeterControl
|
||||||
|
|
||||||
|
var deviceInfo map[string]interface{}
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
marshal, _ := json.Marshal(g.Config().DeviceInfo)
|
||||||
|
json.Unmarshal(marshal, &deviceInfo)
|
||||||
|
|
||||||
|
mc = meterControl.GetMeterControls(meterControl.ADL400)
|
||||||
|
initReadFunc()
|
||||||
|
initWriteFunc()
|
||||||
|
|
||||||
|
}
|
||||||
|
func initReadFunc() {
|
||||||
|
towgo.SetFunc("/adl400/readPhaseData", readPhaseData)
|
||||||
|
// 读取通信地址
|
||||||
|
towgo.SetFunc("/adl400/getMsgAddress", getMsgAddress)
|
||||||
|
// 读取日冻结时间
|
||||||
|
towgo.SetFunc("/adl400/getDailyFreezingTime", getDailyFreezingTime)
|
||||||
|
// 读取月冻结时间
|
||||||
|
towgo.SetFunc("/adl400/getMonthlyFreezingTime", getReadMonthlyFreezingTime)
|
||||||
|
// 读取冻结数据
|
||||||
|
towgo.SetFunc("/adl400/getFreezeTheData", getFreezeTheData)
|
||||||
|
// 读取时间
|
||||||
|
towgo.SetFunc("/adl400/geTime", geDeviceTime)
|
||||||
|
}
|
||||||
|
func initWriteFunc() {
|
||||||
|
// 写入通信地址
|
||||||
|
towgo.SetFunc("/adl400/setMsgAddress", setMsgAddress)
|
||||||
|
}
|
||||||
|
func getMeterAddr(cuid string) byte {
|
||||||
|
|
||||||
|
// 去掉 "0x" 前缀,按 16 进制解析
|
||||||
|
return gconv.Byte(strings.TrimPrefix(deviceInfo["meterAddr"].(string), "0x"))
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package adl400TtyApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/util/gconv"
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setMsgAddress(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
MsgAddr string `json:"msg_addr"`
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
|
||||||
|
oldAddr := getMeterAddr(p.CommUid)
|
||||||
|
newAddr := gconv.Byte(strings.TrimPrefix(p.MsgAddr, "0x"))
|
||||||
|
err := mc.WriteMsgAddr(p.CommUid, oldAddr, newAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult("ok")
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package deviceManagement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tgk-touch/internal/library/meterControl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MeterPower struct {
|
||||||
|
MeterId int64 `json:"meterId" xorm:"comment('电表ID')"`
|
||||||
|
MeterAddr string `json:"meterAddr" xorm:"comment('电表从地址')"`
|
||||||
|
|
||||||
|
AVoltage float64 `json:"aVoltage" xorm:"comment('A相电压V/单相电压')"`
|
||||||
|
AElectricCurrent float64 `json:"aElectricCurrent" xorm:"comment('A相电流A/单相电流')"`
|
||||||
|
APower float64 `json:"aPower" xorm:"comment('A相功率Kw/单相功率')"`
|
||||||
|
AEnergy float64 `json:"aEnergy" xorm:"comment('A相电能Kwh/单相电能')"`
|
||||||
|
APowerFactor float64 `json:"aPowerFactor" xorm:"comment('A相功率因数/单相功率因数')"`
|
||||||
|
|
||||||
|
BVoltage float64 `json:"bVoltage" xorm:"comment('B相电压')"`
|
||||||
|
BElectricCurrent float64 `json:"bElectricCurrent" xorm:"comment('B相电流')"`
|
||||||
|
BPower float64 `json:"bPower" xorm:"comment('B相功率')"`
|
||||||
|
BEnergy float64 `json:"bEnergy" xorm:"comment('B相电能Kwh')"`
|
||||||
|
BPowerFactor float64 `json:"bPowerFactor" xorm:"comment('B相功率因数')"`
|
||||||
|
|
||||||
|
CVoltage float64 `json:"cVoltage" xorm:"comment('C相电压')"`
|
||||||
|
CElectricCurrent float64 `json:"cElectricCurrent" xorm:"comment('C相电流')"`
|
||||||
|
CPower float64 `json:"cPower" xorm:"comment('C相功率')"`
|
||||||
|
CEnergy float64 `json:"cEnergy" xorm:"comment('C相电能Kwh')"`
|
||||||
|
CPowerFactor float64 `json:"cPowerFactor" xorm:"comment('C相功率因数')"`
|
||||||
|
|
||||||
|
TotalActivePower float64 `json:"activePower" xorm:"'total_active_power' comment('总有功功率Kw')"` // 006AH
|
||||||
|
TotalActiveEnergy float64 `json:"activeEnergy" xorm:"'total_active_energy' comment('总有功电能Kwh')"` // 000A
|
||||||
|
TotalPowerFactor float64 `json:"powerFactor" xorm:"'total_power_factor' comment('总功率因数')"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Meter struct {
|
||||||
|
CommUid string `json:"commUid"`
|
||||||
|
RtuId int64 `json:"rtuId" xorm:"comment('所属监控终端Id')"`
|
||||||
|
RoadId int64 `json:"roadId" xorm:"comment('路段Id')"`
|
||||||
|
ActiveTime string `json:"activeTime" xorm:"comment('激活时间')"`
|
||||||
|
MeterName string `json:"meterName" xorm:"comment('电表名称')"`
|
||||||
|
MeterAddress string `json:"meterAddress" xorm:"comment('电表从地址')"`
|
||||||
|
Phase3 bool `json:"phase3" xorm:"comment('相位 false单相 true三项')"`
|
||||||
|
MeterModel meterControl.MeterFirm `json:"meterModel" xorm:"comment('电表型号')"`
|
||||||
|
WorkState int64 `json:"workState" xorm:"comment('工作状态 0正常 1禁用 2维修')"`
|
||||||
|
Description string `json:"description" xorm:"comment('描述')"`
|
||||||
|
TotalEnergy float64 `json:"total_energy" xorm:"comment('统计能耗')"`
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package deviceManagement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"tgk-touch/internal/library/m9z"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
TgkMain struct {
|
||||||
|
Name string `json:"name" xorm:"comment('主控器名称')" `
|
||||||
|
RtuId int64 `json:"rtuId" xorm:"comment('终端ID')" `
|
||||||
|
OpenLoopCount int `json:"openLoopCount" xorm:"comment('开启回路数')"`
|
||||||
|
Mode int `json:"mode" xorm:"comment('1~2自动模式, -1 手动模式')"`
|
||||||
|
UpgradeProgress uint32 `json:"upgrade_progress" xorm:"comment('升级进度地址')"`
|
||||||
|
UpgradeStatus int `json:"upgrade_status" xorm:"comment('升级进度 0 未完成 1完成')"`
|
||||||
|
UpgradeFirmwareId string `json:"upgrade_firmware_id" xorm:"comment('固件包升级id')"`
|
||||||
|
FirmwareVersion string `json:"firmware_version" xorm:"comment('固件版本')"`
|
||||||
|
|
||||||
|
BleEnable bool `json:"ble_enable" xorm:"comment('是否启用蓝牙超时')"`
|
||||||
|
BleOfflineMin uint8 `json:"ble_offline_min" xorm:"comment('蓝牙超时时间')"`
|
||||||
|
BleName string `json:"ble_name" xorm:"comment('蓝牙名称')"`
|
||||||
|
Temperature float64 `json:"temperature" xorm:"comment('温度')"`
|
||||||
|
Loops []*TgkLoop `json:"loops" xorm:"json"`
|
||||||
|
}
|
||||||
|
TgkLoop struct {
|
||||||
|
m9z.Loop
|
||||||
|
V float32 `json:"v"`
|
||||||
|
A float32 `json:"a"`
|
||||||
|
Kw float32 `json:"kw"`
|
||||||
|
}
|
||||||
|
)
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package licenseterminal
|
||||||
|
|
||||||
|
type License struct {
|
||||||
|
ID int64 `json:"id"` //Licenseid
|
||||||
|
LicenseKey string `json:"license_key"` //许可证密钥
|
||||||
|
AccessCode string `json:"access_code"` //授权码
|
||||||
|
AccessCodeVersion string `json:"access_code_version"` //授权码的版本
|
||||||
|
OrderSerialNumber string `json:"order_serial_number"` //订单编号
|
||||||
|
ProductSerialNumber string `json:"product_serial_number"` //产品序列号
|
||||||
|
ProductNumber string `json:"product_number"` //产品编号
|
||||||
|
ProductName string `json:"product_name"` //产品名称
|
||||||
|
Starttime int64 `json:"starttime"` //起始日
|
||||||
|
Endtime int64 `json:"endtime"` //截止日期
|
||||||
|
Sale string `json:"sale"` //销售人员
|
||||||
|
CustomerName string `json:"customer_name"` //客户名称
|
||||||
|
Remark string `json:"remark"` //备注
|
||||||
|
Valid bool `json:"valid"` //是否有效(非存储结构)
|
||||||
|
ValidErrMessage string `json:"valid_err_message"` //无效的错误信息
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActiveRequestInfo struct {
|
||||||
|
ProductNumber string `json:"product_number"`
|
||||||
|
AccessCode string `json:"access_code"`
|
||||||
|
AccessCodeVersion string `json:"access_code_version"`
|
||||||
|
LicenseKey string `json:"license_key"`
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package licenseterminal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var method string = "/license/terminal"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
towgo.SetFunc(method+"/list", list)
|
||||||
|
}
|
||||||
|
|
||||||
|
func list(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
rpcConn.WriteResult(GetLicense())
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package m9zApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *M9zFaultHistory) TableName() string {
|
||||||
|
return `m9z_fault_history`
|
||||||
|
}
|
||||||
|
|
||||||
|
type M9zFaultHistory struct {
|
||||||
|
ID int64 `json:"id" xorm:"pk autoincr"`
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
LoopIdx uint `json:"loop_idx"`
|
||||||
|
Voltage float32 `json:"voltage"`
|
||||||
|
FaultMsg string `json:"fault_msg"`
|
||||||
|
FaultCode string `json:"fault_code"`
|
||||||
|
FaultTime time.Time `json:"fault_time" xorm:"created"`
|
||||||
|
OperateStatus uint `json:"operate_status" xorm:"default 0 comment('0未处理,1已处理')"`
|
||||||
|
}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
package m9zApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
var deviceInfo map[string]interface{}
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
marshal, _ := json.Marshal(g.Config().DeviceInfo)
|
||||||
|
json.Unmarshal(marshal, &deviceInfo)
|
||||||
|
towgo.SetFunc("/m9z/fault/list", faultList)
|
||||||
|
towgo.SetFunc("/m9z/fault/batchExec", execFailByIds)
|
||||||
|
// 获取设备输出状态参数
|
||||||
|
towgo.SetFunc("/m9z/getOutStatus", getOutStatus)
|
||||||
|
// 获取设备模式
|
||||||
|
towgo.SetFunc("/m9z/getDeviceMode", getDeviceMode)
|
||||||
|
// 设置设备模式
|
||||||
|
towgo.SetFunc("/m9z/setDeviceMode", setDeviceMode)
|
||||||
|
// 获取手动控制信息
|
||||||
|
towgo.SetFunc("/m9z/getDeviceManualInfo", getDeviceManualInfo)
|
||||||
|
// 设置手动控制
|
||||||
|
towgo.SetFunc("/m9z/setDeviceManualInfo", setDeviceManualInfo)
|
||||||
|
// 获取设备时间
|
||||||
|
towgo.SetFunc("/m9z/getDeviceTime", getDeviceTime)
|
||||||
|
// 设置设备时间
|
||||||
|
towgo.SetFunc("/m9z/setDeviceTime", setDeviceTime)
|
||||||
|
// 获取设备经纬度信息
|
||||||
|
towgo.SetFunc("/m9z/getLgnLatData", getLgnLatData)
|
||||||
|
// 设置设备经纬度信息
|
||||||
|
towgo.SetFunc("/m9z/setLgnLatData", setLgnLatData)
|
||||||
|
// 获取日出日落时间偏差
|
||||||
|
towgo.SetFunc("/m9z/getSunRiseSet", getSunRiseSet)
|
||||||
|
// 设置日出日落时间偏差
|
||||||
|
towgo.SetFunc("/m9z/setSunRiseSet", setSunRiseSet)
|
||||||
|
// 获取设备的状态
|
||||||
|
towgo.SetFunc("/m9z/getDeviceStatus", getDeviceStatus)
|
||||||
|
// 实时监控
|
||||||
|
towgo.SetFunc("/m9z/getDeviceStatus2", getDeviceStatus2)
|
||||||
|
// 获取设备的配置
|
||||||
|
towgo.SetFunc("/m9z/getDeviceConfig", getDeviceConfig)
|
||||||
|
// 设置设备的配置
|
||||||
|
towgo.SetFunc("/m9z/setDeviceConfig", setDeviceConfig)
|
||||||
|
// 获取日出日落时间
|
||||||
|
towgo.SetFunc("/m9z/getDeviceSunRiseTime", getDeviceSunRiseTime)
|
||||||
|
// 保存配置参数
|
||||||
|
towgo.SetFunc("/m9z/setSave", setSave)
|
||||||
|
// 重启设备
|
||||||
|
towgo.SetFunc("/m9z/setRestart", setRestart)
|
||||||
|
// 设置经纬度和日出日落时间差
|
||||||
|
towgo.SetFunc("/m9z/setDeviceLgnLatAndSunRsTime", setDeviceLgnLatAndSunRsTime)
|
||||||
|
// 读取开始任务 (优化指令 CMD=0x13)
|
||||||
|
towgo.SetFunc("/m9z/getStartTask", getStartTask)
|
||||||
|
// 读取中间任务 (优化指令 CMD=0x14)
|
||||||
|
towgo.SetFunc("/m9z/getMiddleTaskRead", getMiddleTaskRead)
|
||||||
|
// 读取结束任务 (优化指令 CMD=0x15)
|
||||||
|
towgo.SetFunc("/m9z/getStopTaskRead", getStopTaskRead)
|
||||||
|
// 写入开始任务 (优化指令 CMD=0x13)
|
||||||
|
towgo.SetFunc("/m9z/setStartTaskWrite", setStartTaskWrite)
|
||||||
|
|
||||||
|
// 写入中间任务 (优化指令 CMD=0x14)
|
||||||
|
towgo.SetFunc("/m9z/setMiddleTaskWrite", setMiddleTaskWrite)
|
||||||
|
|
||||||
|
// 写入结束任务 (优化指令 CMD=0x15)
|
||||||
|
towgo.SetFunc("/m9z/setStopTaskWrite", setStopTaskWrite)
|
||||||
|
towgo.SetFunc("/m9z/getStartTask2", getStartTask2)
|
||||||
|
towgo.SetFunc("/m9z/getStopTask2", getStopTask2)
|
||||||
|
towgo.SetFunc("/m9z/setStartTask2", setStartTask2)
|
||||||
|
towgo.SetFunc("/m9z/setStopTask2", setStopTask2)
|
||||||
|
towgo.SetFunc("/m9z/getMiddleTask2", getMiddleTask2)
|
||||||
|
towgo.SetFunc("/m9z/setMiddleTask2", setMiddleTask2)
|
||||||
|
|
||||||
|
towgo.SetFunc("/m9z/getSubLoopParameters", getSubLoopParameters)
|
||||||
|
towgo.SetFunc("/m9z/getAllSubLoopParameter", getAllSubLoopParameter)
|
||||||
|
towgo.SetFunc("/m9z/touchdisplay/getDeviceID", getTouchDeviceId)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTouchDeviceId(rpc towgo.JsonRpcConnection) {
|
||||||
|
|
||||||
|
rpc.WriteResult(deviceInfo)
|
||||||
|
}
|
||||||
|
func faultDelete(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
}
|
||||||
|
rpc.ReadResult(&p)
|
||||||
|
if p.Id == 0 {
|
||||||
|
panic(terror.New("id 为空"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
err := deleteById(p.Id)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult("ok")
|
||||||
|
}
|
||||||
|
func faultList(rpc towgo.JsonRpcConnection) {
|
||||||
|
data, err := readData()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(g.NewPageResult(int64(len(data)), data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func execFailByIds(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
Ids []int `json:"ids"`
|
||||||
|
Operate uint `json:"operate"` // 0 处理 1删除
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.Operate == 0 {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for _, id := range p.Ids {
|
||||||
|
err := deleteById(id)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rpc.WriteResult("ok")
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,410 @@
|
|||||||
|
package m9zApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
"tgk-touch/internal/library/m9z"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDeviceId(rpc towgo.JsonRpcConnection) (string, []uint) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Idxs []uint `json:"idxs"`
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
return p.CommUid, p.Idxs
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 获取设备输出状态参数
|
||||||
|
func getOutStatus(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
read, err := m9z.DeviceOutStatusRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo 有问题 不管写入什么模式返回都是FF 获取设备编程模式 1-3 对应模式01~模式03 编程模式0~2
|
||||||
|
func getDeviceMode(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
read, err := m9z.ModeRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取手动控制信息
|
||||||
|
func getDeviceManualInfo(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
manual, err := m9z.ManualRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if !manual.Able {
|
||||||
|
// 如果当前非手动控制模式就读取设备状态后赋值给手动控制对象
|
||||||
|
//读取设备状态
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
read, err := m9z.DeviceStatusRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for i, _ := range manual.Loops {
|
||||||
|
manual.Loops[i].IsOpen = read.Relays[i]
|
||||||
|
manual.Loops[i].Pwm = int(read.PWMOutputs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rpc.WriteResult(manual)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备上的时间
|
||||||
|
func getDeviceTime(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
deviceTime, timestampSec, err := m9z.DeviceTimeRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
result["deviceTime"] = deviceTime.Format("2006-01-02 15:04:05")
|
||||||
|
result["timestampSec"] = timestampSec
|
||||||
|
rpc.WriteResult(result)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备经纬度信息
|
||||||
|
func getLgnLatData(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
manual, err := m9z.LgnLatRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
r := map[string]interface{}{}
|
||||||
|
r["lgn"] = manual.Lgn
|
||||||
|
r["lat"] = manual.Lat
|
||||||
|
r["loc"] = manual.Loc.String()
|
||||||
|
rpc.WriteResult(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日出日落时间偏差
|
||||||
|
func getSunRiseSet(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
read, err := m9z.SunRiseSetRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备的状态
|
||||||
|
func getDeviceStatus(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
read, err := m9z.DeviceStatusRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeviceStatusLoop struct {
|
||||||
|
m9z.Loop
|
||||||
|
V float32
|
||||||
|
A float32
|
||||||
|
Kw float32
|
||||||
|
}
|
||||||
|
type DeviceStatus struct {
|
||||||
|
m9z.DeviceStatus
|
||||||
|
Loops []DeviceStatusLoop
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实时监控数据
|
||||||
|
func getDeviceStatus2(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
read, err := m9z.DeviceStatusRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
d := new(DeviceStatus)
|
||||||
|
d.DeviceStatus = *read
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
var loop DeviceStatusLoop
|
||||||
|
loop.Name = fmt.Sprintf("#%+v", i+1)
|
||||||
|
loop.Index = i
|
||||||
|
loop.IsOpen = read.Relays[i]
|
||||||
|
loop.Pwm = int(read.PWMOutputs[i])
|
||||||
|
parametersRead, err := m9z.SubLoopParametersRead(cuid, uint(i))
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if parametersRead != nil {
|
||||||
|
kw := float32(0.0)
|
||||||
|
loop.V = (parametersRead.DCVoltage * 10) / 10
|
||||||
|
for _, v := range parametersRead.Modules {
|
||||||
|
loop.A = loop.A + v.OutputCurrent
|
||||||
|
kw = float32(math.Round(float64(v.OutputCurrent*v.OutputVoltage*1000))/1000) + kw
|
||||||
|
}
|
||||||
|
loop.Kw = ((kw / 1000) * 1000) / 1000
|
||||||
|
loop.A = (loop.A * 100) / 100
|
||||||
|
}
|
||||||
|
d.Loops = append(d.Loops, loop)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
// 按 Timestamp 排序(最早的在前)
|
||||||
|
sort.Slice(d.Loops, func(i, j int) bool {
|
||||||
|
return d.Loops[i].Index < d.Loops[j].Index
|
||||||
|
})
|
||||||
|
rpc.WriteResult(d)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备的配置
|
||||||
|
func getDeviceConfig(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
read, err := m9z.DeviceConfigRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日出日落时间
|
||||||
|
func getDeviceSunRiseTime(rpc towgo.JsonRpcConnection) {
|
||||||
|
cuid, _ := getDeviceId(rpc)
|
||||||
|
|
||||||
|
read, err := m9z.SunRiseTimeRead(cuid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取开始任务 (优化指令 CMD=0x13)
|
||||||
|
func getStartTask(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Mode uint8 `json:"mode"` // 0x00-0x02
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
read, err := m9z.StartTaskRead(p.CommUid, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
/*program, err := m9z.ControlTaskToTaskProgram(m9z.DefaultStopTask, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}*/
|
||||||
|
/*err = m9z.StartTaskWriteByTaskCfg(p.CommUid, p.Mode, m9z.DefaultStartTask)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取中间任务 (优化指令 CMD=0x14)
|
||||||
|
func getMiddleTaskRead(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Mode uint8 `json:"mode"` // 0x00-0x02
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
read, err := m9z.MiddleTaskRead(p.CommUid, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取结束任务 (优化指令 CMD=0x15)
|
||||||
|
func getStopTaskRead(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Mode uint8 `json:"mode"` // 0x00-0x02
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
read, err := m9z.StopTaskRead(p.CommUid, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.WriteResult(read)
|
||||||
|
}
|
||||||
|
func getStartTask2(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Mode uint8 `json:"mode"` // 0x00-0x02
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
read, err := m9z.StartTaskRead(p.CommUid, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(terror.Wrap(err, ""))
|
||||||
|
}
|
||||||
|
task, err := m9z.TaskProgramToControlTask(read)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
|
||||||
|
}
|
||||||
|
if task.TimeType == 1 {
|
||||||
|
timeRead, err := m9z.SunRiseTimeRead(p.CommUid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
task.ExecTime = timeRead.Sunrise
|
||||||
|
}
|
||||||
|
rpc.WriteResult(&m9z.TaskProgram{})
|
||||||
|
|
||||||
|
}
|
||||||
|
func getStopTask2(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Mode uint8 `json:"mode"` // 0x00-0x02
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
read, err := m9z.StopTaskRead(p.CommUid, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
task, err := m9z.TaskProgramToControlTask(read)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if task.TimeType == 1 {
|
||||||
|
timeRead, err := m9z.SunRiseTimeRead(p.CommUid)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
task.ExecTime = timeRead.Sunset
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.WriteResult(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMiddleTask2(rpc towgo.JsonRpcConnection) {
|
||||||
|
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Mode uint8 `json:"mode"` // 0x00-0x02
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
read, err := m9z.MiddleTaskRead(p.CommUid, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
/*program, err := m9z.MiddleControlTaskToTaskProgram(m9z.DefaultMiddleTask, p.Mode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}*/
|
||||||
|
task, err := m9z.TaskProgramToMiddleControlTask(read)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.WriteResult(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubLoopParameters(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
Idx uint `json:"idx"`
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := m9z.SubLoopParametersRead(p.CommUid, p.Idx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rpc.WriteResult(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllSubLoopParameter(rpc towgo.JsonRpcConnection) {
|
||||||
|
var p struct {
|
||||||
|
CommUid string `json:"comm_uid"`
|
||||||
|
}
|
||||||
|
rpc.ReadParams(&p)
|
||||||
|
if p.CommUid == "" {
|
||||||
|
panic(terror.New("comm_uid is empty"))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
subLoopData := make([]*m9z.LoopFullParameters, 0)
|
||||||
|
subLoopMap := make(map[string]*m9z.LoopFullParameters)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
subLoop, err := m9z.SubLoopParametersRead(p.CommUid, uint(i))
|
||||||
|
if err != nil || subLoop == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subLoopMap[subLoop.LoopAddress] = subLoop
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
for _, v := range subLoopMap {
|
||||||
|
subLoopData = append(subLoopData, v)
|
||||||
|
}
|
||||||
|
result["subLoopData"] = subLoopData
|
||||||
|
totalP := 0.0
|
||||||
|
|
||||||
|
for _, subLoop := range subLoopData {
|
||||||
|
totalP = totalP + float64(subLoop.DCVoltage*subLoop.DCCurrent)
|
||||||
|
}
|
||||||
|
result["totalP"] = totalP
|
||||||
|
rpc.WriteResult(result)
|
||||||
|
}
|
||||||
@ -0,0 +1,367 @@
|
|||||||
|
package m9zTtyPwd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
g "tgk-touch/internal/global"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/towgo/towgo/lib/system"
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultPassword = "123456"
|
||||||
|
DefaultSalt = "m9zTty"
|
||||||
|
SessionExpireMinutes = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
manager *PasswordManager = &PasswordManager{
|
||||||
|
verifiedSessions: make(map[string]time.Time),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var noInterceptor bool
|
||||||
|
|
||||||
|
var (
|
||||||
|
whiteListMethods = map[string]bool{
|
||||||
|
"/m9z/password/verify": true,
|
||||||
|
"/m9z/password/change": true,
|
||||||
|
// 实时监控
|
||||||
|
"/m9z/touchdisplay/getDeviceID": true,
|
||||||
|
"/m9z/getDeviceStatus2": true,
|
||||||
|
"/getMessageInterval": true,
|
||||||
|
"/adl400/readPhaseData": true,
|
||||||
|
// 报警预览
|
||||||
|
"/m9z/fault/list": true,
|
||||||
|
}
|
||||||
|
whiteListPrefixes = []string{
|
||||||
|
//"/m9z/get",
|
||||||
|
//"/m9z/system/get",
|
||||||
|
//"/m9z/fault",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type PasswordManager struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
hashedPwd string
|
||||||
|
salt string
|
||||||
|
verifiedSessions map[string]time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordData struct {
|
||||||
|
HashedPassword string `json:"hashed_password"`
|
||||||
|
Salt string `json:"salt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPwdFilePath() string {
|
||||||
|
return filepath.Join(system.GetPathOfProgram(), "data", "m9zTtyPwd.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashPassword(pwd, salt string) string {
|
||||||
|
data := []byte(pwd + salt)
|
||||||
|
sum := sha256.Sum256(data)
|
||||||
|
return hex.EncodeToString(sum[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) loadFromFile() error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
filePath := getPwdFilePath()
|
||||||
|
data, err := os.ReadFile(filePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
|
||||||
|
m.hashedPwd = hashPassword(DefaultPassword, DefaultSalt)
|
||||||
|
m.salt = DefaultSalt
|
||||||
|
|
||||||
|
return m.saveToFile()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pwdData PasswordData
|
||||||
|
if err := json.Unmarshal(data, &pwdData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.hashedPwd = pwdData.HashedPassword
|
||||||
|
m.salt = pwdData.Salt
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) saveToFile() error {
|
||||||
|
filePath := getPwdFilePath()
|
||||||
|
dir := filepath.Dir(filePath)
|
||||||
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pwdData := PasswordData{
|
||||||
|
HashedPassword: m.hashedPwd,
|
||||||
|
Salt: m.salt,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(pwdData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.WriteFile(filePath, data, 0600)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) verify(pwd string) bool {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
return m.hashedPwd == hashPassword(pwd, m.salt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) change(newPwd string) error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
m.hashedPwd = hashPassword(newPwd, m.salt)
|
||||||
|
return m.saveToFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) addVerifiedSession(sessionId string) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
m.verifiedSessions[sessionId] = time.Now().Add(SessionExpireMinutes * time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) isSessionVerified(sessionId string) bool {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
expireTime, ok := m.verifiedSessions[sessionId]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if time.Now().After(expireTime) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) removeSession(sessionId string) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
delete(m.verifiedSessions, sessionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) cleanupExpiredSessions() {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
now := time.Now()
|
||||||
|
for sessionId, expireTime := range m.verifiedSessions {
|
||||||
|
if now.After(expireTime) {
|
||||||
|
delete(m.verifiedSessions, sessionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PasswordManager) isWhiteListed(method string) bool {
|
||||||
|
if whiteListMethods[method] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, prefix := range whiteListPrefixes {
|
||||||
|
if strings.HasPrefix(method, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func NoInterceptor(b bool) {
|
||||||
|
noInterceptor = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnauthorizedMethodAdd(method string) {
|
||||||
|
whiteListMethods[method] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnauthorizedMethodPrefixAdd(prefix string) {
|
||||||
|
whiteListPrefixes = append(whiteListPrefixes, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mu sync.Mutex
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
if err := manager.loadFromFile(); err != nil {
|
||||||
|
g.GVA_LOG.Sugar().Warnf("load password data failed: %v, using default", err)
|
||||||
|
manager.hashedPwd = hashPassword(DefaultPassword, DefaultSalt)
|
||||||
|
manager.salt = DefaultSalt
|
||||||
|
manager.saveToFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
towgo.SetFunc("/m9z/password/verify", verifyPwd)
|
||||||
|
towgo.SetFunc("/m9z/password/change", changePwd)
|
||||||
|
towgo.SetFunc("/m9z/system/getTime", getSystemTime)
|
||||||
|
towgo.SetFunc("/m9z/system/setTime", setSystemTime)
|
||||||
|
|
||||||
|
towgo.AddInterceptor(pwdInterceptor)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(5 * time.Minute)
|
||||||
|
for range ticker.C {
|
||||||
|
manager.cleanupExpiredSessions()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSessionId() string {
|
||||||
|
data := []byte(time.Now().String())
|
||||||
|
sum := md5.Sum(data)
|
||||||
|
return hex.EncodeToString(sum[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyPwd(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
var req struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
rpcConn.ReadParams(&req)
|
||||||
|
|
||||||
|
sessionId := generateSessionId()
|
||||||
|
if manager.verify(req.Password) {
|
||||||
|
manager.addVerifiedSession(sessionId)
|
||||||
|
rpcConn.WriteResult(map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
"session_id": sessionId,
|
||||||
|
"message": "verified",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rpcConn.WriteError(401, "invalid password")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChangePwdReq struct {
|
||||||
|
OldPassword string `json:"old_password"`
|
||||||
|
NewPassword string `json:"new_password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func changePwd(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
var req ChangePwdReq
|
||||||
|
rpcConn.ReadParams(&req)
|
||||||
|
|
||||||
|
if !manager.verify(req.OldPassword) {
|
||||||
|
rpcConn.WriteError(500, "旧密码错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(req.NewPassword) < 6 {
|
||||||
|
rpcConn.WriteError(500, "新密码长度小于 6")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := manager.change(req.NewPassword); err != nil {
|
||||||
|
rpcConn.WriteError(500, "change password failed: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcConn.WriteResult(map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
"message": "password changed",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func pwdInterceptor(conn towgo.JsonRpcConnection) error {
|
||||||
|
if noInterceptor {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcRequest := conn.GetRpcRequest()
|
||||||
|
rpcResponse := conn.GetRpcResponse()
|
||||||
|
|
||||||
|
if manager.isWhiteListed(rpcRequest.Method) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionId := rpcRequest.Session
|
||||||
|
if sessionId == "" {
|
||||||
|
rpcResponse.Error.Set(401, "password verification required")
|
||||||
|
conn.Write()
|
||||||
|
return errors.New("password verification required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !manager.isSessionVerified(sessionId) {
|
||||||
|
rpcResponse.Error.Set(401, "session expired or invalid")
|
||||||
|
conn.Write()
|
||||||
|
return errors.New("password verification required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSystemTime(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
now := time.Now()
|
||||||
|
rpcConn.WriteResult(map[string]interface{}{
|
||||||
|
"timestamp": now.Unix(),
|
||||||
|
"datetime": now.Format("2006-01-02 15:04:05"),
|
||||||
|
"timezone": now.Location().String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetTimeReq struct {
|
||||||
|
Datetime string `json:"datetime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSystemTime(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
var req SetTimeReq
|
||||||
|
rpcConn.ReadParams(&req)
|
||||||
|
|
||||||
|
if req.Datetime == "" {
|
||||||
|
rpcConn.WriteError(400, "datetime is required")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
layouts := []string{
|
||||||
|
"2006-01-02 15:04:05",
|
||||||
|
"2006-01-02T15:04:05Z",
|
||||||
|
"2006-01-02 15:04",
|
||||||
|
"2006-01-02",
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetTime time.Time
|
||||||
|
var parseErr error
|
||||||
|
for _, layout := range layouts {
|
||||||
|
targetTime, parseErr = time.Parse(layout, req.Datetime)
|
||||||
|
if parseErr == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parseErr != nil {
|
||||||
|
rpcConn.WriteError(400, "invalid datetime format, supported: 2006-01-02 15:04:05, 2006-01-02T15:04:05Z, 2006-01-02 15:04, 2006-01-02")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
unixTime := targetTime.Unix()
|
||||||
|
cmd := exec.Command("date", "-s", targetTime.Format("2006-01-02 15:04:05"))
|
||||||
|
cmd.Run()
|
||||||
|
|
||||||
|
cmd = exec.Command("hwclock", "-w")
|
||||||
|
cmd.Run()
|
||||||
|
|
||||||
|
cmd = exec.Command("timedatectl", "set-ntp", "false")
|
||||||
|
cmd.Run()
|
||||||
|
|
||||||
|
rpcConn.WriteResult(map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
"message": "system time updated",
|
||||||
|
"old_time": time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
"new_time": targetTime.Format("2006-01-02 15:04:05"),
|
||||||
|
"unix_time": unixTime,
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,246 @@
|
|||||||
|
package maincontrollerClient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"go.bug.st/serial"
|
||||||
|
)
|
||||||
|
|
||||||
|
var serialPortMode bool
|
||||||
|
var serialPort *SerialPort
|
||||||
|
|
||||||
|
// SerialPort 串口对象
|
||||||
|
type SerialPort struct {
|
||||||
|
config *serial.Mode
|
||||||
|
address string
|
||||||
|
port serial.Port
|
||||||
|
isOpen bool
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
dataChan chan byte
|
||||||
|
onData []func([]byte)
|
||||||
|
ticket *time.Ticker
|
||||||
|
|
||||||
|
isBIO bool
|
||||||
|
bioChan chan []byte
|
||||||
|
bioWriteLock sync.Mutex
|
||||||
|
bioLocker sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSerialPort 创建串口实例
|
||||||
|
func NewSerialPort(portName string, baudRate int) *SerialPort {
|
||||||
|
return &SerialPort{
|
||||||
|
address: portName,
|
||||||
|
|
||||||
|
config: &serial.Mode{
|
||||||
|
|
||||||
|
BaudRate: baudRate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UseSerialPort(portName string, baudRate int) error {
|
||||||
|
serialPortMode = true
|
||||||
|
serialPort = &SerialPort{
|
||||||
|
address: portName,
|
||||||
|
|
||||||
|
config: &serial.Mode{
|
||||||
|
BaudRate: baudRate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := serialPort.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
serialPort.OnDataReceived(func(data []byte) {
|
||||||
|
t := time.NewTimer(time.Millisecond * 100)
|
||||||
|
if serialPort.IsBIO() {
|
||||||
|
<-t.C
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-serialPort.bioChan:
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
serialPort.bioChan <- data
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("无效上传的数据(仅支持BIO模式),丢弃:% X", (data))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open 打开串口连接
|
||||||
|
func (sp *SerialPort) Open() error {
|
||||||
|
|
||||||
|
if sp.isOpen {
|
||||||
|
return terror.New("port is already open")
|
||||||
|
}
|
||||||
|
|
||||||
|
port, err := serial.Open(sp.address, sp.config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.dataChan = make(chan byte, 1)
|
||||||
|
sp.bioChan = make(chan []byte, 1)
|
||||||
|
sp.port = port
|
||||||
|
sp.ctx, sp.cancel = context.WithCancel(context.Background())
|
||||||
|
sp.isOpen = true
|
||||||
|
go sp.readLoop()
|
||||||
|
go sp.readChanLoop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *SerialPort) BIO(data []byte) ([]byte, error) {
|
||||||
|
sp.bioWriteLock.Lock()
|
||||||
|
defer sp.bioWriteLock.Unlock()
|
||||||
|
sp.SetisBIO(true)
|
||||||
|
|
||||||
|
sp.port.Write(data)
|
||||||
|
timer := time.NewTimer(time.Second * 3)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
sp.SetisBIO(false)
|
||||||
|
return nil, terror.New("数据读取超时")
|
||||||
|
case message := <-sp.bioChan:
|
||||||
|
sp.SetisBIO(false)
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 关闭串口连接
|
||||||
|
func (sp *SerialPort) Close() error {
|
||||||
|
|
||||||
|
if !sp.isOpen {
|
||||||
|
return terror.New("port is already closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行关闭操作
|
||||||
|
|
||||||
|
err := sp.port.Close()
|
||||||
|
sp.isOpen = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnDataReceived 注册数据接收事件回调
|
||||||
|
func (sp *SerialPort) OnDataReceived(callback func([]byte)) {
|
||||||
|
sp.onData = append(sp.onData, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *SerialPort) readChanLoop() {
|
||||||
|
sp.ticket = time.NewTicker(time.Millisecond * 100)
|
||||||
|
|
||||||
|
var buf []byte
|
||||||
|
for {
|
||||||
|
if !sp.isOpen {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-sp.ctx.Done():
|
||||||
|
return
|
||||||
|
case <-sp.ticket.C:
|
||||||
|
if len(buf) > 0 {
|
||||||
|
callback := sp.onData
|
||||||
|
for _, f := range callback {
|
||||||
|
go f(buf)
|
||||||
|
}
|
||||||
|
buf = []byte{}
|
||||||
|
}
|
||||||
|
case b := <-sp.dataChan:
|
||||||
|
buf = append(buf, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取循环
|
||||||
|
func (sp *SerialPort) readLoop() {
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-sp.ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
_, err := sp.port.Read(buf)
|
||||||
|
sp.ticket.Reset(time.Millisecond * 100)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
if sp.isOpen {
|
||||||
|
sp.port.Close()
|
||||||
|
sp.isOpen = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.dataChan <- buf[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToBytes(data interface{}) ([]byte, error) {
|
||||||
|
if data == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 []byte 和字符串
|
||||||
|
switch v := data.(type) {
|
||||||
|
case []byte:
|
||||||
|
return v, nil
|
||||||
|
case string:
|
||||||
|
return []byte(v), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理基本类型
|
||||||
|
val := reflect.ValueOf(data)
|
||||||
|
for {
|
||||||
|
if val.Kind() == reflect.Interface {
|
||||||
|
val = val.Elem()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val.Kind() {
|
||||||
|
case reflect.Bool,
|
||||||
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||||
|
reflect.Float32, reflect.Float64:
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := binary.Write(buf, binary.BigEndian, data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 复杂类型使用JSON序列化
|
||||||
|
return json.Marshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *SerialPort) SetisBIO(isBio bool) {
|
||||||
|
sp.bioLocker.Lock()
|
||||||
|
sp.isBIO = isBio
|
||||||
|
sp.bioLocker.Unlock()
|
||||||
|
}
|
||||||
|
func (sp *SerialPort) IsBIO() bool {
|
||||||
|
sp.bioLocker.Lock()
|
||||||
|
defer sp.bioLocker.Unlock()
|
||||||
|
return sp.isBIO
|
||||||
|
}
|
||||||
@ -0,0 +1,193 @@
|
|||||||
|
package utility
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/towgo/towgo/errors/terror"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"tgk-touch/internal/global"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: PathExists
|
||||||
|
//@description: 文件目录是否存在
|
||||||
|
//@param: path string
|
||||||
|
//@return: bool, error
|
||||||
|
|
||||||
|
func PathExists(path string) (bool, error) {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
if fi.IsDir() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, terror.New("存在同名文件")
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: CreateDir
|
||||||
|
//@description: 批量创建文件夹
|
||||||
|
//@param: dirs ...string
|
||||||
|
//@return: err error
|
||||||
|
|
||||||
|
func CreateDir(dirs ...string) (err error) {
|
||||||
|
for _, v := range dirs {
|
||||||
|
exist, err := PathExists(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
g.GVA_LOG.Debug("create directory" + v)
|
||||||
|
if err := os.MkdirAll(v, os.ModePerm); err != nil {
|
||||||
|
g.GVA_LOG.Error("create directory"+v, zap.Any(" error:", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [songzhibin97](https://github.com/songzhibin97)
|
||||||
|
//@function: FileMove
|
||||||
|
//@description: 文件移动供外部调用
|
||||||
|
//@param: src string, dst string(src: 源位置,绝对路径or相对路径, dst: 目标位置,绝对路径or相对路径,必须为文件夹)
|
||||||
|
//@return: err error
|
||||||
|
|
||||||
|
func FileMove(src string, dst string) (err error) {
|
||||||
|
if dst == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
src, err = filepath.Abs(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dst, err = filepath.Abs(dst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
revoke := false
|
||||||
|
dir := filepath.Dir(dst)
|
||||||
|
Redirect:
|
||||||
|
_, err = os.Stat(dir)
|
||||||
|
if err != nil {
|
||||||
|
err = os.MkdirAll(dir, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !revoke {
|
||||||
|
revoke = true
|
||||||
|
goto Redirect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.Rename(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeLFile(filePath string) error {
|
||||||
|
return os.RemoveAll(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [rice]
|
||||||
|
//@function: FileCopy
|
||||||
|
//@description: 文件复制供外部调用
|
||||||
|
//@param: src string, dst string(src: 源位置,绝对路径or相对路径, dst: 目标位置,绝对路径or相对路径,必须为文件夹)
|
||||||
|
//@return: err error
|
||||||
|
|
||||||
|
func FileCopy(src string, dst string) (err error) {
|
||||||
|
if dst == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
src, err = filepath.Abs(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dst, err = filepath.Abs(dst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查源文件是否存在
|
||||||
|
srcInfo, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if srcInfo.IsDir() {
|
||||||
|
return terror.New("源路径是一个目录,不是文件")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保目标目录存在
|
||||||
|
revoke := false
|
||||||
|
dir := filepath.Dir(dst)
|
||||||
|
Redirect:
|
||||||
|
_, err = os.Stat(dir)
|
||||||
|
if err != nil {
|
||||||
|
err = os.MkdirAll(dir, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !revoke {
|
||||||
|
revoke = true
|
||||||
|
goto Redirect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开源文件
|
||||||
|
srcFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
// 创建目标文件
|
||||||
|
dstFile, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dstFile.Close()
|
||||||
|
|
||||||
|
// 复制文件内容
|
||||||
|
_, err = io.Copy(dstFile, srcFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保持文件权限一致
|
||||||
|
return os.Chmod(dst, srcInfo.Mode())
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [songzhibin97](https://github.com/songzhibin97)
|
||||||
|
//@function: TrimSpace
|
||||||
|
//@description: 去除结构体空格
|
||||||
|
//@param: target interface (target: 目标结构体,传入必须是指针类型)
|
||||||
|
//@return: null
|
||||||
|
|
||||||
|
func TrimSpace(target interface{}) {
|
||||||
|
t := reflect.TypeOf(target)
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t = t.Elem()
|
||||||
|
v := reflect.ValueOf(target).Elem()
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
switch v.Field(i).Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
v.Field(i).SetString(strings.TrimSpace(v.Field(i).String()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileExist 判断文件是否存在
|
||||||
|
func FileExist(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err == nil {
|
||||||
|
return !fi.IsDir()
|
||||||
|
}
|
||||||
|
return !os.IsNotExist(err)
|
||||||
|
}
|
||||||
@ -0,0 +1,237 @@
|
|||||||
|
package timer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Timer interface {
|
||||||
|
// 寻找所有Cron
|
||||||
|
FindCronList() map[string]*taskManager
|
||||||
|
// 添加Task 方法形式以秒的形式加入
|
||||||
|
AddTaskByFuncWithSecond(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) // 添加Task Func以秒的形式加入
|
||||||
|
// 添加Task 接口形式以秒的形式加入
|
||||||
|
AddTaskByJobWithSeconds(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error)
|
||||||
|
// 通过函数的方法添加任务
|
||||||
|
AddTaskByFunc(cronName string, spec string, task func(), taskName string, option ...cron.Option) (cron.EntryID, error)
|
||||||
|
// 通过接口的方法添加任务 要实现一个带有 Run方法的接口触发
|
||||||
|
AddTaskByJob(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error)
|
||||||
|
// 获取对应taskName的cron 可能会为空
|
||||||
|
FindCron(cronName string) (*taskManager, bool)
|
||||||
|
// 指定cron开始执行
|
||||||
|
StartCron(cronName string)
|
||||||
|
// 指定cron停止执行
|
||||||
|
StopCron(cronName string)
|
||||||
|
// 查找指定cron下的指定task
|
||||||
|
FindTask(cronName string, taskName string) (*task, bool)
|
||||||
|
// 根据id删除指定cron下的指定task
|
||||||
|
RemoveTask(cronName string, id int)
|
||||||
|
// 根据taskName删除指定cron下的指定task
|
||||||
|
RemoveTaskByName(cronName string, taskName string)
|
||||||
|
// 清理掉指定cronName
|
||||||
|
Clear(cronName string)
|
||||||
|
// 停止所有的cron
|
||||||
|
Stop()
|
||||||
|
Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
type task struct {
|
||||||
|
EntryID cron.EntryID
|
||||||
|
Spec string
|
||||||
|
TaskName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type taskManager struct {
|
||||||
|
corn *cron.Cron
|
||||||
|
tasks map[cron.EntryID]*task
|
||||||
|
}
|
||||||
|
|
||||||
|
// timer 定时任务管理
|
||||||
|
type timer struct {
|
||||||
|
cronList map[string]*taskManager
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTaskByFunc 通过函数的方法添加任务
|
||||||
|
func (t *timer) AddTaskByFunc(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
if _, ok := t.cronList[cronName]; !ok {
|
||||||
|
tasks := make(map[cron.EntryID]*task)
|
||||||
|
t.cronList[cronName] = &taskManager{
|
||||||
|
corn: cron.New(option...),
|
||||||
|
tasks: tasks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id, err := t.cronList[cronName].corn.AddFunc(spec, fun)
|
||||||
|
t.cronList[cronName].corn.Start()
|
||||||
|
t.cronList[cronName].tasks[id] = &task{
|
||||||
|
EntryID: id,
|
||||||
|
Spec: spec,
|
||||||
|
TaskName: taskName,
|
||||||
|
}
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTaskByFuncWithSecond 通过函数的方法使用WithSeconds添加任务
|
||||||
|
func (t *timer) AddTaskByFuncWithSecond(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
option = append(option, cron.WithSeconds())
|
||||||
|
if _, ok := t.cronList[cronName]; !ok {
|
||||||
|
tasks := make(map[cron.EntryID]*task)
|
||||||
|
t.cronList[cronName] = &taskManager{
|
||||||
|
corn: cron.New(option...),
|
||||||
|
tasks: tasks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id, err := t.cronList[cronName].corn.AddFunc(spec, fun)
|
||||||
|
t.cronList[cronName].corn.Start()
|
||||||
|
t.cronList[cronName].tasks[id] = &task{
|
||||||
|
EntryID: id,
|
||||||
|
Spec: spec,
|
||||||
|
TaskName: taskName,
|
||||||
|
}
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTaskByJob 通过接口的方法添加任务
|
||||||
|
func (t *timer) AddTaskByJob(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
if _, ok := t.cronList[cronName]; !ok {
|
||||||
|
tasks := make(map[cron.EntryID]*task)
|
||||||
|
t.cronList[cronName] = &taskManager{
|
||||||
|
corn: cron.New(option...),
|
||||||
|
tasks: tasks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id, err := t.cronList[cronName].corn.AddJob(spec, job)
|
||||||
|
t.cronList[cronName].corn.Start()
|
||||||
|
t.cronList[cronName].tasks[id] = &task{
|
||||||
|
EntryID: id,
|
||||||
|
Spec: spec,
|
||||||
|
TaskName: taskName,
|
||||||
|
}
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTaskByJobWithSeconds 通过接口的方法添加任务
|
||||||
|
func (t *timer) AddTaskByJobWithSeconds(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
option = append(option, cron.WithSeconds())
|
||||||
|
if _, ok := t.cronList[cronName]; !ok {
|
||||||
|
tasks := make(map[cron.EntryID]*task)
|
||||||
|
t.cronList[cronName] = &taskManager{
|
||||||
|
corn: cron.New(option...),
|
||||||
|
tasks: tasks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id, err := t.cronList[cronName].corn.AddJob(spec, job)
|
||||||
|
t.cronList[cronName].corn.Start()
|
||||||
|
t.cronList[cronName].tasks[id] = &task{
|
||||||
|
EntryID: id,
|
||||||
|
Spec: spec,
|
||||||
|
TaskName: taskName,
|
||||||
|
}
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindCron 获取对应cronName的cron 可能会为空
|
||||||
|
func (t *timer) FindCron(cronName string) (*taskManager, bool) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
v, ok := t.cronList[cronName]
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindTask 获取对应cronName的cron 可能会为空
|
||||||
|
func (t *timer) FindTask(cronName string, taskName string) (*task, bool) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
v, ok := t.cronList[cronName]
|
||||||
|
if !ok {
|
||||||
|
return nil, ok
|
||||||
|
}
|
||||||
|
for _, t2 := range v.tasks {
|
||||||
|
if t2.TaskName == taskName {
|
||||||
|
return t2, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindCronList 获取所有的任务列表
|
||||||
|
func (t *timer) FindCronList() map[string]*taskManager {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
return t.cronList
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartCron 开始任务
|
||||||
|
func (t *timer) StartCron(cronName string) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
if v, ok := t.cronList[cronName]; ok {
|
||||||
|
v.corn.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopCron 停止任务
|
||||||
|
func (t *timer) StopCron(cronName string) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
if v, ok := t.cronList[cronName]; ok {
|
||||||
|
v.corn.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTask 从cronName 删除指定任务
|
||||||
|
func (t *timer) RemoveTask(cronName string, id int) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
if v, ok := t.cronList[cronName]; ok {
|
||||||
|
v.corn.Remove(cron.EntryID(id))
|
||||||
|
delete(v.tasks, cron.EntryID(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTaskByName 从cronName 使用taskName 删除指定任务
|
||||||
|
func (t *timer) RemoveTaskByName(cronName string, taskName string) {
|
||||||
|
fTask, ok := t.FindTask(cronName, taskName)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.RemoveTask(cronName, int(fTask.EntryID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear 清除任务
|
||||||
|
func (t *timer) Clear(cronName string) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
if v, ok := t.cronList[cronName]; ok {
|
||||||
|
v.corn.Stop()
|
||||||
|
delete(t.cronList, cronName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (t *timer) Start() {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
for _, v := range t.cronList {
|
||||||
|
v.corn.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 释放资源
|
||||||
|
func (t *timer) Stop() {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
for _, v := range t.cronList {
|
||||||
|
v.corn.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimerTask() Timer {
|
||||||
|
return &timer{cronList: make(map[string]*taskManager)}
|
||||||
|
}
|
||||||
Loading…
Reference in new issue