返回 DeepSeek-Reasonix
remote_session_organization.go
根目录 / desktop / remote_session_organization.go
1 package main
2
3 import (
4 "encoding/json"
5 "fmt"
6 "reasonix/desktop/internal/workspacestate"
7 "reasonix/internal/config"
8 "slices"
9 )
10
11 // Organization belongs to the existing desktop remote-settings owner. Reads
12 // never start Serve or open a connection. Host and workspace both scope the CAS.
13 func (a *App) remoteSessionOrganization(w SessionOrganizationWorkspace, revision *uint64, mutation *SessionOrganizationMutation) (SessionOrganizationSnapshot, error) {
14 var result SessionOrganizationSnapshot
15 keyOf := func(selector *SessionSelector) (string, error) {
16 if selector == nil {
17 return "", fmt.Errorf("session target is required")
18 }
19 if selector.Ref != nil && selector.Ref.HostID == w.HostID && selector.Ref.SessionID != "" {
20 return "ref\x00" + w.HostID + "\x00" + selector.Ref.SessionID, nil
21 }
22 if selector.Source != nil && selector.Source.HostID == w.HostID && selector.Source.Path != "" {
23 return "source\x00" + w.HostID + "\x00" + w.WorkspaceRoot + "\x00" + selector.Source.Path, nil
24 }
25 return "", newSessionOperationError("target_changed", "The session belongs to a different host.")
26 }
27 key, anchor := "", ""
28 if mutation != nil && (mutation.Kind == "move" || mutation.Kind == "set-group") {
29 var err error
30 key, err = keyOf(mutation.Target)
31 if err != nil {
32 return result, err
33 }
34 if mutation.Kind == "move" {
35 anchor, err = keyOf(mutation.Anchor)
36 if err != nil {
37 return result, err
38 }
39 }
40 rows, err := a.RemoteProjectSessions(w.HostID, w.WorkspaceRoot)
41 if err != nil {
42 return result, err
43 }
44 known := map[string]bool{}
45 for _, row := range rows {
46 if row.SessionID != "" {
47 known["ref\x00"+w.HostID+"\x00"+row.SessionID] = true
48 }
49 known["source\x00"+w.HostID+"\x00"+w.WorkspaceRoot+"\x00"+row.Path] = true
50 }
51 if !known[key] || (anchor != "" && !known[anchor]) {
52 return result, newSessionOperationError("target_not_found", "The remote session is no longer available.")
53 }
54 }
55 read := func(c *config.Config) (bool, error) {
56 for i := range c.Remote.Projects {
57 p := &c.Remote.Projects[i]
58 if p.HostID != w.HostID || p.Workspace != w.WorkspaceRoot {
59 continue
60 }
61 var changed bool
62 var err error
63 result, changed, err = mutateRemoteOrganization(p, revision, mutation, key, anchor)
64 return changed, err
65 }
66 return false, newSessionOperationError("target_not_found", "This remote workspace is no longer pinned.")
67 }
68 if mutation == nil {
69 c, err := config.Load()
70 if err != nil {
71 return result, err
72 }
73 _, err = read(c)
74 return result, err
75 }
76 err := editUserConfigIfChanged(read)
77 if err == nil && result.Applied {
78 a.emitProjectTreeMetadataChanged()
79 }
80 return result, err
81 }
82
83 func mutateRemoteOrganization(p *config.RemoteProjectEntry, revision *uint64, mutation *SessionOrganizationMutation, key, anchor string) (SessionOrganizationSnapshot, bool, error) {
84 o := workspacestate.Organization{Order: []string{}, Groups: []workspacestate.OrganizationGroup{}, Imported: map[string]bool{}, MigrationVersion: 1}
85 if p.SessionOrganization != "" {
86 if err := json.Unmarshal([]byte(p.SessionOrganization), &o); err != nil {
87 return SessionOrganizationSnapshot{}, false, err
88 }
89 }
90 if o.Imported == nil {
91 o.Imported = map[string]bool{}
92 }
93 result := organizationSnapshot(o, mutation == nil)
94 if mutation == nil || revision == nil || o.Revision != *revision {
95 return result, false, nil
96 }
97 for _, k := range []string{key, anchor} {
98 if k != "" {
99 o.Imported[k] = true
100 if !slices.Contains(o.Order, k) {
101 o.Order = append(o.Order, k)
102 }
103 }
104 }
105 if err := applyOrganizationMutation(&o, *mutation, key, anchor); err != nil {
106 return SessionOrganizationSnapshot{}, false, err
107 }
108 o.Revision++
109 body, err := json.Marshal(o)
110 if err != nil {
111 return SessionOrganizationSnapshot{}, false, err
112 }
113 p.SessionOrganization = string(body)
114 result = organizationSnapshot(o, true)
115 return result, true, nil
116 }
117
117 lines GO