返回 DeepSeek-Reasonix
file_browser_preview_registry.go
根目录 / desktop / file_browser_preview_registry.go
1 package main
2
3 import (
4 "errors"
5 "sync"
6 )
7
8 // Lifecycle cleanup takes only mu, never operations. Browser RPC may reenter
9 // App, so operations must never be acquired while App.mu is held.
10 type fileBrowserPreviewRegistry struct {
11 mu sync.Mutex
12 operations sync.Mutex
13 bindings map[string]fileBrowserPreviewBinding
14 pending *fileBrowserPreviewOperation
15 }
16
17 type fileBrowserPreviewOperation struct {
18 key string
19 preview fileBrowserPreviewBinding
20 previousURL string
21 revoked bool // guarded by registry.mu
22 }
23
24 func (r *fileBrowserPreviewRegistry) begin(key string, prepared preparedFileBrowserPreview) (*fileBrowserPreviewOperation, fileBrowserPreviewBinding, bool) {
25 r.mu.Lock()
26 defer r.mu.Unlock()
27 binding, reusable := r.bindings[key]
28 op := &fileBrowserPreviewOperation{key: key, previousURL: binding.URL,
29 preview: fileBrowserPreviewBinding{BrowserTabID: binding.BrowserTabID, URL: prepared.url, release: prepared.release}}
30 r.pending = op
31 return op, binding, reusable
32 }
33
34 func (r *fileBrowserPreviewRegistry) end(op *fileBrowserPreviewOperation) {
35 r.mu.Lock()
36 if r.pending == op {
37 r.pending = nil
38 }
39 r.mu.Unlock()
40 }
41
42 func (r *fileBrowserPreviewRegistry) retire(key, rawURL string) {
43 r.mu.Lock()
44 defer r.mu.Unlock()
45 if binding, ok := r.bindings[key]; ok && binding.URL == rawURL {
46 delete(r.bindings, key)
47 binding.release()
48 }
49 }
50
51 // Publish under the same App -> registry order as tab removal. A late host
52 // reply can neither resurrect a removed binding nor attach to a new session.
53 func (a *App) publishFileBrowserPreview(tab *WorkspaceTab, generation uint64, key string, op *fileBrowserPreviewOperation, binding fileBrowserPreviewBinding) error {
54 a.mu.RLock()
55 defer a.mu.RUnlock()
56 r := &a.filePreviews
57 r.mu.Lock()
58 defer r.mu.Unlock()
59 if a.tabs[tab.ID] != tab || tab.removed || tab.SessionGeneration != generation || op.revoked {
60 return errors.New("the session changed before the preview opened")
61 }
62 if r.bindings == nil {
63 r.bindings = make(map[string]fileBrowserPreviewBinding)
64 }
65 r.bindings[key] = binding
66 return nil
67 }
68
69 // Release handles were captured when this app minted the resource. Revoking
70 // them is in-memory and cannot reacquire App.mu or wait for a browser request.
71 func (r *fileBrowserPreviewRegistry) releaseMatching(match func(string, fileBrowserPreviewBinding) bool) {
72 r.mu.Lock()
73 defer r.mu.Unlock()
74 for key, binding := range r.bindings {
75 if match(key, binding) {
76 delete(r.bindings, key)
77 if binding.release != nil {
78 binding.release()
79 }
80 }
81 }
82 if op := r.pending; op != nil {
83 previous := op.preview
84 previous.URL = op.previousURL
85 if match(op.key, op.preview) || match(op.key, previous) {
86 op.revoked = true
87 op.preview.release()
88 }
89 }
90 }
91
91 lines GO