返回 DeepSeek-Reasonix
session_export_diagnostics.go
根目录 / desktop / session_export_diagnostics.go
1 package main
2
3 import (
4 "encoding/json"
5 "errors"
6 "io"
7 "net/http"
8 "os"
9
10 "reasonix/desktop/internal/hostrpc"
11 "reasonix/internal/control"
12 "reasonix/internal/servecontract"
13 "reasonix/internal/session"
14 )
15
16 func (a *App) writeSessionDiagnosticExport(job *sessionExportJob) error {
17 extra := map[string]any{"sessionIdentity": map[string]any{"session": job.handle.Snapshot.Ref, "source": "local", "workspaceRoot": job.workspaceRoot, "storageGeneration": job.handle.Snapshot.StorageGeneration}, "exportSnapshot": job.handle.Snapshot, "frontendObservation": job.observation}
18 var frontend map[string]json.RawMessage
19 _ = json.Unmarshal(job.observation, &frontend)
20 if value := frontend["readDiagnostics"]; len(value) > 0 {
21 extra["readDiagnostics"] = value
22 }
23 if len(job.observation) == 0 {
24 extra["frontendObservation"] = nil
25 }
26 return writeGoalDiagnosticsFile(job.path, func(dst io.Writer) error {
27 if job.client != nil {
28 extra["sessionIdentity"] = map[string]any{"session": job.handle.Snapshot.Ref, "source": "remote", "connectionHostId": job.sourceHostID, "workspaceRoot": job.workspaceRoot, "storageGeneration": job.handle.Snapshot.StorageGeneration}
29 body, _ := json.Marshal(extra)
30 resp, err := serveDoForSession(job.ctx, job.client, http.MethodPost, sessionExportURL(job.base, "/session-export/diagnostic", job.handle.Snapshot.Ref.SessionID, false), body, job.route)
31 if err != nil {
32 return err
33 }
34 defer resp.Body.Close()
35 if resp.StatusCode != http.StatusOK {
36 return errors.New("remote session diagnostics are unavailable; upgrade the remote service if the session was switched or taken over")
37 }
38 _, err = io.Copy(dst, resp.Body)
39 return err
40 }
41 metadata := control.GoalDiagnosticMetadata{ApplicationVersion: version, BuildCommit: buildCommit(), ProtocolVersion: hostrpc.ProtocolVersion, Capabilities: []string{servecontract.SessionExportV1, servecontract.GoalLifecycleV2}}
42 if a.sessionDiagnosticControllerCurrent(job.controller, job.handle.Snapshot.Ref) {
43 runtimeErr := job.controller.WriteSessionDiagnostics(job.ctx, dst, metadata, extra)
44 if a.sessionDiagnosticControllerCurrent(job.controller, job.handle.Snapshot.Ref) {
45 return runtimeErr
46 }
47 file, ok := dst.(*os.File)
48 if !ok {
49 return errors.Join(runtimeErr, errors.New("session controller changed during diagnostic capture"))
50 }
51 if resetErr := file.Truncate(0); resetErr != nil {
52 return errors.Join(runtimeErr, resetErr)
53 }
54 if _, resetErr := file.Seek(0, io.SeekStart); resetErr != nil {
55 return errors.Join(runtimeErr, resetErr)
56 }
57 }
58 return control.WriteColdSessionDiagnostics(job.ctx, dst, job.query, job.handle.Snapshot, metadata, extra)
59 })
60 }
61
62 func (a *App) sessionDiagnosticControllerCurrent(controller *control.Controller, ref session.SessionRef) bool {
63 if controller == nil {
64 return false
65 }
66 boundRef, bound := controller.SessionRef()
67 if !bound || boundRef != ref {
68 return false
69 }
70 a.mu.RLock()
71 defer a.mu.RUnlock()
72 for _, tab := range a.tabs {
73 if !tab.removed && tab.Ctrl == controller && tab.SessionID == ref.SessionID {
74 return true
75 }
76 }
77 return false
78 }
79
79 lines GO