返回 DeepSeek-Reasonix
tabs_persistence_io.go
根目录 / desktop / tabs_persistence_io.go
1 package main
2
3 import (
4 "encoding/json"
5 "errors"
6 "os"
7 "path/filepath"
8
9 "reasonix/internal/fileutil"
10 )
11
12 var errTabsSnapshotChanged = errors.New("desktop tabs changed during startup reconciliation")
13
14 func (a *App) loadTabsForRestore() (desktopTabsFile, uint64) {
15 version := a.tabsSnapshotVersion()
16 file := loadTabsFile()
17 a.rememberTabsFileExtra(file.extra)
18 return file, version
19 }
20
21 // saveTabsWrite writes the tab snapshot outside a.mu. tabsSaveMu serializes
22 // writes because every save shares one destination and fixed temporary path.
23 func (a *App) saveTabsWrite(dir string, entries []desktopTabEntry, activeID string, version uint64) {
24 a.tabsSaveMu.Lock()
25 defer a.tabsSaveMu.Unlock()
26 if version < a.tabsLastWrittenVersion {
27 return
28 }
29 localIDs := make([]string, 0, len(entries))
30 for _, entry := range entries {
31 localIDs = append(localIDs, entry.ID)
32 }
33 remoteEntries, remoteOrder, tabOrder, remoteActive := a.remoteTabsFileEntries(localIDs)
34 if remoteActive != "" {
35 activeID = remoteActive
36 }
37 file := desktopTabsFile{
38 Tabs: entries, ActiveTab: activeID, RemoteTabs: remoteEntries,
39 RemoteTabOrder: remoteOrder, TabOrder: tabOrder,
40 extra: cloneDesktopJSONFields(a.tabsFileExtra),
41 }
42 _ = a.writeTabsFileLocked(dir, file, version)
43 }
44
45 func (a *App) rememberTabsFileExtra(extra map[string]json.RawMessage) {
46 a.tabsSaveMu.Lock()
47 a.tabsFileExtra = cloneDesktopJSONFields(extra)
48 a.tabsSaveMu.Unlock()
49 }
50
51 func (a *App) tabsSnapshotVersion() uint64 {
52 a.mu.RLock()
53 defer a.mu.RUnlock()
54 return a.tabsSaveVersion
55 }
56
57 func (a *App) tabsSnapshotCurrent(version uint64) bool {
58 a.mu.RLock()
59 defer a.mu.RUnlock()
60 return a.tabsSaveVersion == version
61 }
62
63 func (a *App) persistReconciledTabsFile(file desktopTabsFile, expectedVersion uint64) (uint64, error) {
64 a.mu.Lock()
65 if a.tabsSaveVersion != expectedVersion {
66 a.mu.Unlock()
67 return 0, errTabsSnapshotChanged
68 }
69 a.tabsSaveVersion++
70 version := a.tabsSaveVersion
71 a.mu.Unlock()
72
73 a.tabsSaveMu.Lock()
74 defer a.tabsSaveMu.Unlock()
75 if version < a.tabsLastWrittenVersion {
76 return 0, errTabsSnapshotChanged
77 }
78 file.extra = cloneDesktopJSONFields(a.tabsFileExtra)
79 if err := a.writeTabsFileLocked(desktopConfigDir(), file, version); err != nil {
80 return version, err
81 }
82 return version, nil
83 }
84
85 // writeTabsFileLocked writes an already-reconciled snapshot under tabsSaveMu.
86 func (a *App) writeTabsFileLocked(dir string, file desktopTabsFile, version uint64) error {
87 if err := os.MkdirAll(dir, 0o755); err != nil {
88 return err
89 }
90 body, err := json.MarshalIndent(file, "", " ")
91 if err != nil {
92 return err
93 }
94 path := filepath.Join(dir, tabsFileName)
95 tmp := path + ".tmp"
96 if err := os.WriteFile(tmp, body, 0o644); err != nil {
97 return err
98 }
99 if err := fileutil.ReplaceFile(tmp, path); err != nil {
100 return err
101 }
102 a.tabsLastWrittenVersion = version
103 return nil
104 }
105
105 lines GO