feat: Phase 4 多平台接入 — Platform Bridge + 6平台适配器 + 身份权限系统 (22文件, 2129行)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/yourname/cyrene-ai/platform-bridge/internal/bridge"
|
||||
)
|
||||
|
||||
// WebhookPayload is the standard webhook request body.
|
||||
type WebhookPayload struct {
|
||||
UserID string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
Content string `json:"content"`
|
||||
ContentType string `json:"content_type"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
ChannelType string `json:"channel_type"`
|
||||
MessageID string `json:"message_id,omitempty"`
|
||||
ReplyTo string `json:"reply_to,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
// WebhookResponse is the standard webhook response body.
|
||||
type WebhookResponse struct {
|
||||
Messages []WebhookResponseMessage `json:"messages"`
|
||||
ReplyTo string `json:"reply_to,omitempty"`
|
||||
}
|
||||
|
||||
// WebhookResponseMessage is a single message in a webhook response.
|
||||
type WebhookResponseMessage struct {
|
||||
Type string `json:"type"` // "chat", "action", "system_info"
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// Adapter implements PlatformAdapter for generic webhook integrations.
|
||||
type Adapter struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func NewAdapter(name string) *Adapter {
|
||||
if name == "" {
|
||||
name = "webhook"
|
||||
}
|
||||
return &Adapter{name: name}
|
||||
}
|
||||
|
||||
func (a *Adapter) PlatformName() string { return a.name }
|
||||
|
||||
func (a *Adapter) Capabilities() bridge.PlatformCapabilities {
|
||||
return bridge.PlatformCapabilities{
|
||||
MaxMessageLength: 2000,
|
||||
SupportsMarkdown: true,
|
||||
SupportsImage: false,
|
||||
SupportsVoice: false,
|
||||
SupportsEmoji: true,
|
||||
SupportsReaction: false,
|
||||
SupportsTypingHint: false,
|
||||
RecommendBurstMax: 2,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Adapter) Connect(ctx context.Context) error {
|
||||
fmt.Printf("[webhook:%s] adapter ready\n", a.name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Adapter) Disconnect(ctx context.Context) error { return nil }
|
||||
|
||||
func (a *Adapter) IsConnected() bool { return true }
|
||||
|
||||
func (a *Adapter) HealthCheck() error { return nil }
|
||||
|
||||
// ToUnified converts a webhook payload to UnifiedMessage.
|
||||
func (a *Adapter) ToUnified(rawMessage interface{}) (*bridge.UnifiedMessage, error) {
|
||||
payload, ok := rawMessage.(*WebhookPayload)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected *WebhookPayload, got %T", rawMessage)
|
||||
}
|
||||
|
||||
contentType := payload.ContentType
|
||||
if contentType == "" {
|
||||
contentType = "text"
|
||||
}
|
||||
channelType := payload.ChannelType
|
||||
if channelType == "" {
|
||||
channelType = "direct"
|
||||
}
|
||||
|
||||
ts := time.Now()
|
||||
if payload.Timestamp > 0 {
|
||||
ts = time.Unix(payload.Timestamp, 0)
|
||||
}
|
||||
|
||||
return &bridge.UnifiedMessage{
|
||||
SenderID: payload.UserID,
|
||||
SenderName: payload.UserName,
|
||||
Platform: a.name,
|
||||
ChannelID: payload.ChannelID,
|
||||
ChannelType: channelType,
|
||||
Content: payload.Content,
|
||||
ContentType: contentType,
|
||||
MessageID: payload.MessageID,
|
||||
ReplyTo: payload.ReplyTo,
|
||||
RawData: rawMessage,
|
||||
Timestamp: ts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FromUnified converts a unified response to webhook response format.
|
||||
func (a *Adapter) FromUnified(response *bridge.UnifiedResponse) ([]bridge.PlatformMessage, error) {
|
||||
var msgs []bridge.PlatformMessage
|
||||
for _, rm := range response.Messages {
|
||||
msgs = append(msgs, bridge.PlatformMessage{
|
||||
Content: rm.Content,
|
||||
FormatMode: rm.FormatMode,
|
||||
ReplyTo: response.ReplyTo,
|
||||
})
|
||||
}
|
||||
return msgs, nil
|
||||
}
|
||||
Reference in New Issue
Block a user