refactor api server around rpc services

This commit is contained in:
lpf
2026-03-15 01:00:41 +08:00
parent 341e578c9f
commit 231529e907
32 changed files with 5956 additions and 3614 deletions

View File

@@ -47,8 +47,53 @@ type DispatchPolicy struct {
var defaultManager = NewManager()
var nodeActionCapabilityChecks = map[string]func(Capabilities) bool{
"run": func(c Capabilities) bool { return c.Run },
"agent_task": func(c Capabilities) bool { return c.Model },
"camera_snap": func(c Capabilities) bool { return c.Camera },
"camera_clip": func(c Capabilities) bool { return c.Camera },
"screen_record": func(c Capabilities) bool { return c.Screen },
"screen_snapshot": func(c Capabilities) bool { return c.Screen },
"location_get": func(c Capabilities) bool { return c.Location },
"canvas_snapshot": func(c Capabilities) bool { return c.Canvas },
"canvas_action": func(c Capabilities) bool { return c.Canvas },
}
var realtimePreferredActions = map[string]struct{}{
"camera_snap": {},
"camera_clip": {},
"screen_record": {},
"screen_snapshot": {},
"canvas_snapshot": {},
"canvas_action": {},
}
var wireMessageHandlers = map[string]func(*Manager, WireMessage) bool{
"node_response": handleWireNodeResponse,
}
func DefaultManager() *Manager { return defaultManager }
func handleWireNodeResponse(m *Manager, msg WireMessage) bool {
if strings.TrimSpace(msg.ID) == "" {
return false
}
m.mu.Lock()
ch := m.pending[msg.ID]
if ch != nil {
delete(m.pending, msg.ID)
}
m.mu.Unlock()
if ch == nil {
return false
}
select {
case ch <- msg:
default:
}
return true
}
func NewManager() *Manager {
m := &Manager{
nodes: map[string]NodeInfo{},
@@ -199,28 +244,10 @@ func (m *Manager) RegisterWireSender(nodeID string, sender WireSender) {
}
func (m *Manager) HandleWireMessage(msg WireMessage) bool {
switch strings.ToLower(strings.TrimSpace(msg.Type)) {
case "node_response":
if strings.TrimSpace(msg.ID) == "" {
return false
}
m.mu.Lock()
ch := m.pending[msg.ID]
if ch != nil {
delete(m.pending, msg.ID)
}
m.mu.Unlock()
if ch == nil {
return false
}
select {
case ch <- msg:
default:
}
return true
default:
return false
if handler := wireMessageHandlers[strings.ToLower(strings.TrimSpace(msg.Type))]; handler != nil {
return handler(m, msg)
}
return false
}
func (m *Manager) SendWireRequest(ctx context.Context, nodeID string, req Request) (Response, error) {
@@ -314,22 +341,10 @@ func nodeSupportsRequest(n NodeInfo, req Request) bool {
return false
}
}
switch action {
case "run":
return n.Capabilities.Run
case "agent_task":
return n.Capabilities.Model
case "camera_snap", "camera_clip":
return n.Capabilities.Camera
case "screen_record", "screen_snapshot":
return n.Capabilities.Screen
case "location_get":
return n.Capabilities.Location
case "canvas_snapshot", "canvas_action":
return n.Capabilities.Canvas
default:
return n.Capabilities.Invoke
if check := nodeActionCapabilityChecks[action]; check != nil {
return check(n.Capabilities)
}
return n.Capabilities.Invoke
}
func (m *Manager) PickFor(action string) (NodeInfo, bool) {
@@ -595,12 +610,8 @@ func nodeHasAgent(n NodeInfo, agentID string) bool {
}
func prefersRealtimeTransport(action string) bool {
switch strings.ToLower(strings.TrimSpace(action)) {
case "camera_snap", "camera_clip", "screen_record", "screen_snapshot", "canvas_snapshot", "canvas_action":
return true
default:
return false
}
_, ok := realtimePreferredActions[strings.ToLower(strings.TrimSpace(action))]
return ok
}
func (m *Manager) reaperLoop() {

View File

@@ -111,31 +111,24 @@ type HTTPRelayTransport struct {
func (s *HTTPRelayTransport) Name() string { return "relay" }
var actionHTTPPaths = map[string]string{
"run": "/run",
"invoke": "/invoke",
"agent_task": "/agent/task",
"camera_snap": "/camera/snap",
"camera_clip": "/camera/clip",
"screen_record": "/screen/record",
"screen_snapshot": "/screen/snapshot",
"location_get": "/location/get",
"canvas_snapshot": "/canvas/snapshot",
"canvas_action": "/canvas/action",
}
func actionHTTPPath(action string) string {
switch strings.ToLower(strings.TrimSpace(action)) {
case "run":
return "/run"
case "invoke":
return "/invoke"
case "agent_task":
return "/agent/task"
case "camera_snap":
return "/camera/snap"
case "camera_clip":
return "/camera/clip"
case "screen_record":
return "/screen/record"
case "screen_snapshot":
return "/screen/snapshot"
case "location_get":
return "/location/get"
case "canvas_snapshot":
return "/canvas/snapshot"
case "canvas_action":
return "/canvas/action"
default:
return "/invoke"
if path := actionHTTPPaths[strings.ToLower(strings.TrimSpace(action))]; path != "" {
return path
}
return "/invoke"
}
func DoEndpointRequest(ctx context.Context, client *http.Client, endpoint, token string, req Request) (Response, error) {

View File

@@ -186,6 +186,23 @@ func (t *WebRTCTransport) currentSignaler(nodeID string) WireSender {
return t.signal[strings.TrimSpace(nodeID)]
}
var webRTCSignalHandlers = map[string]func(*gatewayRTCSession, WireMessage) error{
"signal_answer": func(session *gatewayRTCSession, msg WireMessage) error {
var desc webrtc.SessionDescription
if err := mapInto(msg.Payload, &desc); err != nil {
return err
}
return session.pc.SetRemoteDescription(desc)
},
"signal_candidate": func(session *gatewayRTCSession, msg WireMessage) error {
var candidate webrtc.ICECandidateInit
if err := mapInto(msg.Payload, &candidate); err != nil {
return err
}
return session.pc.AddICECandidate(candidate)
},
}
func (t *WebRTCTransport) HandleSignal(msg WireMessage) error {
nodeID := strings.TrimSpace(msg.From)
if nodeID == "" {
@@ -195,22 +212,10 @@ func (t *WebRTCTransport) HandleSignal(msg WireMessage) error {
if err != nil {
return err
}
switch strings.ToLower(strings.TrimSpace(msg.Type)) {
case "signal_answer":
var desc webrtc.SessionDescription
if err := mapInto(msg.Payload, &desc); err != nil {
return err
}
return session.pc.SetRemoteDescription(desc)
case "signal_candidate":
var candidate webrtc.ICECandidateInit
if err := mapInto(msg.Payload, &candidate); err != nil {
return err
}
return session.pc.AddICECandidate(candidate)
default:
return fmt.Errorf("unsupported signal type: %s", msg.Type)
if handler := webRTCSignalHandlers[strings.ToLower(strings.TrimSpace(msg.Type))]; handler != nil {
return handler(session, msg)
}
return fmt.Errorf("unsupported signal type: %s", msg.Type)
}
func (t *WebRTCTransport) Send(ctx context.Context, req Request) (Response, error) {