package handler import ( "encoding/json" "fmt" "github.com/rabbitmq/amqp091-go" "math/rand" "samba/pkg/log" "samba/pkg/repo" "samba/pkg/rmq" "samba/pkg/servername" "samba/pkg/service" "samba/util/config" "samba/util/util" ) type dbService struct { service.IService *repo.ClickHouseRepo } var gDBServices dbServices type dbServices struct { services []*dbService } func (d *dbServices) Get(uid int64) *dbService { if uid < 0 { i := rand.Int() % len(d.services) return d.services[i] } return d.services[uid%int64(len(d.services))] } func (d *dbServices) QueueName(childId int) string { return fmt.Sprintf("%v-%v", servername.ClickHouse, childId) } func (d *dbServices) Num() int { return len(d.services) } func hallHandlerMessage(_ service.IService, d *amqp091.Delivery) { var msg map[string]interface{} if err := json.Unmarshal(d.Body, &msg); err != nil { log.Error(fmt.Sprintf("consume message error: %v.body:%v", err, string(d.Body))) return } //log.Debug(fmt.Sprintf("srv:%v recv msg:%v", s.Name(), string(d.Body))) if fn, ok := MsgHandler[msg["a"].(string)]; ok { fn(d, msg) } else { log.Error(fmt.Sprintf("msgId:%v not exist", msg["a"])) } } func InitService() { for j := 0; j < config.Cmd.ChildNum; j++ { i := j opts := []service.Option{ service.SetOnInit(func(s service.IService) bool { if err := s.ExchangeDeclare(util.Direct(servername.ClickHouse), rmq.ExchangeDirect); err != nil { log.Error(err.Error()) return false } if err := s.ExchangeDeclare(util.Topic(servername.ClickHouse), rmq.ExchangeTopic); err != nil { log.Error(err.Error()) return false } if err := s.QueueDeclare(gDBServices.QueueName(i)); err != nil { log.Error(err.Error()) return false } if !RegisterMsgHandler(s, i) { return false } if err := s.Consume(gDBServices.QueueName(i)); err != nil { log.Error(err.Error()) return false } log.Info(fmt.Sprintf("service:%v init", s.Name())) return true }), service.SetOnNotifyStop(func(s service.IService) { }), service.SetCanStop(func(s service.IService) bool { return true }), service.SetOnStop(func(s service.IService) { if err := s.ConsumeDelete(); err != nil { log.Error(err.Error()) } else { log.Info(fmt.Sprintf("delete consume channle")) } if err := s.QueueDelete(gDBServices.QueueName(i)); err != nil { log.Error(err.Error()) } else { log.Info(fmt.Sprintf("delete queue:%v", gDBServices.QueueName(i))) } log.Info(fmt.Sprintf("service:%v stop", s.Name())) }), } s := service.NewService(servername.ClickHouse, gDBServices.QueueName(i), config.RabbitmqUrl(), hallHandlerMessage, opts...) dbs := &dbService{ IService: s, } cnf := &config.Config.ClickHouse var err error dbs.ClickHouseRepo, err = repo.InitClickHouse(cnf.Host, cnf.Port, cnf.Username, cnf.Password, cnf.DbName) if err != nil { log.Error(err.Error()) } else { gDBServices.services = append(gDBServices.services, dbs) } } } func StopService() { for _, s := range gDBServices.services { s.NotifyStop() } for _, s := range gDBServices.services { s.WaitStop() } } func SendMsg(exchange, router, token string, uid int64, msgId string, msg interface{}) error { data := service.Message{ MsgId: msgId, Data: msg, Token: token, Uid: uid, } byteData, err := json.Marshal(data) if err != nil { return err } log.Debug(fmt.Sprintf("send msg:%v to exchange:%v, routKey:%v, data:%v", msgId, exchange, router, string(byteData))) if err = gDBServices.Get(uid).Publish(exchange, router, byteData); err != nil { log.Error(err.Error()) } return err } func SendMsgToRPC(d *amqp091.Delivery, svr service.IService, data any, rid string, methodName ...string) { rsp := map[string]any{ "a": util.Tie(len(rid) > 0, rid, "0"), "p": data, } buf, err := json.Marshal(rsp) if err == nil { err = svr.PublishRpc(d, buf) } if err != nil { log.Error(fmt.Sprintf("response RPC fail method=%s,err:%v", util.TieOrFn(len(methodName) <= 0, "unknown", func() string { return methodName[0] }), err)) } }