package wxwork import ( "log/slog" "strings" "sync" "github.com/panjf2000/ants/v2" "github.com/silenceper/wechat/v2/work/kf" ) const ( callbackWorkerCount = 16 // worker 数量 callbackMaxBlockingTasks = 10000 // 队列大小 callbackMsgTypeEvent = "event" callbackEventKFMsgOrEvent = "kf_msg_or_event" ) type CallbackHandler func(message kf.CallbackMessage) var ( callbackHandlerMu sync.RWMutex callbackHandlers map[string]CallbackHandler callbackPool *ants.PoolWithFunc ) func init() { var err error callbackHandlers = make(map[string]CallbackHandler) callbackPool, err = ants.NewPoolWithFunc( callbackWorkerCount, dispatchCallbackMessage, ants.WithMaxBlockingTasks(callbackMaxBlockingTasks), ) if err != nil { slog.Error("init wxwork callback pool failed", "error", err) } } // ConsumeCallback 异步消费企业微信客服回调。 func ConsumeCallback(message kf.CallbackMessage) error { if callbackPool == nil { slog.Error("wxwork callback pool is not initialized", "msg_type", message.MsgType, "event", message.Event, "open_kfid", message.OpenKfID, ) return nil } if err := callbackPool.Invoke(message); err != nil { slog.Error("invoke wxwork callback failed", "msg_type", message.MsgType, "event", message.Event, "open_kfid", message.OpenKfID, "error", err, ) return err } return nil } // RegHandler 注册企业微信客服回调处理器。 func RegHandler(msgType, event string, handler CallbackHandler) { callbackHandlerMu.Lock() defer callbackHandlerMu.Unlock() key := buildCallbackKey(msgType, event) if callbackHandlers[key] != nil { slog.Error("duplicate wxwork callback handler registration", "key", key) return } callbackHandlers[key] = handler } // buildCallbackKey 生成客服回调处理器的注册键。 func buildCallbackKey(msgType, event string) string { msgType = strings.TrimSpace(msgType) event = strings.TrimSpace(event) if msgType == callbackMsgTypeEvent { return msgType + ":" + event } return msgType } func dispatchCallbackMessage(value any) { message, ok := value.(kf.CallbackMessage) if !ok { slog.Error("invalid wxwork callback message type") return } handler := getCallbackHandler(message) if handler == nil { return } handler(message) } func getCallbackHandler(message kf.CallbackMessage) CallbackHandler { callbackHandlerMu.RLock() defer callbackHandlerMu.RUnlock() key := buildCallbackKey(message.MsgType, message.Event) handler, ok := callbackHandlers[key] if ok { return handler } slog.Warn("wxwork callback handler not found", "key", key, "msg_type", message.MsgType, "event", message.Event, ) return nil }