32 changed files with 1691 additions and 38 deletions
@ -0,0 +1,37 @@ |
|||||||
|
|
||||||
|
[app] |
||||||
|
|
||||||
|
[grpc] |
||||||
|
address = ":7010" |
||||||
|
maxSendMsgSize = "8Mi" |
||||||
|
maxRecvMsgSize = "8Mi" |
||||||
|
readBufferSize = "8Ki" |
||||||
|
writeBufferSize = "8Ki" |
||||||
|
|
||||||
|
[grpc.register.attrs] |
||||||
|
weight = 100 |
||||||
|
|
||||||
|
[etcd] |
||||||
|
endpoints = ["124.222.131.236:3279"] |
||||||
|
username = "root" |
||||||
|
password = "sopod@etcd" |
||||||
|
|
||||||
|
[redis] |
||||||
|
Addr = "124.222.131.236:3379" |
||||||
|
Password = "sopod@redis#" |
||||||
|
DB = 1 |
||||||
|
MinIdleConns = 3 |
||||||
|
|
||||||
|
[nats] |
||||||
|
Url = "nats://nats.sopod@124.222.131.236:3222" |
||||||
|
|
||||||
|
[gorm] |
||||||
|
logMode=true |
||||||
|
|
||||||
|
[gorm.mysql] |
||||||
|
# https://gorm.io/zh_CN/docs/connecting_to_the_database.html |
||||||
|
DSN = "root:sopod_mysql2347-@tcp(124.222.131.236:3666)/groups?charset=utf8&parseTime=True&loc=Local" |
||||||
|
|
||||||
|
[prometheus] |
||||||
|
enable = false |
||||||
|
port = 7019 |
||||||
@ -1,6 +1,36 @@ |
|||||||
package main |
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
clientv3 "go.etcd.io/etcd/client/v3" |
||||||
|
"google.golang.org/grpc/grpclog" |
||||||
|
"sonet/internal/postal/logic" |
||||||
|
"sonet/pkg/config" |
||||||
|
"sonet/pkg/grpc/discovery" |
||||||
|
"sonet/pkg/utils/logger" |
||||||
|
"sonet/pkg/utils/shutdown" |
||||||
|
) |
||||||
|
|
||||||
// websocket server with postalService
|
// websocket server with postalService
|
||||||
func main() { |
func main() { |
||||||
|
grpclog.SetLoggerV2(logger.Logger) |
||||||
|
|
||||||
|
conf := config.LoadConfig(nil, "cmd/gateway_ws") |
||||||
|
postalServer := logic.NewPostalServer() |
||||||
|
|
||||||
|
// registry and run...
|
||||||
|
etcdClient, err := clientv3.New(conf.Etcd) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
postalRegistry := discovery.NewRegister(etcdClient) |
||||||
|
shutdown.AddShutdownHook(postalRegistry.Stop) |
||||||
|
|
||||||
|
go func() { |
||||||
|
err = postalServer.Run(conf.Grpc, postalRegistry) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
shutdown.Await() |
||||||
} |
} |
||||||
|
|||||||
@ -1,3 +1,7 @@ |
|||||||
package sonet |
package sonet |
||||||
|
|
||||||
//go:generate protoc --go_out=./api/gen --go-grpc_out=./api/gen ./api/*.proto
|
//go:generate protoc --go_out=./api/gen --go-grpc_out=./api/gen ./api/*.proto
|
||||||
|
//go:generate pbjs -t static-module -w es6 -o api/genjs/postal.js api/postal.proto --no-service
|
||||||
|
//go:generate pbjs -t static-module -w es6 -o api/genjs/auth.js api/auth.proto --no-service
|
||||||
|
//go:generate pbjs -t static-module -w es6 -o api/genjs/chat.js api/chat.proto --no-service
|
||||||
|
//go:generate pbjs -t static-module -w es6 -o api/genjs/mahjong.js api/mahjong.proto --no-service
|
||||||
|
|||||||
@ -1,20 +1,192 @@ |
|||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= |
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= |
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= |
||||||
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= |
||||||
|
github.com/bufbuild/protocompile v0.7.1 h1:Kd8fb6EshOHXNNRtYAmLAwy/PotlyFoN0iMbuwGNh0M= |
||||||
|
github.com/bufbuild/protocompile v0.7.1/go.mod h1:+Etjg4guZoAqzVk2czwEQP12yaxLJ8DxuqCJ9qHdH94= |
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= |
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= |
||||||
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= |
||||||
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= |
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= |
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= |
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= |
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= |
||||||
|
github.com/dsnet/golib/unitconv v1.0.2 h1:45gXng3Op1vTrnX1PdM9Bla4mEpBFYA5aC8dlqacmwM= |
||||||
|
github.com/dsnet/golib/unitconv v1.0.2/go.mod h1:86KTUtTJFLreKjc4sS9xE0rhj4lR44Ox0rEQSEXSWwM= |
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= |
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= |
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= |
||||||
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= |
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= |
||||||
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= |
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= |
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= |
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= |
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= |
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= |
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= |
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= |
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= |
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= |
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= |
||||||
golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= |
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= |
||||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= |
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= |
github.com/jhump/protoreflect v1.15.4 h1:mrwJhfQGGljwvR/jPEocli8KA6G9afbQpH8NY2wORcI= |
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
github.com/jhump/protoreflect v1.15.4/go.mod h1:2B+zwrnMY3TTIqEK01OG/d3pyUycQBfDf+bx8fE2DNg= |
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= |
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= |
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= |
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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= |
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
||||||
|
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= |
||||||
|
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= |
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= |
||||||
|
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/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= |
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= |
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= |
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |
||||||
|
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E= |
||||||
|
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= |
||||||
|
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY= |
||||||
|
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts= |
||||||
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= |
||||||
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= |
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= |
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= |
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= |
||||||
|
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk= |
||||||
|
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= |
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= |
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= |
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= |
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= |
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= |
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= |
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= |
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= |
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= |
||||||
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= |
||||||
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= |
||||||
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= |
||||||
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= |
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= |
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= |
||||||
|
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= |
||||||
|
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= |
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= |
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= |
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= |
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= |
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= |
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= |
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= |
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= |
||||||
|
go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E= |
||||||
|
go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= |
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A= |
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= |
||||||
|
go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU= |
||||||
|
go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE= |
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= |
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= |
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= |
||||||
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= |
||||||
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= |
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= |
||||||
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= |
||||||
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= |
||||||
|
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= |
||||||
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= |
||||||
|
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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
||||||
|
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= |
||||||
|
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= |
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= |
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= |
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
||||||
|
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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= |
||||||
|
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= |
||||||
|
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= |
||||||
|
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= |
||||||
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= |
||||||
|
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-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
||||||
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= |
||||||
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= |
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= |
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= |
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= |
||||||
|
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= |
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= |
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= |
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= |
||||||
|
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= |
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= |
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= |
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= |
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= |
||||||
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= |
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= |
||||||
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= |
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= |
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= |
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= |
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= |
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= |
||||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= |
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= |
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= |
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= |
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= |
||||||
|
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/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= |
||||||
|
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.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= |
||||||
|
gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= |
||||||
|
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= |
||||||
|
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= |
||||||
|
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= |
||||||
|
|||||||
@ -0,0 +1,23 @@ |
|||||||
|
package logic |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"sonet/api/gen/auth" |
||||||
|
) |
||||||
|
|
||||||
|
type AuthServer struct { |
||||||
|
auth.UnimplementedAuthServer |
||||||
|
} |
||||||
|
|
||||||
|
func (s *AuthServer) Login(ctx context.Context, req *auth.ReqLogin) (*auth.ResLogin, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
func (s *AuthServer) Verify(ctx context.Context, req *auth.ReqVerify) (*auth.Subject, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
func (s *AuthServer) Registry(ctx context.Context, req *auth.ReqRegistry) (*auth.Subject, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
func (s *AuthServer) FindByUid(ctx context.Context, req *auth.ReqFindByUid) (*auth.Subject, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
package logic |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"google.golang.org/protobuf/types/known/emptypb" |
||||||
|
"sonet/api/gen/chat" |
||||||
|
) |
||||||
|
|
||||||
|
type ChatServer struct { |
||||||
|
chat.UnimplementedChatServer |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) Send(ctx context.Context, send *chat.ReqSend) (*chat.ResSend, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomSend(ctx context.Context, send *chat.ReqRoomSend) (*chat.ResSend, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomCreate(ctx context.Context, create *chat.ReqRoomCreate) (*chat.ResRoomCreate, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomJoin(ctx context.Context, join *chat.ReqRoomJoin) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomLeave(ctx context.Context, leave *chat.ReqRoomLeave) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomKickOut(ctx context.Context, out *chat.ReqRoomKickOut) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomInfo(ctx context.Context, info *chat.ReqRoomInfo) (*chat.ResRoomInfo, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *ChatServer) RoomList(ctx context.Context, list *chat.ReqRoomList) (*chat.ResRoomList, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
@ -0,0 +1,59 @@ |
|||||||
|
package logic |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"google.golang.org/protobuf/types/known/emptypb" |
||||||
|
"sonet/api/gen/mahjong" |
||||||
|
) |
||||||
|
|
||||||
|
type MahjongServer struct { |
||||||
|
mahjong.UnimplementedMahjongServer |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) PlayerOnline(ctx context.Context, empty *emptypb.Empty) (*mahjong.ResPlayerOnline, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) PlayerOffline(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) LobbyView(ctx context.Context, empty *emptypb.Empty) (*mahjong.Lobby, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) CreateTable(ctx context.Context, empty *emptypb.Empty) (*mahjong.MjTable, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) JoinTable(ctx context.Context, table *mahjong.ReqJoinTable) (*mahjong.MjTable, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) LeaveTable(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) KickoutTable(ctx context.Context, table *mahjong.ReqKickoutTable) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) ReadyStart(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) CancelReady(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) DismissTable(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) GameStart(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *MahjongServer) PlayerAction(ctx context.Context, action *mahjong.ReqPlayerAction) (*emptypb.Empty, error) { |
||||||
|
return nil, nil |
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
package ws |
||||||
|
|
||||||
|
type WebsocketServer struct { |
||||||
|
} |
||||||
@ -0,0 +1,55 @@ |
|||||||
|
package config |
||||||
|
|
||||||
|
import ( |
||||||
|
nats "github.com/nats-io/nats.go" |
||||||
|
redis "github.com/redis/go-redis/v9" |
||||||
|
clientv3 "go.etcd.io/etcd/client/v3" |
||||||
|
"gorm.io/driver/mysql" |
||||||
|
"gorm.io/gorm" |
||||||
|
"sonet/pkg/grpc/discovery" |
||||||
|
) |
||||||
|
|
||||||
|
// Configuration 服务配置
|
||||||
|
type Configuration struct { |
||||||
|
App map[string]any |
||||||
|
Grpc GrpcConfig |
||||||
|
GrpcClient GrpcClientConfig |
||||||
|
Gorm GormConfig |
||||||
|
Snowflake SnowflakeConfig |
||||||
|
Etcd clientv3.Config |
||||||
|
Redis redis.Options |
||||||
|
Nats nats.Options |
||||||
|
Prometheus PrometheusConfig |
||||||
|
} |
||||||
|
|
||||||
|
type GrpcConfig struct { |
||||||
|
Address string |
||||||
|
NoReflection bool |
||||||
|
MaxSendMsgSize string |
||||||
|
MaxRecvMsgSize string |
||||||
|
ReadBufferSize string |
||||||
|
WriteBufferSize string |
||||||
|
Register discovery.Server |
||||||
|
} |
||||||
|
|
||||||
|
type GrpcKeepaliveConfig struct { |
||||||
|
// todo...
|
||||||
|
} |
||||||
|
|
||||||
|
type GrpcClientConfig struct { |
||||||
|
} |
||||||
|
|
||||||
|
type GormConfig struct { |
||||||
|
LogMode bool // default false
|
||||||
|
gorm.Config |
||||||
|
Mysql mysql.Config |
||||||
|
} |
||||||
|
|
||||||
|
type SnowflakeConfig struct { |
||||||
|
NodeId int64 // 0-1023, 相同服务每个部署实例不重复
|
||||||
|
} |
||||||
|
|
||||||
|
type PrometheusConfig struct { |
||||||
|
Enable bool |
||||||
|
Port int |
||||||
|
} |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
package config |
||||||
|
|
||||||
|
import ( |
||||||
|
"gorm.io/driver/mysql" |
||||||
|
"gorm.io/gorm" |
||||||
|
"gorm.io/gorm/logger" |
||||||
|
) |
||||||
|
|
||||||
|
func NewGorm(conf GormConfig) *gorm.DB { |
||||||
|
if conf.LogMode { |
||||||
|
conf.Logger = logger.Default.LogMode(logger.Info) |
||||||
|
} |
||||||
|
db, err := gorm.Open(mysql.New(conf.Mysql), &conf) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
return db |
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
package config |
||||||
|
|
||||||
|
import ( |
||||||
|
"google.golang.org/grpc" |
||||||
|
"sonet/pkg/utils/conver" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGrpcOptions(config GrpcConfig) (opts []grpc.ServerOption) { |
||||||
|
if config.MaxSendMsgSize != "" { |
||||||
|
opts = append(opts, grpc.MaxSendMsgSize(conver.MustParseDataUnitInt(config.MaxSendMsgSize))) |
||||||
|
} |
||||||
|
if config.MaxRecvMsgSize != "" { |
||||||
|
opts = append(opts, grpc.MaxSendMsgSize(conver.MustParseDataUnitInt(config.MaxRecvMsgSize))) |
||||||
|
} |
||||||
|
if config.ReadBufferSize != "" { |
||||||
|
opts = append(opts, grpc.MaxSendMsgSize(conver.MustParseDataUnitInt(config.ReadBufferSize))) |
||||||
|
} |
||||||
|
if config.WriteBufferSize != "" { |
||||||
|
opts = append(opts, grpc.MaxSendMsgSize(conver.MustParseDataUnitInt(config.WriteBufferSize))) |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
@ -0,0 +1,80 @@ |
|||||||
|
package config |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"flag" |
||||||
|
"github.com/spf13/viper" |
||||||
|
"os" |
||||||
|
"sonet/pkg/utils/logger" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
func parseConfPathFlag(confPath string) (filePath, fileName, confName, confType string) { |
||||||
|
idx := strings.LastIndex(confPath, "/") |
||||||
|
filePath = confPath[:idx+1] |
||||||
|
fileName = confPath[idx+1:] |
||||||
|
idx2 := strings.LastIndex(fileName, ".") |
||||||
|
confName = fileName[:idx2] |
||||||
|
confType = fileName[idx2+1:] |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// LoadConfig load config.toml
|
||||||
|
// appConf service custom config
|
||||||
|
// return common service configuration
|
||||||
|
func LoadConfig(appConf any, confPathArg ...string) *Configuration { |
||||||
|
confPath := "" |
||||||
|
confName := "config" |
||||||
|
confType := "toml" |
||||||
|
envPrefix := "SO" |
||||||
|
|
||||||
|
if len(confPathArg) > 0 { |
||||||
|
confPath = confPathArg[0] |
||||||
|
} |
||||||
|
|
||||||
|
// go run xx -conf=config/xx.toml
|
||||||
|
confPathFlag := flag.String("conf", "", "config file path.") |
||||||
|
envPrefixFlag := flag.String("envPrefix", "", "env config key prefix.") |
||||||
|
flag.Parse() |
||||||
|
if *confPathFlag != "" { |
||||||
|
confPath, _, confName, confType = parseConfPathFlag(*confPathFlag) |
||||||
|
} |
||||||
|
if *envPrefixFlag != "" { |
||||||
|
envPrefix = *envPrefixFlag |
||||||
|
} |
||||||
|
if confPath == "" { |
||||||
|
confPath = "./" |
||||||
|
} |
||||||
|
logger.Infof("use config file: %s%s.%s, env prefix=%s\n", confPath, confName, confType, envPrefix) |
||||||
|
|
||||||
|
viper.AddConfigPath(confPath) |
||||||
|
viper.SetConfigName(confName) |
||||||
|
viper.SetConfigType(confType) |
||||||
|
viper.SetEnvPrefix(envPrefix) |
||||||
|
viper.AutomaticEnv() |
||||||
|
viper.AllowEmptyEnv(true) |
||||||
|
|
||||||
|
conf := &Configuration{} |
||||||
|
|
||||||
|
if err := viper.ReadInConfig(); err != nil { |
||||||
|
panic(errors.New("viper read config fail: " + err.Error())) |
||||||
|
} |
||||||
|
if err := viper.Unmarshal(conf); err != nil { |
||||||
|
panic(errors.New("viper unmarshal config failed: " + err.Error())) |
||||||
|
} |
||||||
|
if appConf != nil && len(conf.App) > 0 { |
||||||
|
if err := viper.UnmarshalKey("app", appConf); err != nil { |
||||||
|
panic(errors.New("viper unmarshal app config failed: " + err.Error())) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return conf |
||||||
|
} |
||||||
|
|
||||||
|
func LoadIdlPath(idlPath string) (string, error) { |
||||||
|
idl, err := os.ReadFile(idlPath) |
||||||
|
if err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
return string(idl), nil |
||||||
|
} |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
package discovery |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"google.golang.org/grpc/resolver" |
||||||
|
) |
||||||
|
|
||||||
|
type Server struct { |
||||||
|
Name string `json:"name"` |
||||||
|
Addr string `json:"addr"` // 地址
|
||||||
|
Attrs map[string]string `json:"attrs"` // attributes
|
||||||
|
Ttl int64 `json:"-"` |
||||||
|
} |
||||||
|
|
||||||
|
func BuildPrefix(server Server) string { |
||||||
|
return fmt.Sprintf("/%s/", server.Name) |
||||||
|
} |
||||||
|
|
||||||
|
func BuildRegisterPath(server Server) string { |
||||||
|
return fmt.Sprintf("%s%s", BuildPrefix(server), server.Addr) |
||||||
|
} |
||||||
|
|
||||||
|
func ParseValue(value []byte) (Server, error) { |
||||||
|
server := Server{} |
||||||
|
if err := json.Unmarshal(value, &server); err != nil { |
||||||
|
return server, err |
||||||
|
} |
||||||
|
|
||||||
|
return server, nil |
||||||
|
} |
||||||
|
|
||||||
|
func SplitPath(path string) (Server, error) { |
||||||
|
server := Server{} |
||||||
|
strs := strings.Split(path, "/") |
||||||
|
if len(strs) == 0 { |
||||||
|
return server, errors.New("invalid path") |
||||||
|
} |
||||||
|
|
||||||
|
server.Addr = strs[len(strs)-1] |
||||||
|
|
||||||
|
return server, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Exist helper function
|
||||||
|
func Exist(l []resolver.Address, addr resolver.Address) bool { |
||||||
|
for i := range l { |
||||||
|
if l[i].Addr == addr.Addr { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Remove helper function
|
||||||
|
func Remove(s []resolver.Address, addr resolver.Address) ([]resolver.Address, bool) { |
||||||
|
for i := range s { |
||||||
|
if s[i].Addr == addr.Addr { |
||||||
|
s[i] = s[len(s)-1] |
||||||
|
return s[:len(s)-1], true |
||||||
|
} |
||||||
|
} |
||||||
|
return nil, false |
||||||
|
} |
||||||
|
|
||||||
|
func BuildResolverUrl(app string) string { |
||||||
|
return schema + ":///" + app |
||||||
|
} |
||||||
@ -0,0 +1,166 @@ |
|||||||
|
package discovery |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"encoding/json" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"google.golang.org/grpc/grpclog" |
||||||
|
"net" |
||||||
|
"sonet/pkg/utils/nets" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
|
||||||
|
clientv3 "go.etcd.io/etcd/client/v3" |
||||||
|
) |
||||||
|
|
||||||
|
var DefaultRegisterTTL int64 = 10 |
||||||
|
|
||||||
|
func RegisterAddress(listener net.Listener) (addr string, err error) { |
||||||
|
port := listener.Addr().(*net.TCPAddr).Port |
||||||
|
ipv4, err := nets.GetHostIpv4() |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
addr = fmt.Sprintf("%s:%d", ipv4, port) |
||||||
|
return |
||||||
|
} |
||||||
|
func MustGetRegisterAddr(listener net.Listener) (addr string) { |
||||||
|
port := listener.Addr().(*net.TCPAddr).Port |
||||||
|
ipv4, err := nets.GetHostIpv4() |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
addr = fmt.Sprintf("%s:%s", ipv4, port) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
type Register struct { |
||||||
|
DialTimeout int |
||||||
|
|
||||||
|
closeCh chan struct{} |
||||||
|
leasesID clientv3.LeaseID |
||||||
|
keepAliveCh <-chan *clientv3.LeaseKeepAliveResponse |
||||||
|
|
||||||
|
srvInfo Server |
||||||
|
srvTTL int64 |
||||||
|
cli *clientv3.Client |
||||||
|
} |
||||||
|
|
||||||
|
// NewRegister create a register based on etcd
|
||||||
|
func NewRegister(client *clientv3.Client) *Register { |
||||||
|
return &Register{ |
||||||
|
cli: client, |
||||||
|
DialTimeout: 3, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Register a user
|
||||||
|
func (r *Register) Register(srvInfo Server, ttl int64) (err error) { |
||||||
|
if strings.Split(srvInfo.Addr, ":")[0] == "" { |
||||||
|
return errors.New("invalid ip address") |
||||||
|
} |
||||||
|
|
||||||
|
r.srvInfo = srvInfo |
||||||
|
r.srvTTL = ttl |
||||||
|
|
||||||
|
if err = r.register(); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
if r.closeCh == nil { |
||||||
|
r.closeCh = make(chan struct{}) |
||||||
|
} |
||||||
|
|
||||||
|
go r.keepAlive() |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (r *Register) register() error { |
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(r.DialTimeout)*time.Second) |
||||||
|
defer cancel() |
||||||
|
|
||||||
|
leaseResp, err := r.cli.Grant(ctx, r.srvTTL) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
r.leasesID = leaseResp.ID |
||||||
|
|
||||||
|
if r.keepAliveCh, err = r.cli.KeepAlive(context.Background(), r.leasesID); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
data, err := json.Marshal(r.srvInfo) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
_, err = r.cli.Put(context.Background(), BuildRegisterPath(r.srvInfo), string(data), clientv3.WithLease(r.leasesID)) |
||||||
|
|
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// Stop stop register
|
||||||
|
func (r *Register) Stop() { |
||||||
|
if r.closeCh == nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r.closeCh <- struct{}{} |
||||||
|
<-r.closeCh // 阻塞到关闭
|
||||||
|
close(r.closeCh) |
||||||
|
} |
||||||
|
|
||||||
|
// unregister 删除节点
|
||||||
|
func (r *Register) unregister() error { |
||||||
|
_, err := r.cli.Delete(context.Background(), BuildRegisterPath(r.srvInfo)) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
func (r *Register) keepAlive() { |
||||||
|
ticker := time.NewTicker(time.Duration(r.srvTTL) * time.Second) |
||||||
|
defer ticker.Stop() |
||||||
|
|
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-r.closeCh: |
||||||
|
if err := r.unregister(); err != nil { |
||||||
|
grpclog.Error("unregister failed, error: ", err) |
||||||
|
} |
||||||
|
if _, err := r.cli.Revoke(context.Background(), r.leasesID); err != nil { |
||||||
|
grpclog.Error("revoke failed, error: ", err) |
||||||
|
} |
||||||
|
r.closeCh <- struct{}{} |
||||||
|
return |
||||||
|
case res := <-r.keepAliveCh: |
||||||
|
if res == nil { |
||||||
|
if err := r.register(); err != nil { |
||||||
|
grpclog.Error("register failed, error: ", err) |
||||||
|
} |
||||||
|
} |
||||||
|
case <-ticker.C: |
||||||
|
if r.keepAliveCh == nil { |
||||||
|
if err := r.register(); err != nil { |
||||||
|
grpclog.Error("register failed, error: ", err) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (r *Register) GetServerInfo() (Server, error) { |
||||||
|
resp, err := r.cli.Get(context.Background(), BuildRegisterPath(r.srvInfo)) |
||||||
|
if err != nil { |
||||||
|
return r.srvInfo, err |
||||||
|
} |
||||||
|
|
||||||
|
server := Server{} |
||||||
|
if resp.Count >= 1 { |
||||||
|
if err := json.Unmarshal(resp.Kvs[0].Value, &server); err != nil { |
||||||
|
return server, err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return server, err |
||||||
|
} |
||||||
@ -0,0 +1,168 @@ |
|||||||
|
package discovery |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/sirupsen/logrus" |
||||||
|
clientv3 "go.etcd.io/etcd/client/v3" |
||||||
|
"google.golang.org/grpc/resolver" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
schema = "etcd" |
||||||
|
) |
||||||
|
|
||||||
|
// Resolver for grpc client
|
||||||
|
type Resolver struct { |
||||||
|
schema string |
||||||
|
EtcdAddrs []string |
||||||
|
DialTimeout int |
||||||
|
|
||||||
|
closeCh chan struct{} |
||||||
|
watchCh clientv3.WatchChan |
||||||
|
cli *clientv3.Client |
||||||
|
keyPrifix string |
||||||
|
srvAddrsList []resolver.Address |
||||||
|
|
||||||
|
cc resolver.ClientConn |
||||||
|
logger *logrus.Logger |
||||||
|
} |
||||||
|
|
||||||
|
// NewResolver create a new resolver.Builder base on etcd
|
||||||
|
func NewResolver(etcdAddrs []string, logger *logrus.Logger) *Resolver { |
||||||
|
return &Resolver{ |
||||||
|
schema: schema, |
||||||
|
EtcdAddrs: etcdAddrs, |
||||||
|
DialTimeout: 3, |
||||||
|
logger: logger, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Scheme returns the scheme supported by this resolver.
|
||||||
|
func (r *Resolver) Scheme() string { |
||||||
|
return r.schema |
||||||
|
} |
||||||
|
|
||||||
|
// Build creates a new resolver.Resolver for the given target
|
||||||
|
func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (rr resolver.Resolver, err error) { |
||||||
|
r.cc = cc |
||||||
|
r.keyPrifix = BuildPrefix(Server{Name: target.Endpoint()}) |
||||||
|
if _, err := r.start(); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return r, nil |
||||||
|
} |
||||||
|
|
||||||
|
// ResolveNow resolver.Resolver interface
|
||||||
|
func (r *Resolver) ResolveNow(o resolver.ResolveNowOptions) {} |
||||||
|
|
||||||
|
// Close resolver.Resolver interface
|
||||||
|
func (r *Resolver) Close() { |
||||||
|
r.closeCh <- struct{}{} |
||||||
|
} |
||||||
|
|
||||||
|
// start
|
||||||
|
func (r *Resolver) start() (chan<- struct{}, error) { |
||||||
|
var err error |
||||||
|
r.cli, err = clientv3.New(clientv3.Config{ |
||||||
|
Endpoints: r.EtcdAddrs, |
||||||
|
Username: "root", |
||||||
|
Password: "sopod@etcd", |
||||||
|
DialTimeout: time.Duration(r.DialTimeout) * time.Second, |
||||||
|
}) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
resolver.Register(r) |
||||||
|
|
||||||
|
r.closeCh = make(chan struct{}) |
||||||
|
|
||||||
|
if err = r.sync(); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
go r.watch() |
||||||
|
|
||||||
|
return r.closeCh, nil |
||||||
|
} |
||||||
|
|
||||||
|
// watch update events
|
||||||
|
func (r *Resolver) watch() { |
||||||
|
ticker := time.NewTicker(time.Minute) |
||||||
|
r.watchCh = r.cli.Watch(context.Background(), r.keyPrifix, clientv3.WithPrefix()) |
||||||
|
|
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-r.closeCh: |
||||||
|
return |
||||||
|
case res, ok := <-r.watchCh: |
||||||
|
if ok { |
||||||
|
r.update(res.Events) |
||||||
|
} |
||||||
|
case <-ticker.C: |
||||||
|
if err := r.sync(); err != nil { |
||||||
|
r.logger.Error("sync failed", err) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// update
|
||||||
|
func (r *Resolver) update(events []*clientv3.Event) { |
||||||
|
for _, ev := range events { |
||||||
|
var info Server |
||||||
|
var err error |
||||||
|
|
||||||
|
switch ev.Type { |
||||||
|
case clientv3.EventTypePut: |
||||||
|
info, err = ParseValue(ev.Kv.Value) |
||||||
|
if err != nil { |
||||||
|
continue |
||||||
|
} |
||||||
|
addr := resolver.Address{Addr: info.Addr} |
||||||
|
for k, v := range info.Attrs { |
||||||
|
addr.Attributes = addr.Attributes.WithValue(k, v) |
||||||
|
} |
||||||
|
if !Exist(r.srvAddrsList, addr) { |
||||||
|
r.srvAddrsList = append(r.srvAddrsList, addr) |
||||||
|
r.cc.UpdateState(resolver.State{Addresses: r.srvAddrsList}) |
||||||
|
} |
||||||
|
case clientv3.EventTypeDelete: |
||||||
|
info, err = SplitPath(string(ev.Kv.Key)) |
||||||
|
if err != nil { |
||||||
|
continue |
||||||
|
} |
||||||
|
addr := resolver.Address{Addr: info.Addr} |
||||||
|
if s, ok := Remove(r.srvAddrsList, addr); ok { |
||||||
|
r.srvAddrsList = s |
||||||
|
r.cc.UpdateState(resolver.State{Addresses: r.srvAddrsList}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// sync 同步获取所有地址信息
|
||||||
|
func (r *Resolver) sync() (err error) { |
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) |
||||||
|
defer cancel() |
||||||
|
res, err := r.cli.Get(ctx, r.keyPrifix, clientv3.WithPrefix()) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r.srvAddrsList = []resolver.Address{} |
||||||
|
|
||||||
|
for _, v := range res.Kvs { |
||||||
|
info, err := ParseValue(v.Value) |
||||||
|
if err != nil { |
||||||
|
continue |
||||||
|
} |
||||||
|
addr := resolver.Address{Addr: info.Addr} |
||||||
|
for k, v := range info.Attrs { |
||||||
|
addr.Attributes = addr.Attributes.WithValue(k, v) |
||||||
|
} |
||||||
|
r.srvAddrsList = append(r.srvAddrsList, addr) |
||||||
|
} |
||||||
|
err = r.cc.UpdateState(resolver.State{Addresses: r.srvAddrsList}) |
||||||
|
return |
||||||
|
} |
||||||
@ -0,0 +1,289 @@ |
|||||||
|
package desc_source |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"io/ioutil" |
||||||
|
"sync" |
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto" |
||||||
|
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||||
|
"github.com/jhump/protoreflect/desc" |
||||||
|
"github.com/jhump/protoreflect/desc/protoparse" |
||||||
|
"github.com/jhump/protoreflect/dynamic" |
||||||
|
"github.com/jhump/protoreflect/grpcreflect" |
||||||
|
"google.golang.org/grpc/codes" |
||||||
|
"google.golang.org/grpc/status" |
||||||
|
) |
||||||
|
|
||||||
|
// ErrReflectionNotSupported is returned by DescriptorSource operations that
|
||||||
|
// rely on interacting with the reflection service when the source does not
|
||||||
|
// actually expose the reflection service. When this occurs, an alternate source
|
||||||
|
// (like file descriptor sets) must be used.
|
||||||
|
var ErrReflectionNotSupported = errors.New("server does not support the reflection API") |
||||||
|
|
||||||
|
// DescriptorSource is a source of protobuf descriptor information. It can be backed by a FileDescriptorSet
|
||||||
|
// proto (like a file generated by protoc) or a remote server that supports the reflection API.
|
||||||
|
type DescriptorSource interface { |
||||||
|
// ListServices returns a list of fully-qualified service names. It will be all services in a set of
|
||||||
|
// descriptor files or the set of all services exposed by a gRPC server.
|
||||||
|
ListServices() ([]string, error) |
||||||
|
// FindSymbol returns a descriptor for the given fully-qualified symbol name.
|
||||||
|
FindSymbol(fullyQualifiedName string) (desc.Descriptor, error) |
||||||
|
// AllExtensionsForType returns all known extension fields that extend the given message type name.
|
||||||
|
AllExtensionsForType(typeName string) ([]*desc.FieldDescriptor, error) |
||||||
|
} |
||||||
|
|
||||||
|
// DescriptorSourceFromProtoSets creates a DescriptorSource that is backed by the named files, whose contents
|
||||||
|
// are encoded FileDescriptorSet protos.
|
||||||
|
func DescriptorSourceFromProtoSets(fileNames ...string) (DescriptorSource, error) { |
||||||
|
files := &descpb.FileDescriptorSet{} |
||||||
|
for _, fileName := range fileNames { |
||||||
|
b, err := ioutil.ReadFile(fileName) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("could not load protoset file %q: %v", fileName, err) |
||||||
|
} |
||||||
|
|
||||||
|
var fs descpb.FileDescriptorSet |
||||||
|
err = proto.Unmarshal(b, &fs) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("could not parse contents of protoset file %q: %v", fileName, err) |
||||||
|
} |
||||||
|
|
||||||
|
files.File = append(files.File, fs.File...) |
||||||
|
} |
||||||
|
return DescriptorSourceFromFileDescriptorSet(files) |
||||||
|
} |
||||||
|
|
||||||
|
// DescriptorSourceFromProtoFiles creates a DescriptorSource that is backed by the named files,
|
||||||
|
// whose contents are Protocol Buffer source files. The given importPaths are used to locate
|
||||||
|
// any imported files.
|
||||||
|
func DescriptorSourceFromProtoFiles(importPaths []string, fileNames ...string) (DescriptorSource, error) { |
||||||
|
p := protoparse.Parser{ |
||||||
|
ImportPaths: importPaths, |
||||||
|
InferImportPaths: len(importPaths) == 0, |
||||||
|
} |
||||||
|
fds, err := p.ParseFiles(fileNames...) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("could not parse given files: %v", err) |
||||||
|
} |
||||||
|
|
||||||
|
return DescriptorSourceFromFileDescriptors(fds...) |
||||||
|
} |
||||||
|
|
||||||
|
// DescriptorSourceFromFileDescriptorSet creates a DescriptorSource that is backed by the FileDescriptorSet.
|
||||||
|
func DescriptorSourceFromFileDescriptorSet(files *descpb.FileDescriptorSet) (DescriptorSource, error) { |
||||||
|
unresolved := map[string]*descpb.FileDescriptorProto{} |
||||||
|
for _, fd := range files.File { |
||||||
|
unresolved[fd.GetName()] = fd |
||||||
|
} |
||||||
|
|
||||||
|
resolved := map[string]*desc.FileDescriptor{} |
||||||
|
for _, fd := range files.File { |
||||||
|
_, err := resolveFileDescriptor(unresolved, resolved, fd.GetName()) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return &fileSource{files: resolved}, nil |
||||||
|
} |
||||||
|
|
||||||
|
func resolveFileDescriptor(unresolved map[string]*descpb.FileDescriptorProto, resolved map[string]*desc.FileDescriptor, filename string) (*desc.FileDescriptor, error) { |
||||||
|
if r, ok := resolved[filename]; ok { |
||||||
|
return r, nil |
||||||
|
} |
||||||
|
|
||||||
|
fd, ok := unresolved[filename] |
||||||
|
if !ok { |
||||||
|
return nil, fmt.Errorf("no descriptor found for %q", filename) |
||||||
|
} |
||||||
|
|
||||||
|
deps := make([]*desc.FileDescriptor, 0, len(fd.GetDependency())) |
||||||
|
for _, dep := range fd.GetDependency() { |
||||||
|
depFd, err := resolveFileDescriptor(unresolved, resolved, dep) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
deps = append(deps, depFd) |
||||||
|
} |
||||||
|
|
||||||
|
result, err := desc.CreateFileDescriptor(fd, deps...) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
resolved[filename] = result |
||||||
|
return result, nil |
||||||
|
} |
||||||
|
|
||||||
|
// DescriptorSourceFromFileDescriptors creates a DescriptorSource that is backed by the given
|
||||||
|
// file descriptors
|
||||||
|
func DescriptorSourceFromFileDescriptors(files ...*desc.FileDescriptor) (DescriptorSource, error) { |
||||||
|
fds := map[string]*desc.FileDescriptor{} |
||||||
|
for _, fd := range files { |
||||||
|
if err := addFile(fd, fds); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return &fileSource{files: fds}, nil |
||||||
|
} |
||||||
|
|
||||||
|
func addFile(fd *desc.FileDescriptor, fds map[string]*desc.FileDescriptor) error { |
||||||
|
name := fd.GetName() |
||||||
|
if existing, ok := fds[name]; ok { |
||||||
|
// already added this file
|
||||||
|
if existing != fd { |
||||||
|
// doh! duplicate files provided
|
||||||
|
return fmt.Errorf("given files include multiple copies of %q", name) |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
fds[name] = fd |
||||||
|
for _, dep := range fd.GetDependencies() { |
||||||
|
if err := addFile(dep, fds); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
type fileSource struct { |
||||||
|
files map[string]*desc.FileDescriptor |
||||||
|
er *dynamic.ExtensionRegistry |
||||||
|
erInit sync.Once |
||||||
|
} |
||||||
|
|
||||||
|
func (fs *fileSource) ListServices() ([]string, error) { |
||||||
|
set := map[string]bool{} |
||||||
|
for _, fd := range fs.files { |
||||||
|
for _, svc := range fd.GetServices() { |
||||||
|
set[svc.GetFullyQualifiedName()] = true |
||||||
|
} |
||||||
|
} |
||||||
|
sl := make([]string, 0, len(set)) |
||||||
|
for svc := range set { |
||||||
|
sl = append(sl, svc) |
||||||
|
} |
||||||
|
|
||||||
|
return sl, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (fs *fileSource) ListMethods() (map[string][]string, error) { |
||||||
|
set := map[string][]string{} |
||||||
|
for _, fd := range fs.files { |
||||||
|
for _, svc := range fd.GetServices() { |
||||||
|
m, ok := set[svc.GetFullyQualifiedName()] |
||||||
|
if !ok { |
||||||
|
m = []string{} |
||||||
|
} |
||||||
|
for _, v := range svc.GetMethods() { |
||||||
|
m = append(m, v.GetName()) |
||||||
|
// m = append(.GetFullyQualifiedName()], v.GetName())
|
||||||
|
} |
||||||
|
|
||||||
|
set[svc.GetFullyQualifiedName()] = m |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return set, nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetAllFiles returns all of the underlying file descriptors. This is
|
||||||
|
// more thorough and more efficient than the fallback strategy used by
|
||||||
|
// the GetAllFiles package method, for enumerating all files from a
|
||||||
|
// descriptor source.
|
||||||
|
func (fs *fileSource) GetAllFiles() ([]*desc.FileDescriptor, error) { |
||||||
|
files := make([]*desc.FileDescriptor, len(fs.files)) |
||||||
|
i := 0 |
||||||
|
for _, fd := range fs.files { |
||||||
|
files[i] = fd |
||||||
|
i++ |
||||||
|
} |
||||||
|
|
||||||
|
return files, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (fs *fileSource) FindSymbol(fullyQualifiedName string) (desc.Descriptor, error) { |
||||||
|
for _, fd := range fs.files { |
||||||
|
if dsc := fd.FindSymbol(fullyQualifiedName); dsc != nil { |
||||||
|
return dsc, nil |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil, notFound("Symbol", fullyQualifiedName) |
||||||
|
} |
||||||
|
|
||||||
|
func (fs *fileSource) AllExtensionsForType(typeName string) ([]*desc.FieldDescriptor, error) { |
||||||
|
fs.erInit.Do(func() { |
||||||
|
fs.er = &dynamic.ExtensionRegistry{} |
||||||
|
for _, fd := range fs.files { |
||||||
|
fs.er.AddExtensionsFromFile(fd) |
||||||
|
} |
||||||
|
}) |
||||||
|
return fs.er.AllExtensionsForType(typeName), nil |
||||||
|
} |
||||||
|
|
||||||
|
// DescriptorSourceFromServer creates a DescriptorSource that uses the given gRPC reflection client
|
||||||
|
// to interrogate a server for descriptor information. If the server does not support the reflection
|
||||||
|
// API then the various DescriptorSource methods will return ErrReflectionNotSupported
|
||||||
|
func DescriptorSourceFromServer(_ context.Context, refClient *grpcreflect.Client) DescriptorSource { |
||||||
|
return serverSource{client: refClient} |
||||||
|
} |
||||||
|
|
||||||
|
type serverSource struct { |
||||||
|
client *grpcreflect.Client |
||||||
|
} |
||||||
|
|
||||||
|
func (ss serverSource) ListServices() ([]string, error) { |
||||||
|
svcs, err := ss.client.ListServices() |
||||||
|
return svcs, reflectionSupport(err) |
||||||
|
} |
||||||
|
|
||||||
|
func (ss serverSource) FindSymbol(fullyQualifiedName string) (desc.Descriptor, error) { |
||||||
|
file, err := ss.client.FileContainingSymbol(fullyQualifiedName) |
||||||
|
if err != nil { |
||||||
|
return nil, reflectionSupport(err) |
||||||
|
} |
||||||
|
|
||||||
|
d := file.FindSymbol(fullyQualifiedName) |
||||||
|
if d == nil { |
||||||
|
return nil, notFound("Symbol", fullyQualifiedName) |
||||||
|
} |
||||||
|
|
||||||
|
return d, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (ss serverSource) AllExtensionsForType(typeName string) ([]*desc.FieldDescriptor, error) { |
||||||
|
var exts []*desc.FieldDescriptor |
||||||
|
nums, err := ss.client.AllExtensionNumbersForType(typeName) |
||||||
|
if err != nil { |
||||||
|
return nil, reflectionSupport(err) |
||||||
|
} |
||||||
|
|
||||||
|
for _, fieldNum := range nums { |
||||||
|
ext, err := ss.client.ResolveExtension(typeName, fieldNum) |
||||||
|
if err != nil { |
||||||
|
return nil, reflectionSupport(err) |
||||||
|
} |
||||||
|
exts = append(exts, ext) |
||||||
|
} |
||||||
|
|
||||||
|
return exts, nil |
||||||
|
} |
||||||
|
|
||||||
|
func reflectionSupport(err error) error { |
||||||
|
if err == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
if stat, ok := status.FromError(err); ok && stat.Code() == codes.Unimplemented { |
||||||
|
return ErrReflectionNotSupported |
||||||
|
} |
||||||
|
|
||||||
|
return err |
||||||
|
} |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
package desc_source |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/jhump/protoreflect/grpcreflect" |
||||||
|
) |
||||||
|
|
||||||
|
type notFoundError string |
||||||
|
|
||||||
|
func notFound(kind, name string) error { |
||||||
|
return notFoundError(fmt.Sprintf("%s not found: %s", kind, name)) |
||||||
|
} |
||||||
|
|
||||||
|
func (e notFoundError) Error() string { |
||||||
|
return string(e) |
||||||
|
} |
||||||
|
|
||||||
|
func IsNotFoundError(err error) bool { |
||||||
|
if grpcreflect.IsElementNotFoundError(err) { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
_, ok := err.(notFoundError) |
||||||
|
return ok |
||||||
|
} |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
package protocol |
||||||
|
|
||||||
|
// protocol
|
||||||
|
// 1byte: magic: 99
|
||||||
|
// 1byte: 1 request, 2 response, 3 event, 4 error
|
||||||
|
// 1byte: status: 20-OK, 30-CLIENT_TIMEOUT, 31-SERVER_TIMEOUT, 40-BAD_REQUEST, 41-BAD_RESPONSE, 44-SERVICE_NOT_FOUND, 50-CLIENT_ERROR, 51-SERVER_ERROR, 52-SERVICE_ERROR
|
||||||
|
// 4bit: svc,method url desc: 1 name, 2 number
|
||||||
|
// 4bit: serialize: 1proto, 2json
|
||||||
|
// 4byte: seqId
|
||||||
|
// string: service, method / 4byte svc, 4byte method/4byte notice
|
||||||
|
// proto bytes / json bytes
|
||||||
|
|
||||||
|
const ( |
||||||
|
Magic int8 = 99 |
||||||
|
|
||||||
|
TypeRequest int8 = 1 |
||||||
|
TypeResponse int8 = 2 |
||||||
|
TypeNotice int8 = 3 |
||||||
|
TypeError int8 = 4 |
||||||
|
) |
||||||
|
|
||||||
|
type Header struct { |
||||||
|
Magic int8 |
||||||
|
Type int8 // 1 request, 2 response, 3 event, 4 error
|
||||||
|
Status int8 |
||||||
|
UrlType int8 |
||||||
|
SerializeType int8 |
||||||
|
SeqId int32 |
||||||
|
SvcNo int32 |
||||||
|
MethodNo int32 |
||||||
|
Svc string |
||||||
|
Method string |
||||||
|
} |
||||||
|
|
||||||
|
type Payload struct { |
||||||
|
Header Header |
||||||
|
Body []byte |
||||||
|
} |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
package conver |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/dsnet/golib/unitconv" |
||||||
|
) |
||||||
|
|
||||||
|
// ParseDataUnit parse 1Ki -> 1024, 1K -> 1000
|
||||||
|
func ParseDataUnit(unit string) (val float64, err error) { |
||||||
|
val, err = unitconv.ParsePrefix(unit, unitconv.AutoParse) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func ParseDataUnitInt(unit string) (val int, err error) { |
||||||
|
v, err := ParseDataUnit(unit) |
||||||
|
val = int(v) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func MustParseDataUnit(unit string) (val float64) { |
||||||
|
val, err := unitconv.ParsePrefix(unit, unitconv.AutoParse) |
||||||
|
if err != nil { |
||||||
|
panic(fmt.Errorf("error parse data unit %s, %s", unit, err.Error())) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func MustParseDataUnitInt(unit string) (val int) { |
||||||
|
return int(MustParseDataUnit(unit)) |
||||||
|
} |
||||||
@ -0,0 +1,49 @@ |
|||||||
|
package logger |
||||||
|
|
||||||
|
func Info(args ...any) { |
||||||
|
Logger.Info(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Infoln(args ...any) { |
||||||
|
Logger.Infoln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Infof(format string, args ...any) { |
||||||
|
Logger.Infof(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Warning(args ...any) { |
||||||
|
Logger.Warning(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Warningln(args ...any) { |
||||||
|
Logger.Warningln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Warningf(format string, args ...any) { |
||||||
|
Logger.Warningf(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Error(args ...any) { |
||||||
|
Logger.Error(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Errorln(args ...any) { |
||||||
|
Logger.Errorln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Errorf(format string, args ...any) { |
||||||
|
Logger.Errorf(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Fatal(args ...any) { |
||||||
|
Logger.Fatal(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Fatalln(args ...any) { |
||||||
|
Logger.Fatalln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func Fatalf(format string, args ...any) { |
||||||
|
Logger.Fatalf(format, args...) |
||||||
|
} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
package logger |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/sirupsen/logrus" |
||||||
|
) |
||||||
|
|
||||||
|
var Logger *SoLogger |
||||||
|
|
||||||
|
func init() { |
||||||
|
Logger = &SoLogger{logger: logrus.New()} |
||||||
|
} |
||||||
|
|
||||||
|
type SoLogger struct { |
||||||
|
logger *logrus.Logger |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Info(args ...any) { |
||||||
|
l.logger.Info(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Infoln(args ...any) { |
||||||
|
l.logger.Infoln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Infof(format string, args ...any) { |
||||||
|
l.logger.Infof(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Warning(args ...any) { |
||||||
|
l.logger.Warning(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Warningln(args ...any) { |
||||||
|
l.logger.Warningln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Warningf(format string, args ...any) { |
||||||
|
l.logger.Warningf(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Error(args ...any) { |
||||||
|
l.logger.Error(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Errorln(args ...any) { |
||||||
|
l.logger.Errorln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Errorf(format string, args ...any) { |
||||||
|
l.logger.Errorf(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Fatal(args ...any) { |
||||||
|
l.logger.Fatal(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Fatalln(args ...any) { |
||||||
|
l.logger.Fatalln(args...) |
||||||
|
} |
||||||
|
|
||||||
|
func (l *SoLogger) Fatalf(format string, args ...any) { |
||||||
|
l.logger.Fatalf(format, args...) |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
logrusLevels = []logrus.Level{logrus.TraceLevel, logrus.DebugLevel, logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel} |
||||||
|
logrusLevelsLen = len(logrusLevels) |
||||||
|
) |
||||||
|
|
||||||
|
// V enable level
|
||||||
|
// grpclog:info=2,warn=3...
|
||||||
|
// logrus: warn=3,info=4...
|
||||||
|
func (l *SoLogger) V(level int) bool { |
||||||
|
if level >= logrusLevelsLen { |
||||||
|
return true |
||||||
|
} |
||||||
|
return logrusLevels[level] <= l.logger.Level |
||||||
|
} |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
package nets |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"net" |
||||||
|
) |
||||||
|
|
||||||
|
// GetHostIpv4 获取本地内网IP
|
||||||
|
func GetHostIpv4() (string, error) { |
||||||
|
privates, err := getAllIPV4(func(ip net.IP) bool { |
||||||
|
return ip.IsPrivate() |
||||||
|
}) |
||||||
|
if err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
if len(privates) == 0 { |
||||||
|
return "", errors.New("no private ip") |
||||||
|
} |
||||||
|
return privates[0], nil |
||||||
|
} |
||||||
|
|
||||||
|
func getAllIPV4(filter func(net.IP) bool) (ips []string, err error) { |
||||||
|
// 获取所有网卡
|
||||||
|
addrs, err := net.InterfaceAddrs() |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for _, addr := range addrs { |
||||||
|
// 这个网络地址是IP地址: ipv4, ipv6
|
||||||
|
ipNet, isIpNet := addr.(*net.IPNet) |
||||||
|
if isIpNet && !ipNet.IP.IsLoopback() { |
||||||
|
// 跳过IPV6
|
||||||
|
if ipNet.IP.To4() != nil { |
||||||
|
if filter(ipNet.IP) { |
||||||
|
ips = append(ips, ipNet.IP.String()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
package shutdown |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
"os" |
||||||
|
"os/signal" |
||||||
|
"sync" |
||||||
|
"sync/atomic" |
||||||
|
"syscall" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
shutdownHooks []func() |
||||||
|
lock = &sync.Mutex{} |
||||||
|
sigChan = make(chan os.Signal, 1) |
||||||
|
) |
||||||
|
|
||||||
|
func AddShutdownHook(hook func()) { |
||||||
|
lock.Lock() |
||||||
|
defer lock.Unlock() |
||||||
|
shutdownHooks = append(shutdownHooks, hook) |
||||||
|
} |
||||||
|
|
||||||
|
func Await() { |
||||||
|
// 监听两个信号: TERM信号(kill + 进程号)触发, 中断信号(ctrl + c)触发
|
||||||
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) |
||||||
|
s := <-sigChan |
||||||
|
// 监听到关闭信号
|
||||||
|
log.Println("catch exit signal: ", s) |
||||||
|
|
||||||
|
var success, fail int32 |
||||||
|
for _, hook := range shutdownHooks { |
||||||
|
func() { |
||||||
|
defer func() { |
||||||
|
if err := recover(); err != nil { |
||||||
|
log.Println("exec shutdown hook panic: ", err) |
||||||
|
atomic.AddInt32(&fail, 1) |
||||||
|
return |
||||||
|
} |
||||||
|
atomic.AddInt32(&success, 1) |
||||||
|
}() |
||||||
|
|
||||||
|
hook() |
||||||
|
}() |
||||||
|
} |
||||||
|
|
||||||
|
log.Printf("execute shutdown hook %d success, %d failed\n", success, fail) |
||||||
|
} |
||||||
|
|
||||||
|
//func Shutdown() {
|
||||||
|
// sigChan <- syscall.SIGQUIT
|
||||||
|
//}
|
||||||
Loading…
Reference in new issue