feat 排队
This commit is contained in:
@@ -4,7 +4,8 @@ import (
|
||||
"common/log"
|
||||
"common/proto/sc/sc_pb"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"gateway/internal/handler/ws_handler"
|
||||
"context"
|
||||
"gateway/internal/handler/ws_handler/client"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"sync"
|
||||
)
|
||||
@@ -38,16 +39,16 @@ func (s *Server) ToClient(server grpc_pb.Gateway_ToClientServer) error {
|
||||
log.Errorf("ToClient proto.Marshal error: %v", err)
|
||||
continue
|
||||
}
|
||||
for _, client := range ws_handler.UserMgr.GetAll() {
|
||||
client.WriteBytesPreMarshal(data)
|
||||
for _, cli := range client.UserMgr.GetAll() {
|
||||
cli.WriteBytesPreMarshal(data)
|
||||
}
|
||||
|
||||
//for _, client := range ws_handler.UserMgr.GetAll() {
|
||||
// client.WriteBytes(sc_pb.MessageID(args.MessageID), args.Payload)
|
||||
//}
|
||||
} else {
|
||||
if client := ws_handler.UserMgr.GetByUSN(args.USN); client != nil {
|
||||
client.WriteBytes(sc_pb.MessageID(args.MessageID), args.Payload)
|
||||
if cli := client.UserMgr.GetByUSN(args.USN); cli != nil {
|
||||
cli.WriteBytes(sc_pb.MessageID(args.MessageID), args.Payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,3 +57,7 @@ func (s *Server) ToClient(server grpc_pb.Gateway_ToClientServer) error {
|
||||
wg.Wait()
|
||||
return server.SendAndClose(&grpc_pb.ToClientResp{})
|
||||
}
|
||||
|
||||
func (s *Server) KickUser(ctx context.Context, req *grpc_pb.KickUserReq) (*grpc_pb.KickUserResp, error) {
|
||||
return &grpc_pb.KickUserResp{}, nil
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"common/discover/common"
|
||||
"common/net/grpc/service"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"gateway/internal/handler/ws_handler"
|
||||
"gateway/internal/handler/ws_handler/client"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ func NewServer(ttl int64) *Server {
|
||||
}
|
||||
|
||||
func (s *Server) OnInit(serve *grpc.Server) {
|
||||
ws_handler.GatewaySID = s.SID
|
||||
client.GatewaySID = s.SID
|
||||
grpc_pb.RegisterGatewayServer(serve, s)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,60 +6,79 @@ import (
|
||||
"context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var sceneServerM map[int64]map[SceneFun]grpc.ClientStream // map[sid]map[方法名]流连接
|
||||
|
||||
type SceneFun int
|
||||
|
||||
const (
|
||||
FunAction SceneFun = iota
|
||||
)
|
||||
|
||||
func init() {
|
||||
sceneServerM = make(map[int64]map[SceneFun]grpc.ClientStream)
|
||||
var sceneServer sync.Map // map[string]*sceneStream
|
||||
|
||||
type sceneStream struct {
|
||||
mu sync.Mutex
|
||||
stream grpc.ClientStream
|
||||
}
|
||||
|
||||
func findSceneBySID(sid int64, fun SceneFun) (grpc.ClientStream, error) {
|
||||
g := sceneServerM[sid]
|
||||
if g == nil {
|
||||
g = make(map[SceneFun]grpc.ClientStream)
|
||||
sceneServerM[sid] = g
|
||||
func findSceneBySID(sid int64, fun SceneFun) (*sceneStream, error) {
|
||||
key := sceneKey(sid, fun)
|
||||
|
||||
if v, ok := sceneServer.Load(key); ok {
|
||||
return v.(*sceneStream), nil
|
||||
}
|
||||
sceneLink := g[fun]
|
||||
if sceneLink == nil {
|
||||
sceneClient, err := service.SceneNewClient(sid)
|
||||
if err != nil {
|
||||
log.Errorf("cannot find sceneClient: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
var link grpc.ClientStream
|
||||
switch fun {
|
||||
case FunAction:
|
||||
link, err = sceneClient.Action(context.Background())
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("findSceneBySID %v err: %v, sid: %v", fun, err, sid)
|
||||
return nil, err
|
||||
}
|
||||
g[fun] = link
|
||||
sceneLink = link
|
||||
|
||||
client, err := service.SceneNewClient(sid)
|
||||
if err != nil {
|
||||
log.Errorf("findSceneBySID cannot find client: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return sceneLink, nil
|
||||
var stream grpc.ClientStream
|
||||
switch fun {
|
||||
case FunAction:
|
||||
stream, err = client.Action(context.Background())
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("findSceneBySID %v err: %v, sid: %v", fun, err, sid)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ss := &sceneStream{stream: stream}
|
||||
if actual, loaded := sceneServer.LoadOrStore(key, ss); loaded {
|
||||
go func() { _ = stream.CloseSend() }()
|
||||
return actual.(*sceneStream), nil
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func SendMessageToScene(sid int64, fun SceneFun, msg proto.Message, re ...bool) error {
|
||||
stream, err := findSceneBySID(sid, fun)
|
||||
ss, err := findSceneBySID(sid, fun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = stream.SendMsg(msg); err != nil {
|
||||
|
||||
ss.mu.Lock()
|
||||
err = ss.stream.SendMsg(msg)
|
||||
ss.mu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
key := sceneKey(sid, fun)
|
||||
if v, ok := sceneServer.Load(key); ok && v == ss {
|
||||
sceneServer.Delete(key)
|
||||
_ = ss.stream.CloseSend()
|
||||
}
|
||||
// 如果没有标识本次是重试的,就重试一次(默认重试)
|
||||
if re == nil || !re[0] {
|
||||
_ = stream.CloseSend()
|
||||
delete(sceneServerM[sid], fun)
|
||||
return SendMessageToScene(sid, fun, msg, true)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sceneKey(sid int64, fun SceneFun) string {
|
||||
return strconv.FormatInt(sid, 10) + "-" + strconv.Itoa(int(fun))
|
||||
}
|
||||
|
||||
20
internal/grpc_server/stream_client/scene_test.go
Normal file
20
internal/grpc_server/stream_client/scene_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package stream_client
|
||||
|
||||
import (
|
||||
"gateway/internal/testutil"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type SceneTestSuite struct {
|
||||
testutil.TestSuite
|
||||
}
|
||||
|
||||
func (ts *SceneTestSuite) TestSceneKey() {
|
||||
r := sceneKey(1122, FunAction)
|
||||
ts.Assert().Equal("1122-0", r)
|
||||
}
|
||||
|
||||
func TestLoginTestSuite(t *testing.T) {
|
||||
suite.Run(t, &SceneTestSuite{})
|
||||
}
|
||||
Reference in New Issue
Block a user