mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-14 02:37:29 +08:00
270 lines
8.6 KiB
Go
270 lines
8.6 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
|
|
rpcpkg "github.com/YspCoder/clawgo/pkg/rpc"
|
|
)
|
|
|
|
func (s *Server) handleNodeRPC(w http.ResponseWriter, r *http.Request) {
|
|
s.handleRPC(w, r, s.nodeRPCRegistry())
|
|
}
|
|
|
|
func (s *Server) handleProviderRPC(w http.ResponseWriter, r *http.Request) {
|
|
s.handleRPC(w, r, s.providerRPCRegistry())
|
|
}
|
|
|
|
func (s *Server) handleWorkspaceRPC(w http.ResponseWriter, r *http.Request) {
|
|
s.handleRPC(w, r, s.workspaceRPCRegistry())
|
|
}
|
|
|
|
func (s *Server) handleConfigRPC(w http.ResponseWriter, r *http.Request) {
|
|
s.handleRPC(w, r, s.configRPCRegistry())
|
|
}
|
|
|
|
func (s *Server) handleCronRPC(w http.ResponseWriter, r *http.Request) {
|
|
s.handleRPC(w, r, s.cronRPCRegistry())
|
|
}
|
|
|
|
func (s *Server) handleSkillsRPC(w http.ResponseWriter, r *http.Request) {
|
|
s.handleRPC(w, r, s.skillsRPCRegistry())
|
|
}
|
|
|
|
func (s *Server) handleRPC(w http.ResponseWriter, r *http.Request, registry *rpcpkg.Registry) {
|
|
if !s.checkAuth(r) {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
var req rpcpkg.Request
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeRPCError(w, http.StatusBadRequest, req.RequestID, rpcError("invalid_argument", "invalid json", nil, false))
|
|
return
|
|
}
|
|
result, rpcErr := registry.Handle(r.Context(), req)
|
|
if rpcErr != nil {
|
|
writeRPCError(w, rpcHTTPStatus(rpcErr), req.RequestID, rpcErr)
|
|
return
|
|
}
|
|
writeJSON(w, rpcpkg.Response{
|
|
OK: true,
|
|
Result: result,
|
|
RequestID: strings.TrimSpace(req.RequestID),
|
|
})
|
|
}
|
|
|
|
func (s *Server) buildNodeRegistry() *rpcpkg.Registry {
|
|
svc := s.nodeRPCService()
|
|
reg := rpcpkg.NewRegistry()
|
|
rpcpkg.RegisterJSON(reg, "node.register", func(ctx context.Context, req rpcpkg.RegisterNodeRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Register(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "node.heartbeat", func(ctx context.Context, req rpcpkg.HeartbeatNodeRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Heartbeat(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "node.dispatch", func(ctx context.Context, req rpcpkg.DispatchNodeRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Dispatch(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "node.artifact.list", func(ctx context.Context, req rpcpkg.ListNodeArtifactsRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.ListArtifacts(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "node.artifact.get", func(ctx context.Context, req rpcpkg.GetNodeArtifactRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.GetArtifact(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "node.artifact.delete", func(ctx context.Context, req rpcpkg.DeleteNodeArtifactRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.DeleteArtifact(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "node.artifact.prune", func(ctx context.Context, req rpcpkg.PruneNodeArtifactsRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.PruneArtifacts(ctx, req)
|
|
})
|
|
return reg
|
|
}
|
|
|
|
func (s *Server) nodeRPCRegistry() *rpcpkg.Registry {
|
|
if s == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
s.nodeRPCOnce.Do(func() {
|
|
s.nodeRPCReg = s.buildNodeRegistry()
|
|
})
|
|
if s.nodeRPCReg == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
return s.nodeRPCReg
|
|
}
|
|
|
|
func (s *Server) buildProviderRegistry() *rpcpkg.Registry {
|
|
svc := s.providerRPCService()
|
|
reg := rpcpkg.NewRegistry()
|
|
rpcpkg.RegisterJSON(reg, "provider.list_models", func(ctx context.Context, req rpcpkg.ListProviderModelsRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.ListModels(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "provider.models.update", func(ctx context.Context, req rpcpkg.UpdateProviderModelsRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.UpdateModels(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "provider.chat", func(ctx context.Context, req rpcpkg.ProviderChatRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Chat(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "provider.count_tokens", func(ctx context.Context, req rpcpkg.ProviderCountTokensRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.CountTokens(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "provider.runtime.view", func(ctx context.Context, req rpcpkg.ProviderRuntimeViewRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.RuntimeView(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "provider.runtime.action", func(ctx context.Context, req rpcpkg.ProviderRuntimeActionRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.RuntimeAction(ctx, req)
|
|
})
|
|
return reg
|
|
}
|
|
|
|
func (s *Server) providerRPCRegistry() *rpcpkg.Registry {
|
|
if s == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
s.providerRPCOnce.Do(func() {
|
|
s.providerRPCReg = s.buildProviderRegistry()
|
|
})
|
|
if s.providerRPCReg == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
return s.providerRPCReg
|
|
}
|
|
|
|
func (s *Server) buildWorkspaceRegistry() *rpcpkg.Registry {
|
|
svc := s.workspaceRPCService()
|
|
reg := rpcpkg.NewRegistry()
|
|
rpcpkg.RegisterJSON(reg, "workspace.list_files", func(ctx context.Context, req rpcpkg.ListWorkspaceFilesRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.ListFiles(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "workspace.read_file", func(ctx context.Context, req rpcpkg.ReadWorkspaceFileRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.ReadFile(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "workspace.write_file", func(ctx context.Context, req rpcpkg.WriteWorkspaceFileRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.WriteFile(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "workspace.delete_file", func(ctx context.Context, req rpcpkg.DeleteWorkspaceFileRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.DeleteFile(ctx, req)
|
|
})
|
|
return reg
|
|
}
|
|
|
|
func (s *Server) workspaceRPCRegistry() *rpcpkg.Registry {
|
|
if s == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
s.workspaceRPCOnce.Do(func() {
|
|
s.workspaceRPCReg = s.buildWorkspaceRegistry()
|
|
})
|
|
if s.workspaceRPCReg == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
return s.workspaceRPCReg
|
|
}
|
|
|
|
func (s *Server) buildConfigRegistry() *rpcpkg.Registry {
|
|
svc := s.configRPCService()
|
|
reg := rpcpkg.NewRegistry()
|
|
rpcpkg.RegisterJSON(reg, "config.view", func(ctx context.Context, req rpcpkg.ConfigViewRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.View(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "config.save", func(ctx context.Context, req rpcpkg.ConfigSaveRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Save(ctx, req)
|
|
})
|
|
return reg
|
|
}
|
|
|
|
func (s *Server) configRPCRegistry() *rpcpkg.Registry {
|
|
if s == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
s.configRPCOnce.Do(func() {
|
|
s.configRPCReg = s.buildConfigRegistry()
|
|
})
|
|
if s.configRPCReg == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
return s.configRPCReg
|
|
}
|
|
|
|
func (s *Server) buildCronRegistry() *rpcpkg.Registry {
|
|
svc := s.cronRPCService()
|
|
reg := rpcpkg.NewRegistry()
|
|
rpcpkg.RegisterJSON(reg, "cron.list", func(ctx context.Context, req rpcpkg.ListCronJobsRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.List(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "cron.get", func(ctx context.Context, req rpcpkg.GetCronJobRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Get(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "cron.mutate", func(ctx context.Context, req rpcpkg.MutateCronJobRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Mutate(ctx, req)
|
|
})
|
|
return reg
|
|
}
|
|
|
|
func (s *Server) cronRPCRegistry() *rpcpkg.Registry {
|
|
if s == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
s.cronRPCOnce.Do(func() {
|
|
s.cronRPCReg = s.buildCronRegistry()
|
|
})
|
|
if s.cronRPCReg == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
return s.cronRPCReg
|
|
}
|
|
|
|
func (s *Server) buildSkillsRegistry() *rpcpkg.Registry {
|
|
svc := s.skillsRPCService()
|
|
reg := rpcpkg.NewRegistry()
|
|
rpcpkg.RegisterJSON(reg, "skills.view", func(ctx context.Context, req rpcpkg.SkillsViewRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.View(ctx, req)
|
|
})
|
|
rpcpkg.RegisterJSON(reg, "skills.mutate", func(ctx context.Context, req rpcpkg.SkillsMutateRequest) (interface{}, *rpcpkg.Error) {
|
|
return svc.Mutate(ctx, req)
|
|
})
|
|
return reg
|
|
}
|
|
|
|
func (s *Server) skillsRPCRegistry() *rpcpkg.Registry {
|
|
if s == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
s.skillsRPCOnce.Do(func() {
|
|
s.skillsRPCReg = s.buildSkillsRegistry()
|
|
})
|
|
if s.skillsRPCReg == nil {
|
|
return rpcpkg.NewRegistry()
|
|
}
|
|
return s.skillsRPCReg
|
|
}
|
|
|
|
func writeRPCError(w http.ResponseWriter, status int, requestID string, rpcErr *rpcpkg.Error) {
|
|
if rpcErr == nil {
|
|
rpcErr = rpcError("internal", "rpc error", nil, false)
|
|
}
|
|
writeJSONStatus(w, status, rpcpkg.Response{
|
|
OK: false,
|
|
Error: rpcErr,
|
|
RequestID: strings.TrimSpace(requestID),
|
|
})
|
|
}
|
|
|
|
|
|
func mustJSONMarshal(value interface{}) json.RawMessage {
|
|
if value == nil {
|
|
return json.RawMessage([]byte("{}"))
|
|
}
|
|
data, err := json.Marshal(value)
|
|
if err != nil {
|
|
return json.RawMessage([]byte("{}"))
|
|
}
|
|
return data
|
|
}
|