feat(channel): KOOK Webhook(WH) 接收模式——与 WS 配置切换(ReceiveMode)
- kook.Config 加 ReceiveMode("ws"默认/"webhook") + WebhookPath(默认/webhook/kook) + WebhookVerifyToken + WebhookEncryptKey(AES-256-CBC)
- 按权威文档(Reference/kaiheila webhook.md)实现: 无X-Signature HMAC, 真实校验=d.verify_token比对(不匹配403)+可选AES解密+zlib解压+challenge回显
- webhook.go: InboundHandler+WebhookPath, POST→zlib解压→AES解密→verify_token校验→challenge回显→归一UnifiedMessage→SetMessageHandler; WS模式Connect不拨网关仅标记connected
- channelbridge/webhookAdapter 接口改用 WebhookPath(); WebhookHandlers 收KOOK WH(ws模式跳过); 既有webhook通道补WebhookPath照常挂载
- namedAdapter 转发InboundHandler/WebhookPath; kook env兜底 +4个CHANNEL_KOOK_*键
- 测试: verify_token 403/challenge/zlib/AES往返/WebhookPath按模式/WH不拨gateway/WebhookHandlers收KOOK; 全仓build/vet/test绿
- 待真token端到端实测(需主人提供CHANNEL_KOOK_TOKEN+开发者后台切WebHook配回调URL)
This commit is contained in:
1 parent
1ebc82fffd
commit
617157262b
11 files changed
+981
-32
No files matched your search
@@ -112,12 +112,18 @@ func New(cfg Config, opts ...Option) *Adapter {
|
||||
// Name returns the platform identifier.
|
||||
func (a *Adapter) Name() string { return platformName }
|
||||
|
||||
// Config returns a snapshot of the adapter's configuration. The BotToken is the
|
||||
// sensitive field; callers that persist this map must treat it as a secret.
|
||||
// Config returns a snapshot of the adapter's configuration. The BotToken,
|
||||
// WebhookVerifyToken and WebhookEncryptKey are sensitive; callers that persist
|
||||
// this map must treat them as secrets (the admin read path masks these keys via
|
||||
// the "token"/"key" substring rules).
|
||||
func (a *Adapter) Config() map[string]any {
|
||||
return map[string]any{
|
||||
"bot_token": a.cfg.BotToken,
|
||||
"base_url": a.baseURL,
|
||||
"bot_token": a.cfg.BotToken,
|
||||
"base_url": a.baseURL,
|
||||
"receive_mode": a.cfg.normalizedReceiveMode(),
|
||||
"webhook_path": a.cfg.WebhookPath,
|
||||
"webhook_verify_token": a.cfg.WebhookVerifyToken,
|
||||
"webhook_encrypt_key": a.cfg.WebhookEncryptKey,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +144,21 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
||||
a.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
mode := a.cfg.normalizedReceiveMode()
|
||||
a.mu.Unlock()
|
||||
|
||||
// Webhook mode: the Cyrene gateway mounts InboundHandler to receive KOOK
|
||||
// callbacks (KOOK posts to the configured route). No gateway WebSocket is
|
||||
// dialed — webhook and websocket are mutually exclusive. Mark connected so the
|
||||
// REST reply path and HealthCheck see a live session.
|
||||
if mode == modeWebhook {
|
||||
a.mu.Lock()
|
||||
a.connected = true
|
||||
a.mu.Unlock()
|
||||
a.log.Info("connected", "mode", mode, "token_len", len(a.cfg.BotToken))
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := a.fetchGatewayURL(ctx); err != nil {
|
||||
return fmt.Errorf("kook: connect: %w", err)
|
||||
}
|
||||
@@ -151,7 +170,7 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
||||
a.mu.Unlock()
|
||||
|
||||
go a.runWS(lifeCtx)
|
||||
a.log.Info("connected", "token_len", len(a.cfg.BotToken))
|
||||
a.log.Info("connected", "mode", mode, "token_len", len(a.cfg.BotToken))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -230,14 +249,14 @@ func (a *Adapter) SetMessageHandler(fn adapter.MessageHandler) {
|
||||
// bot-uploaded media URLs.
|
||||
func (a *Adapter) Capabilities() adapter.Capabilities {
|
||||
return adapter.Capabilities{
|
||||
MaxMessageLength: maxMessageLen,
|
||||
Markdown: true,
|
||||
Image: false,
|
||||
Voice: false,
|
||||
Reaction: false,
|
||||
TypingHint: false,
|
||||
MaxMessageLength: maxMessageLen,
|
||||
Markdown: true,
|
||||
Image: false,
|
||||
Voice: false,
|
||||
Reaction: false,
|
||||
TypingHint: false,
|
||||
RecommendBurstMax: 1,
|
||||
Proactive: true,
|
||||
Proactive: true,
|
||||
}.Normalize()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user