diff --git a/.gitignore b/.gitignore index a67962d..3f08705 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ Thumbs.db /tmp /api/gen +/api/genjs .back_groups/ diff --git a/api/auth.proto b/api/auth.proto index 71a5da6..ddff556 100644 --- a/api/auth.proto +++ b/api/auth.proto @@ -5,7 +5,7 @@ syntax = "proto3"; option go_package = "./auth"; -service AuthService { +service Auth { // account password login rpc Login(ReqLogin) returns(ResLogin); diff --git a/api/chat.proto b/api/chat.proto index ae68ac4..dea8929 100644 --- a/api/chat.proto +++ b/api/chat.proto @@ -1,42 +1,44 @@ syntax = "proto3"; import "google/protobuf/empty.proto"; +//import "postal.proto"; option go_package = "./chat"; -service AuthService { - rpc Send(ReqSendChat) returns (ResSendChat); +service Chat { + rpc Send(ReqSend) returns (ResSend); - rpc GroupSend(ReqSendGroupChat) returns (ResSendChat); + rpc RoomSend(ReqRoomSend) returns (ResSend); - rpc GroupCreate(ReqGroupCreate) returns (ResGroupCreate); + rpc RoomCreate(ReqRoomCreate) returns (ResRoomCreate); - rpc GroupJoin(ReqGroupJoin) returns (google.protobuf.Empty); + rpc RoomJoin(ReqRoomJoin) returns (google.protobuf.Empty); - rpc GroupLeave(ReqGroupLeave) returns (google.protobuf.Empty); + rpc RoomLeave(ReqRoomLeave) returns (google.protobuf.Empty); - rpc GroupKickOut(ReqGroupKickOut) returns (google.protobuf.Empty); + rpc RoomKickOut(ReqRoomKickOut) returns (google.protobuf.Empty); - rpc GroupInfo(ReqGroupInfo) returns (ResGroupInfo); + rpc RoomInfo(ReqRoomInfo) returns (ResRoomInfo); - rpc GroupList(ReqGroupList) returns (ResGroupList); + rpc RoomList(ReqRoomList) returns (ResRoomList); } message ChatMessage { string sender = 1; string content = 7; +// Message message = 8; } -message ReqSendChat { +message ReqSend { string receiver = 2; string content = 3; // 消息格式化器 [img:img_id][file:file_id]text... } -message ReqSendGroupChat { +message ReqRoomSend { string gid = 1; string message = 2; } -message ResSendChat { +message ResSend { int32 status = 1; // 1已发送,2已接收 string result = 2; } @@ -51,38 +53,38 @@ message Group { int64 createAt = 7; } -message ReqGroupCreate { +message ReqRoomCreate { string gname = 2; } -message ResGroupCreate { +message ResRoomCreate { Group group = 1; } -message ReqGroupJoin { +message ReqRoomJoin { string gid = 1; } -message ReqGroupLeave { +message ReqRoomLeave { string gid = 1; } -message ReqGroupKickOut { +message ReqRoomKickOut { string gid = 1; string uid = 2; } -message ReqGroupInfo { +message ReqRoomInfo { string gid = 1; } -message ResGroupInfo { +message ResRoomInfo { Group group = 1; } -message ReqGroupList { +message ReqRoomList { } -message ResGroupList { +message ResRoomList { repeated Group groups = 1; } diff --git a/api/mahjong.proto b/api/mahjong.proto index b40e0ff..16705ad 100644 --- a/api/mahjong.proto +++ b/api/mahjong.proto @@ -3,7 +3,7 @@ syntax = "proto3"; import "google/protobuf/empty.proto"; option go_package = "./mahjong"; -service MahjongService { +service Mahjong { rpc PlayerOnline(google.protobuf.Empty) returns(ResPlayerOnline); // 登录后初始化玩家信 diff --git a/api/postal.proto b/api/postal.proto index 1d42bca..d6c410e 100644 --- a/api/postal.proto +++ b/api/postal.proto @@ -18,7 +18,9 @@ message Message { int64 time = 3; int32 svcNo = 4; int32 msgNo = 5; - bytes body = 6; // protobuf bytes + string svc = 13; + string msg = 14; + bytes body = 15; // protobuf bytes } message ReqDeliver { diff --git a/cmd/auth/main.go b/cmd/auth/main.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/cmd/auth/main.go @@ -0,0 +1 @@ +package main diff --git a/cmd/gateway_ws/config.toml b/cmd/gateway_ws/config.toml new file mode 100644 index 0000000..9d5075d --- /dev/null +++ b/cmd/gateway_ws/config.toml @@ -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 diff --git a/cmd/gateway_ws/main.go b/cmd/gateway_ws/main.go index 81a2b9e..4af2e58 100644 --- a/cmd/gateway_ws/main.go +++ b/cmd/gateway_ws/main.go @@ -1,6 +1,36 @@ 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 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() } diff --git a/generate.go b/generate.go index ff20944..ce37340 100644 --- a/generate.go +++ b/generate.go @@ -1,3 +1,7 @@ package sonet //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 diff --git a/go.mod b/go.mod index 176c323..b2454bd 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,59 @@ module sonet go 1.19 require ( + github.com/golang/protobuf v1.5.3 + github.com/jhump/protoreflect v1.15.4 + github.com/nats-io/nats.go v1.31.0 + github.com/redis/go-redis/v9 v9.4.0 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/viper v1.18.2 + go.etcd.io/etcd/client/v3 v3.5.11 google.golang.org/grpc v1.60.1 google.golang.org/protobuf v1.32.0 + gorm.io/driver/mysql v1.5.2 + gorm.io/gorm v1.25.5 ) require ( - github.com/golang/protobuf v1.5.3 // indirect - golang.org/x/net v0.16.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect + github.com/bufbuild/protocompile v0.7.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dsnet/golib/unitconv v1.0.2 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/klauspost/compress v1.17.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/nats-io/nkeys v0.4.6 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.11 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.11 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 41235cf..693378c 100644 --- a/go.sum +++ b/go.sum @@ -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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jhump/protoreflect v1.15.4 h1:mrwJhfQGGljwvR/jPEocli8KA6G9afbQpH8NY2wORcI= +github.com/jhump/protoreflect v1.15.4/go.mod h1:2B+zwrnMY3TTIqEK01OG/d3pyUycQBfDf+bx8fE2DNg= +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/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= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/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/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= 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= diff --git a/internal/auth/logic/auth_server.go b/internal/auth/logic/auth_server.go new file mode 100644 index 0000000..205ec15 --- /dev/null +++ b/internal/auth/logic/auth_server.go @@ -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 +} diff --git a/internal/chat/logic/chat_server.go b/internal/chat/logic/chat_server.go new file mode 100644 index 0000000..fd85711 --- /dev/null +++ b/internal/chat/logic/chat_server.go @@ -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 +} diff --git a/internal/mahjong/logic/mahjong_server.go b/internal/mahjong/logic/mahjong_server.go new file mode 100644 index 0000000..b624494 --- /dev/null +++ b/internal/mahjong/logic/mahjong_server.go @@ -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 +} diff --git a/internal/postal/logic/postal_server.go b/internal/postal/logic/postal_server.go index 5152db0..697147d 100644 --- a/internal/postal/logic/postal_server.go +++ b/internal/postal/logic/postal_server.go @@ -2,8 +2,14 @@ package logic import ( "context" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" "google.golang.org/protobuf/types/known/emptypb" + "net" "sonet/api/gen/postal" + "sonet/pkg/config" + "sonet/pkg/grpc/discovery" + "sonet/pkg/utils/logger" ) type PostalServer struct { @@ -14,6 +20,44 @@ func NewPostalServer() *PostalServer { return &PostalServer{} } +func (p *PostalServer) Run(conf config.GrpcConfig, postalRegister *discovery.Register) (err error) { + server := grpc.NewServer( + config.GetGrpcOptions(conf)..., + ) + if !conf.NoReflection { + // 注册反射服务 + reflection.Register(server) + } + postal.RegisterPostalServer(server, p) + listen, err := net.Listen("tcp", conf.Address) + if err != nil { + return + } + + // registry discovery + regConf := conf.Register + if regConf.Name == "" { + regConf.Name = postal.Postal_ServiceDesc.ServiceName + } + if regConf.Addr == "" { + regConf.Addr, err = discovery.RegisterAddress(listen) + if err != nil { + return + } + } + if regConf.Ttl == 0 { + regConf.Ttl = discovery.DefaultRegisterTTL + } + if err = postalRegister.Register(regConf, regConf.Ttl); err != nil { + return + } + + // run serve + logger.Infof("%s server running %s\n", regConf.Name, listen.Addr().String()) + err = server.Serve(listen) + return +} + func (p *PostalServer) Deliver(ctx context.Context, deliver *postal.ReqDeliver) (*postal.ResDeliver, error) { return nil, nil } diff --git a/internal/postal/ws/ws_server.go b/internal/postal/ws/ws_server.go new file mode 100644 index 0000000..c76027c --- /dev/null +++ b/internal/postal/ws/ws_server.go @@ -0,0 +1,4 @@ +package ws + +type WebsocketServer struct { +} diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..f52bfba --- /dev/null +++ b/pkg/config/config.go @@ -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 +} diff --git a/pkg/config/gorm.go b/pkg/config/gorm.go new file mode 100644 index 0000000..331dd58 --- /dev/null +++ b/pkg/config/gorm.go @@ -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 +} diff --git a/pkg/config/grpc_options.go b/pkg/config/grpc_options.go new file mode 100644 index 0000000..bdfb606 --- /dev/null +++ b/pkg/config/grpc_options.go @@ -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 +} diff --git a/pkg/config/loader.go b/pkg/config/loader.go new file mode 100644 index 0000000..5bf8eba --- /dev/null +++ b/pkg/config/loader.go @@ -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 +} diff --git a/pkg/deliver/deliver.go b/pkg/deliver/deliver.go new file mode 100644 index 0000000..9eae15d --- /dev/null +++ b/pkg/deliver/deliver.go @@ -0,0 +1 @@ +package deliver diff --git a/pkg/grpc/discovery/instance.go b/pkg/grpc/discovery/instance.go new file mode 100644 index 0000000..8d0c93b --- /dev/null +++ b/pkg/grpc/discovery/instance.go @@ -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 +} diff --git a/pkg/grpc/discovery/register.go b/pkg/grpc/discovery/register.go new file mode 100644 index 0000000..1402dd4 --- /dev/null +++ b/pkg/grpc/discovery/register.go @@ -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 +} diff --git a/pkg/grpc/discovery/resolver.go b/pkg/grpc/discovery/resolver.go new file mode 100644 index 0000000..2d59da7 --- /dev/null +++ b/pkg/grpc/discovery/resolver.go @@ -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 +} diff --git a/pkg/grpc/generic/desc_source/desc_source.go b/pkg/grpc/generic/desc_source/desc_source.go new file mode 100644 index 0000000..1ea0895 --- /dev/null +++ b/pkg/grpc/generic/desc_source/desc_source.go @@ -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 +} diff --git a/pkg/grpc/generic/desc_source/error.go b/pkg/grpc/generic/desc_source/error.go new file mode 100644 index 0000000..a84cc85 --- /dev/null +++ b/pkg/grpc/generic/desc_source/error.go @@ -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 +} diff --git a/pkg/protocol/protocol.go b/pkg/protocol/protocol.go new file mode 100644 index 0000000..c450f77 --- /dev/null +++ b/pkg/protocol/protocol.go @@ -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 +} diff --git a/pkg/utils/conver/unit_conver.go b/pkg/utils/conver/unit_conver.go new file mode 100644 index 0000000..92b1166 --- /dev/null +++ b/pkg/utils/conver/unit_conver.go @@ -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)) +} diff --git a/pkg/utils/logger/exported.go b/pkg/utils/logger/exported.go new file mode 100644 index 0000000..44ce168 --- /dev/null +++ b/pkg/utils/logger/exported.go @@ -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...) +} diff --git a/pkg/utils/logger/logger.go b/pkg/utils/logger/logger.go new file mode 100644 index 0000000..01ee9f1 --- /dev/null +++ b/pkg/utils/logger/logger.go @@ -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 +} diff --git a/pkg/utils/nets/ip.go b/pkg/utils/nets/ip.go new file mode 100644 index 0000000..65a2f83 --- /dev/null +++ b/pkg/utils/nets/ip.go @@ -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 +} diff --git a/pkg/utils/shutdown/signal.go b/pkg/utils/shutdown/signal.go new file mode 100644 index 0000000..a7ff8ba --- /dev/null +++ b/pkg/utils/shutdown/signal.go @@ -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 +//}