Browse Source

grpc server

master
tangmingyou 3 years ago
parent
commit
1b34df21e5
  1. 1
      .gitignore
  2. 2
      api/auth.proto
  3. 44
      api/chat.proto
  4. 2
      api/mahjong.proto
  5. 4
      api/postal.proto
  6. 1
      cmd/auth/main.go
  7. 37
      cmd/gateway_ws/config.toml
  8. 30
      cmd/gateway_ws/main.go
  9. 4
      generate.go
  10. 55
      go.mod
  11. 190
      go.sum
  12. 23
      internal/auth/logic/auth_server.go
  13. 43
      internal/chat/logic/chat_server.go
  14. 59
      internal/mahjong/logic/mahjong_server.go
  15. 44
      internal/postal/logic/postal_server.go
  16. 4
      internal/postal/ws/ws_server.go
  17. 55
      pkg/config/config.go
  18. 18
      pkg/config/gorm.go
  19. 23
      pkg/config/grpc_options.go
  20. 80
      pkg/config/loader.go
  21. 1
      pkg/deliver/deliver.go
  22. 72
      pkg/grpc/discovery/instance.go
  23. 166
      pkg/grpc/discovery/register.go
  24. 168
      pkg/grpc/discovery/resolver.go
  25. 289
      pkg/grpc/generic/desc_source/desc_source.go
  26. 25
      pkg/grpc/generic/desc_source/error.go
  27. 38
      pkg/protocol/protocol.go
  28. 30
      pkg/utils/conver/unit_conver.go
  29. 49
      pkg/utils/logger/exported.go
  30. 78
      pkg/utils/logger/logger.go
  31. 42
      pkg/utils/nets/ip.go
  32. 52
      pkg/utils/shutdown/signal.go

1
.gitignore vendored

@ -28,4 +28,5 @@ Thumbs.db
/tmp
/api/gen
/api/genjs
.back_groups/

2
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);

44
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; // 12
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;
}

2
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); //

4
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 {

1
cmd/auth/main.go

@ -0,0 +1 @@
package main

37
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

30
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()
}

4
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

55
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
)

190
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=

23
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
}

43
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
}

59
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
}

44
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
}

4
internal/postal/ws/ws_server.go

@ -0,0 +1,4 @@
package ws
type WebsocketServer struct {
}

55
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
}

18
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
}

23
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
}

80
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
}

1
pkg/deliver/deliver.go

@ -0,0 +1 @@
package deliver

72
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
}

166
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
}

168
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
}

289
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
}

25
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
}

38
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
}

30
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))
}

49
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...)
}

78
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
}

42
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
}

52
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
//}
Loading…
Cancel
Save