package gameService import ( "fmt" "game/common/config" "game/common/constant" "game/common/proto/pb" "game/common/userBindService" "game/common/utils" "github.com/fox/fox/db" "github.com/fox/fox/etcd" "github.com/fox/fox/ipb" "github.com/fox/fox/log" "github.com/fox/fox/processor" "github.com/fox/fox/service" "github.com/go-redis/redis/v8" "github.com/golang/protobuf/proto" "time" ) type GameService struct { *service.NatsService processor *processor.Processor bindService *userBindService.UserBindService } func NewGameService(param *service.InitNatsServiceParams, cfgRedis *config.Redis) *GameService { var err error s := new(GameService) s.NatsService, err = service.NewNatsService(param) if err != nil { log.Fatal(err.Error()) return nil } var userBindServiceRedis *redis.Client userBindServiceRedis, err = db.InitRedis(cfgRedis.Password, cfgRedis.Host, cfgRedis.Port, constant.Redis3UserBindService) if err != nil { log.Fatal(err.Error()) return nil } utils.AutoSetRedisPool(userBindServiceRedis) s.bindService = userBindService.NewUserBindService(userBindServiceRedis, s.ServiceEtcd()) s.processor = processor.NewProcessor() return s } func (s *GameService) BindService() *userBindService.UserBindService { return s.bindService } func (s *GameService) Processor() *processor.Processor { return s.processor } // 依赖子类实现,通过节点id获取topic名再调用SendByTopic func (s *GameService) SendByServiceId(serviceId int, msg *ipb.InternalMsg) error { node, err := s.findNode(pb.ServiceTypeId(serviceId), msg.UserId) if err != nil { return err } topic := service.TopicEx(node.Name) return s.SendByTopic(topic, msg) } // 向内部服务发送消息 func (s *GameService) SendServiceData(topic string, connId uint32, userId int64, msgId int32, data []byte) { iMsg := ipb.MakeMsg(s.Name(), connId, userId, msgId, data) _ = s.SendByTopic(topic, iMsg) } // 向内部服务发送消息 func (s *GameService) SendServiceMsg(sid pb.ServiceTypeId, userId int64, msgId int32, msg proto.Message) { node, err := s.findNode(sid, userId) if err != nil { log.Error(err.Error()) return } topic := service.TopicEx(node.Name) s.SendServiceMsgByTopic(topic, 0, userId, msgId, msg) } func (s *GameService) SendServiceMsgByTopic(topic string, connId uint32, userId int64, msgId int32, msg proto.Message) { log.DebugF("send to:%v msg id:%v, msg:%v", topic, pb.MsgId(msgId), msg.String()) data, _ := proto.Marshal(msg) s.SendServiceData(topic, connId, userId, msgId, data) } // 向内部服务发送消息 func (s *GameService) findNode(serviceId pb.ServiceTypeId, uid int64) (*etcd.ServiceNode, error) { var err error var node *etcd.ServiceNode switch s.bindService.CheckServiceNodeStateType(serviceId) { case etcd.SNST_Stateful: node, err = s.bindService.FindServiceNode(serviceId, uid) case etcd.SNST_Stateless: node, err = s.bindService.HashServiceNode(serviceId, uid) case etcd.SNST_Ordered: node, err = s.bindService.HashServiceNode(serviceId, uid) default: log.ErrorF(s.Log("查找节点类型失败。sid:%v", serviceId)) return nil, fmt.Errorf(s.Log("查找节点类型失败。sid:%v", serviceId)) } if err != nil { return nil, fmt.Errorf(s.Log("查找节点类型失败。sid:%v err:%v", serviceId, err)) } return node, nil } // call实现 func (s *GameService) CallByServiceId(serviceId int, timeout time.Duration, msg *ipb.InternalMsg) (*ipb.InternalMsg, error) { node, err := s.findNode(pb.ServiceTypeId(serviceId), msg.UserId) if err != nil { return nil, err } topic := service.RpcTopicEx(node.Name) return s.CallByTopic(topic, timeout, msg) }