package gateway import ( "fmt" "net/http" "time" "gitea.rutua.cn/kate522/CrossRelay/internal/claudecfg" "gitea.rutua.cn/kate522/CrossRelay/internal/config" ) // providerInput is the provider payload accepted by the management API. type providerInput struct { Name string `json:"name"` Preset string `json:"preset"` BaseURL string `json:"base_url"` APIKey string `json:"api_key"` Models config.Models `json:"models"` } func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) { cfg := s.store.Config() var active any if p := s.store.ActiveClaude(); p != nil { active = map[string]any{ "id": p.ID, "name": p.Name, "base_url": p.BaseURL, "models": p.Models, } } writeJSON(w, http.StatusOK, map[string]any{ "running": true, "version": Version, "port": s.port, "uptime_sec": int(time.Since(s.started).Seconds()), "active_claude_provider": active, "stats": s.snapshotStats(), "language": cfg.Language, "port_mode": cfg.Gateway.PortMode, "fixed_port": cfg.Gateway.FixedPort, }) } func (s *Server) handleListProviders(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": s.store.Config().Providers}) } func (s *Server) handleCreateProvider(w http.ResponseWriter, r *http.Request) { var in providerInput if err := decodeJSON(r, &in, 1<<20); err != nil { writeAPIError(w, http.StatusBadRequest, "invalid request body: "+err.Error()) return } p, err := s.store.AddProvider(in.Name, in.Preset, in.BaseURL, in.APIKey, in.Models) if err != nil { writeAPIError(w, http.StatusBadRequest, err.Error()) return } writeJSON(w, http.StatusCreated, p) } func (s *Server) handleUpdateProvider(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var in providerInput if err := decodeJSON(r, &in, 1<<20); err != nil { writeAPIError(w, http.StatusBadRequest, "invalid request body: "+err.Error()) return } p, err := s.store.UpdateProvider(id, in.Name, in.Preset, in.BaseURL, in.APIKey, in.Models) if err != nil { writeAPIError(w, http.StatusBadRequest, err.Error()) return } writeJSON(w, http.StatusOK, p) } func (s *Server) handleDeleteProvider(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.store.DeleteProvider(id); err != nil { writeAPIError(w, http.StatusNotFound, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"deleted": id}) } // handleApply activates a provider and writes it into Claude Code's // settings.json. func (s *Server) handleApply(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") p, err := s.store.ActivateClaude(id) if err != nil { writeAPIError(w, http.StatusNotFound, err.Error()) return } mgr, err := s.claudeManager() if err != nil { writeAPIError(w, http.StatusInternalServerError, err.Error()) return } settings, err := mgr.Apply(claudecfg.ApplyOptions{ BaseURL: fmt.Sprintf("http://127.0.0.1:%d", s.port), Token: s.store.Config().RelayToken, Models: p.Models, }) if err != nil { writeAPIError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{ "provider": p, "env": settings.Env, }) } // handleRestore puts back the most recent backup of settings.json. func (s *Server) handleRestore(w http.ResponseWriter, r *http.Request) { mgr, err := s.claudeManager() if err != nil { writeAPIError(w, http.StatusInternalServerError, err.Error()) return } name, err := mgr.Restore() if err != nil { writeAPIError(w, http.StatusNotFound, err.Error()) return } _ = s.store.ClearActiveClaude() writeJSON(w, http.StatusOK, map[string]any{"restored_from": name}) } func (s *Server) handleBackups(w http.ResponseWriter, r *http.Request) { mgr, err := s.claudeManager() if err != nil { writeAPIError(w, http.StatusInternalServerError, err.Error()) return } items, err := mgr.Backups() if err != nil { writeAPIError(w, http.StatusInternalServerError, err.Error()) return } if items == nil { items = []claudecfg.BackupInfo{} } writeJSON(w, http.StatusOK, map[string]any{"items": items}) } func (s *Server) handleGetSettings(w http.ResponseWriter, r *http.Request) { cfg := s.store.Config() writeJSON(w, http.StatusOK, map[string]any{ "language": cfg.Language, "port_mode": cfg.Gateway.PortMode, "fixed_port": cfg.Gateway.FixedPort, }) } type settingsInput struct { Language string `json:"language"` PortMode string `json:"port_mode"` FixedPort int `json:"fixed_port"` } func (s *Server) handleUpdateSettings(w http.ResponseWriter, r *http.Request) { var in settingsInput if err := decodeJSON(r, &in, 1<<20); err != nil { writeAPIError(w, http.StatusBadRequest, "invalid request body: "+err.Error()) return } if in.Language != "" { if err := s.store.SetLanguage(in.Language); err != nil { writeAPIError(w, http.StatusBadRequest, err.Error()) return } } if in.PortMode != "" { if err := s.store.SetGateway(config.Gateway{ PortMode: in.PortMode, FixedPort: in.FixedPort, }); err != nil { writeAPIError(w, http.StatusBadRequest, err.Error()) return } } cfg := s.store.Config() writeJSON(w, http.StatusOK, map[string]any{ "language": cfg.Language, "port_mode": cfg.Gateway.PortMode, "fixed_port": cfg.Gateway.FixedPort, }) } func (s *Server) handleLogs(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]any{"items": s.logs.list()}) }