package battle import ( "context" "go_dreamfactory/modules" "go_dreamfactory/pb" "sync" "go_dreamfactory/lego/core" "github.com/gorilla/websocket" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) /* 战斗服务客户端组件 */ type clientComp struct { modules.MCompGate options *Options service core.IService module *Battle conn *websocket.Conn seq uint64 pendingmutex sync.Mutex pending map[uint64]*MessageCall //高并发回调 } //组件初始化接口 func (this *clientComp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.MCompGate.Init(service, module, comp, options) this.options = options.(*Options) this.module = module.(*Battle) this.pending = make(map[uint64]*MessageCall) return } func (this *clientComp) Start() (err error) { err = this.MCompGate.Start() dialer := websocket.Dialer{} this.conn, _, err = dialer.Dial(this.options.BattleServerAddr, nil) return } //校验战斗过程 func (this *clientComp) callBattle(ctx context.Context, method string, req proto.Message, reply proto.Message) (err error) { call := new(MessageCall) call.Done = make(chan *MessageCall, 10) call.Args = req call.Reply = reply this.pendingmutex.Lock() seq := this.seq this.seq++ this.pending[seq] = call this.pendingmutex.Unlock() msg := &pb.BattleRpcMessage{ Rid: seq, Method: method, } msg.Data, _ = anypb.New(req) data, _ := proto.Marshal(msg) if err = this.conn.WriteMessage(websocket.BinaryMessage, data); err != nil { this.pendingmutex.Lock() delete(this.pending, seq) this.pendingmutex.Unlock() return } select { case <-ctx.Done(): // cancel by context this.pendingmutex.Lock() call := this.pending[seq] delete(this.pending, seq) this.pendingmutex.Unlock() if call != nil { call.Error = ctx.Err() call.done(this.options.Log) } return ctx.Err() case call := <-call.Done: err = call.Error } return } func (this *clientComp) run() { var ( data []byte msg *pb.BattleRpcMessage = &pb.BattleRpcMessage{} err error ) locp: for { if _, data, err = this.conn.ReadMessage(); err != nil { this.module.Errorf("client err:%v", err) break locp } if err = proto.Unmarshal(data, msg); err != nil { this.module.Errorf("client Unmarshal err:%v", err) break locp } go this.handleresponse(msg) } } func (this *clientComp) handleresponse(resp *pb.BattleRpcMessage) { var call *MessageCall this.pendingmutex.Lock() call = this.pending[resp.Rid] delete(this.pending, resp.Rid) this.pendingmutex.Unlock() call.Error = resp.Data.UnmarshalTo(call.Reply) call.done(this.options.Log) }