返回 DeepSeek-Reasonix
session_target_history_legacy.go
根目录 / desktop / session_target_history_legacy.go
1 package main
2
3 import (
4 "encoding/base64"
5 "encoding/json"
6 "fmt"
7 "strings"
8 )
9
10 type targetHistorySliceCursor struct {
11 V int `json:"v"`
12 Target string `json:"target"`
13 Cursor string `json:"cursor"`
14 }
15
16 func decodeTargetHistorySliceCursor(raw, target string) (string, error) {
17 raw = strings.TrimSpace(raw)
18 if raw == "" {
19 return "", nil
20 }
21 data, err := base64.RawURLEncoding.DecodeString(raw)
22 if err != nil {
23 return "", newSessionOperationError("stale_cursor", "The session content changed. Reload it and try again.")
24 }
25 var cursor targetHistorySliceCursor
26 if err := json.Unmarshal(data, &cursor); err != nil || cursor.V != 1 || cursor.Target != target {
27 return "", newSessionOperationError("stale_cursor", "The session content changed. Reload it and try again.")
28 }
29 return cursor.Cursor, nil
30 }
31
32 func encodeTargetHistorySliceCursor(target, cursor string) string {
33 if strings.TrimSpace(cursor) == "" {
34 return ""
35 }
36 data, err := json.Marshal(targetHistorySliceCursor{V: 1, Target: target, Cursor: cursor})
37 if err != nil {
38 return ""
39 }
40 return base64.RawURLEncoding.EncodeToString(data)
41 }
42
43 // HistorySliceForTarget reads a bounded history page for either a canonical or
44 // legacy local session without selecting it or creating a controller.
45 func (a *App) HistorySliceForTarget(selector SessionSelector, req HistorySliceRequest) (HistorySlice, error) {
46 target, err := a.resolveSessionTargetWithArchived(selector, true)
47 if err != nil {
48 return emptyHistorySlice(), err
49 }
50 targetKey := target.key()
51 req.Cursor, err = decodeTargetHistorySliceCursor(req.Cursor, targetKey)
52 if err != nil {
53 return emptyHistorySlice(), err
54 }
55 req = normalizeHistorySliceRequest(req)
56 if target.SessionRef.SessionID != "" {
57 page, err := a.canonicalHistorySlice(a.desktopSessionService("").Query(), target.SessionRef, "", "", req)
58 page.NextCursor = encodeTargetHistorySliceCursor(targetKey, page.NextCursor)
59 return page, err
60 }
61 dir, path, err := a.sessionDirForPath(target.SessionPath)
62 if err != nil {
63 return emptyHistorySlice(), newSessionOperationError(sessionOperationTargetNotFound, "The session no longer exists.")
64 }
65 page, err := a.coldHistorySlice(dir, path, req)
66 if err != nil {
67 if strings.Contains(strings.ToLower(err.Error()), "cursor") {
68 return emptyHistorySlice(), newSessionOperationError("stale_cursor", "The session content changed. Reload it and try again.")
69 }
70 return emptyHistorySlice(), err
71 }
72 page.NextCursor = encodeTargetHistorySliceCursor(targetKey, page.NextCursor)
73 return page, nil
74 }
75
76 // SearchHistoryContentForTarget searches the disposable legacy history index
77 // for one exact session. The cursor is bound to target, query, and index
78 // revision, so changing tabs or replaying a cursor against a sibling cannot
79 // change the routed object.
80 func (a *App) SearchHistoryContentForTarget(selector SessionSelector, query, cursor string, limit int) (HistorySearchPage, error) {
81 target, err := a.resolveSessionTargetWithArchived(selector, true)
82 if err != nil {
83 return HistorySearchPage{Items: []HistorySearchHit{}}, err
84 }
85 if target.SessionRef.SessionID != "" {
86 return HistorySearchPage{Items: []HistorySearchHit{}}, newSessionOperationError("unsupported", "Use canonical session search for this session.")
87 }
88 _, path, err := a.sessionDirForPath(target.SessionPath)
89 if err != nil {
90 return HistorySearchPage{Items: []HistorySearchHit{}}, newSessionOperationError(sessionOperationTargetNotFound, "The session no longer exists.")
91 }
92 out := a.searchHistorySnapshot(HistorySearchRequest{Query: query, Cursor: cursor, Limit: limit}, path)
93 if out.StaleCursor {
94 return out, snapshotStale("snapshot_unavailable")
95 }
96 if out.ReadError != nil {
97 return out, fmt.Errorf("%s", out.ReadError.Message)
98 }
99 return out, nil
100 }
101
101 lines GO