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,149 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/yourname/cyrene-ai/platform-bridge/internal/bridge"
|
||||
)
|
||||
|
||||
// BridgeHandler exposes the Platform Bridge REST API.
|
||||
type BridgeHandler struct {
|
||||
router *bridge.PlatformRouter
|
||||
}
|
||||
|
||||
func NewBridgeHandler(router *bridge.PlatformRouter) *BridgeHandler {
|
||||
return &BridgeHandler{router: router}
|
||||
}
|
||||
|
||||
func (h *BridgeHandler) RegisterRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/health", h.health)
|
||||
mux.HandleFunc("/api/v1/platforms", h.listPlatforms)
|
||||
mux.HandleFunc("/api/v1/platforms/", h.platformInfo)
|
||||
mux.HandleFunc("/api/v1/identities", h.listIdentities)
|
||||
mux.HandleFunc("/api/v1/webhook/telegram", h.telegramWebhook)
|
||||
mux.HandleFunc("/api/v1/webhook/", h.genericWebhook)
|
||||
}
|
||||
|
||||
func (h *BridgeHandler) health(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"status": "ok", "service": "platform-bridge",
|
||||
"platforms": h.router.ListAdapters(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *BridgeHandler) listPlatforms(w http.ResponseWriter, r *http.Request) {
|
||||
names := h.router.ListAdapters()
|
||||
type platformSummary struct {
|
||||
Name string `json:"name"`
|
||||
Connected bool `json:"connected"`
|
||||
Caps bridge.PlatformCapabilities `json:"capabilities"`
|
||||
}
|
||||
var platforms []platformSummary
|
||||
for _, name := range names {
|
||||
a, err := h.router.GetAdapter(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
platforms = append(platforms, platformSummary{
|
||||
Name: name,
|
||||
Connected: a.IsConnected(),
|
||||
Caps: a.Capabilities(),
|
||||
})
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{"platforms": platforms, "total": len(platforms)})
|
||||
}
|
||||
|
||||
func (h *BridgeHandler) platformInfo(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Path[len("/api/v1/platforms/"):]
|
||||
a, err := h.router.GetAdapter(name)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusNotFound, errResp(err.Error()))
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"name": name,
|
||||
"connected": a.IsConnected(),
|
||||
"capabilities": a.Capabilities(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *BridgeHandler) listIdentities(w http.ResponseWriter, r *http.Request) {
|
||||
all := h.router.ListAllIdentities()
|
||||
writeJSON(w, http.StatusOK, all)
|
||||
}
|
||||
|
||||
// telegramWebhook receives updates from Telegram Bot API.
|
||||
func (h *BridgeHandler) telegramWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
writeJSON(w, http.StatusMethodNotAllowed, errResp("method not allowed"))
|
||||
return
|
||||
}
|
||||
|
||||
// Parse into a generic map first to check for message presence.
|
||||
var raw map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&raw); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, errResp("invalid telegram update"))
|
||||
return
|
||||
}
|
||||
if _, hasMsg := raw["message"]; !hasMsg {
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "ignored"})
|
||||
return
|
||||
}
|
||||
|
||||
_, err := h.router.RouteMessage("telegram", raw)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
// genericWebhook receives standard webhook payloads.
|
||||
func (h *BridgeHandler) genericWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
writeJSON(w, http.StatusMethodNotAllowed, errResp("method not allowed"))
|
||||
return
|
||||
}
|
||||
|
||||
// Extract platform name from path: /api/v1/webhook/{platform}
|
||||
platform := r.URL.Path[len("/api/v1/webhook/"):]
|
||||
if platform == "" || platform == "telegram" {
|
||||
writeJSON(w, http.StatusBadRequest, errResp("specify platform name in path"))
|
||||
return
|
||||
}
|
||||
|
||||
var payload map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, errResp("invalid JSON payload"))
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.router.RouteMessage(platform, &payload)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to platform-specific format.
|
||||
msgs, err := h.router.SendResponse(response)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"messages": msgs,
|
||||
"reply_to": response.ReplyTo,
|
||||
})
|
||||
}
|
||||
|
||||
func errResp(msg string) map[string]string {
|
||||
return map[string]string{"error": msg}
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
json.NewEncoder(w).Encode(data)
|
||||
}
|
||||
Reference in New Issue
Block a user