返回 DeepSeek-Reasonix
inbox_queue.go
根目录 / desktop / inbox_queue.go
1 package main
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "net/http"
8
9 "reasonix/internal/control"
10 "reasonix/internal/servecontract"
11 "reasonix/internal/sessioninbox"
12 )
13
14 type InboxQueueResultView struct {
15 Outcome string `json:"outcome"`
16 Reason string `json:"reason,omitempty"`
17 Snapshot InboxSnapshotView `json:"snapshot"`
18 Edit *control.InboxQueueEdit `json:"edit,omitempty"`
19 Receipt *sessioninbox.InboxReceipt `json:"receipt,omitempty"`
20 }
21
22 // InboxQueueForTarget is additive and never falls back from remote to local.
23 func (a *App) InboxQueueForTarget(target InboxTargetView, request control.InboxQueueRequest) (InboxQueueResultView, error) {
24 if target.Remote {
25 return a.remoteInboxQueue(target, request)
26 }
27 a.runtimeAdmissionMu.RLock()
28 defer a.runtimeAdmissionMu.RUnlock()
29 current, err := a.captureInboxTarget(target.TabID, target.SessionPath)
30 if err != nil || current != target {
31 return InboxQueueResultView{Outcome: "unavailable", Reason: "session_changed"}, nil
32 }
33 ctrl, err := a.inboxCtrl(target.TabID)
34 if err != nil {
35 return InboxQueueResultView{}, err
36 }
37 api, ok := ctrl.(interface {
38 InboxQueue(string, control.InboxQueueRequest) (control.InboxQueueResult, error)
39 })
40 if !ok {
41 return InboxQueueResultView{Outcome: "unavailable", Reason: "unsupported"}, nil
42 }
43 result, err := api.InboxQueue(target.SessionPath, request)
44 if err != nil {
45 return InboxQueueResultView{}, inboxBridgeError(err)
46 }
47 return inboxQueueView(result), nil
48 }
49
50 func inboxQueueView(result control.InboxQueueResult) InboxQueueResultView {
51 return InboxQueueResultView{Outcome: result.Outcome, Reason: result.Reason, Snapshot: inboxSnapshotView(result.Snapshot), Edit: result.Edit, Receipt: result.Receipt}
52 }
53
54 func (a *App) remoteInboxQueue(target InboxTargetView, request control.InboxQueueRequest) (InboxQueueResultView, error) {
55 client, base, err := a.remoteInboxTarget(target)
56 if err != nil {
57 return InboxQueueResultView{Outcome: "unavailable", Reason: "session_changed"}, nil
58 }
59 a.remoteTabMu.Lock()
60 tab := a.remoteTabs[target.TabID]
61 supported := tab != nil && tab.capabilities[servecontract.InboxMutationsV1]
62 a.remoteTabMu.Unlock()
63 if !supported {
64 return InboxQueueResultView{Outcome: "unavailable", Reason: "unsupported"}, nil
65 }
66 body, err := json.Marshal(map[string]any{"sessionPath": target.SessionPath, "request": request})
67 if err != nil {
68 return InboxQueueResultView{}, err
69 }
70 ctx, cancel := commandContext(a)
71 defer cancel()
72 response, err := serveDoForSession(ctx, client, http.MethodPost, serveURL(base, "/inbox/queue"), body, target.SessionPath)
73 if err != nil {
74 return InboxQueueResultView{}, err
75 }
76 defer response.Body.Close()
77 if response.StatusCode == http.StatusConflict {
78 return InboxQueueResultView{Outcome: "unavailable", Reason: "session_changed"}, nil
79 }
80 if response.StatusCode < 200 || response.StatusCode >= 300 {
81 return InboxQueueResultView{}, fmt.Errorf("remote inbox operation failed (%d)", response.StatusCode)
82 }
83 var result control.InboxQueueResult
84 if err := json.NewDecoder(io.LimitReader(response.Body, 8<<20)).Decode(&result); err != nil {
85 return InboxQueueResultView{}, err
86 }
87 currentClient, currentBase, err := a.remoteInboxTarget(target)
88 if err != nil || currentClient != client || currentBase != base {
89 return InboxQueueResultView{Outcome: "unavailable", Reason: "session_changed"}, nil
90 }
91 return inboxQueueView(result), nil
92 }
93
93 lines GO