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) }