Files
2026-05-06 10:45:51 +08:00

90 lines
2.8 KiB
Go

package platformadapter
import (
"encoding/json"
"net/http"
"strings"
"time"
"github.com/bridge/ai-customer-service/internal/domain/message"
"github.com/bridge/ai-customer-service/internal/service/dialog"
)
type Sub2APIAdapter struct{}
func NewSub2APIAdapter() *Sub2APIAdapter {
return &Sub2APIAdapter{}
}
func (a *Sub2APIAdapter) Platform() string {
return "sub2api"
}
func (a *Sub2APIAdapter) ParseInbound(_ *http.Request, body []byte, ctx IngressContext) (*message.UnifiedMessage, *PlatformInboundMeta, error) {
var payload Sub2APIInboundPayload
decoder := json.NewDecoder(strings.NewReader(string(body)))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&payload); err != nil {
return nil, nil, NewRequestError(http.StatusBadRequest, "CS_REQ_4001", "invalid request body")
}
payload.Channel = strings.TrimSpace(payload.Channel)
payload.OpenID = strings.TrimSpace(payload.OpenID)
payload.UserID = strings.TrimSpace(payload.UserID)
payload.Content = strings.TrimSpace(payload.Content)
payload.ContentType = strings.TrimSpace(payload.ContentType)
payload.ReplyTo = strings.TrimSpace(payload.ReplyTo)
if ctx.PathChannel != "" {
payload.Channel = strings.TrimSpace(ctx.PathChannel)
}
if payload.Channel == "" || payload.OpenID == "" || payload.Content == "" {
return nil, nil, NewRequestError(http.StatusBadRequest, "CS_REQ_4002", "channel, open_id and content are required")
}
if payload.Timestamp.IsZero() {
payload.Timestamp = ctx.ReceivedAt
}
msg := &message.UnifiedMessage{
MessageID: payload.MessageID,
Channel: payload.Channel,
OpenID: payload.OpenID,
UserID: payload.UserID,
Content: payload.Content,
ContentType: payload.ContentType,
Timestamp: payload.Timestamp,
ReplyTo: payload.ReplyTo,
}
meta := &PlatformInboundMeta{
EventID: buildEventID("sub2api", payload.MessageID, payload.OpenID, ctx.ReceivedAt),
Platform: a.Platform(),
Channel: payload.Channel,
SourceMessageID: payload.MessageID,
SourceUserID: payload.OpenID,
}
return msg, meta, nil
}
func (a *Sub2APIAdapter) BuildIngressAck(result *dialog.Result, meta *PlatformInboundMeta) any {
resp := map[string]any{
"accepted": true,
"platform": a.Platform(),
}
if meta != nil {
resp["event_id"] = meta.EventID
}
if result != nil {
resp["session_id"] = result.SessionID
if strings.TrimSpace(result.TicketID) != "" {
resp["ticket_id"] = result.TicketID
}
}
return resp
}
func buildEventID(platform, messageID, openID string, now time.Time) string {
if strings.TrimSpace(messageID) != "" {
return strings.ToLower(strings.TrimSpace(platform)) + ":" + strings.TrimSpace(messageID)
}
return strings.ToLower(strings.TrimSpace(platform)) + ":" + strings.TrimSpace(openID) + ":" + now.UTC().Format(time.RFC3339Nano)
}