1package content
2
3import (
4 "sync"
5
6 "github.com/bnema/dumber/internal/application/port"
7 "github.com/bnema/dumber/internal/domain/entity"
8)
9
10type namedBrowsingContextKey struct {
11 OwnerWindowID string
12 Name string
13}
14
15type namedBrowsingContextState struct {
16 PaneID entity.PaneID
17 WebViewID port.WebViewID
18 HostWindowID string
19}
20
21type namedBrowsingContextRegistry struct {
22 mu sync.RWMutex
23 contexts map[namedBrowsingContextKey]namedBrowsingContextState
24}
25
26func newNamedBrowsingContextRegistry() *namedBrowsingContextRegistry {
27 return &namedBrowsingContextRegistry{
28 contexts: make(map[namedBrowsingContextKey]namedBrowsingContextState),
29 }
30}
31
32func (r *namedBrowsingContextRegistry) Register(ownerWindowID, hostWindowID, name string, paneID entity.PaneID, webViewID port.WebViewID) {
33 if r == nil || ownerWindowID == "" || hostWindowID == "" || name == "" || paneID == "" || webViewID == 0 {
34 return
35 }
36 r.mu.Lock()
37 r.contexts[namedBrowsingContextKey{OwnerWindowID: ownerWindowID, Name: name}] = namedBrowsingContextState{
38 PaneID: paneID, WebViewID: webViewID, HostWindowID: hostWindowID,
39 }
40 r.mu.Unlock()
41}
42
43func (r *namedBrowsingContextRegistry) Lookup(
44 windowID, name string,
45 lookupWebView func(entity.PaneID) port.WebView,
46 resolveWindowID func(entity.PaneID) (string, bool),
47) (namedBrowsingContextState, port.WebView, bool) {
48 if r == nil || windowID == "" || name == "" || lookupWebView == nil || resolveWindowID == nil {
49 return namedBrowsingContextState{}, nil, false
50 }
51
52 key := namedBrowsingContextKey{OwnerWindowID: windowID, Name: name}
53 r.mu.RLock()
54 state, ok := r.contexts[key]
55 r.mu.RUnlock()
56 if !ok {
57 return namedBrowsingContextState{}, nil, false
58 }
59
60 currentWindowID, ok := resolveWindowID(state.PaneID)
61 if !ok || currentWindowID != state.HostWindowID {
62 r.deleteIfStateMatches(key, state)
63 return namedBrowsingContextState{}, nil, false
64 }
65
66 wv := lookupWebView(state.PaneID)
67 if wv == nil || wv.IsDestroyed() || wv.ID() != state.WebViewID {
68 r.deleteIfStateMatches(key, state)
69 return namedBrowsingContextState{}, nil, false
70 }
71
72 return state, wv, true
73}
74
75func (r *namedBrowsingContextRegistry) deleteIfStateMatches(key namedBrowsingContextKey, state namedBrowsingContextState) {
76 if r == nil {
77 return
78 }
79 r.mu.Lock()
80 if currentState, ok := r.contexts[key]; ok && currentState == state {
81 delete(r.contexts, key)
82 }
83 r.mu.Unlock()
84}
85
86func (r *namedBrowsingContextRegistry) UnregisterByPaneID(paneID entity.PaneID) {
87 if r == nil || paneID == "" {
88 return
89 }
90 r.mu.Lock()
91 for key, state := range r.contexts {
92 if state.PaneID == paneID {
93 delete(r.contexts, key)
94 }
95 }
96 r.mu.Unlock()
97}
98
99func (r *namedBrowsingContextRegistry) UnregisterByWebViewID(webViewID port.WebViewID) {
100 if r == nil || webViewID == 0 {
101 return
102 }
103 r.mu.Lock()
104 for key, state := range r.contexts {
105 if state.WebViewID == webViewID {
106 delete(r.contexts, key)
107 }
108 }
109 r.mu.Unlock()
110}
111
112func (r *namedBrowsingContextRegistry) UnregisterWindow(windowID string) {
113 if r == nil || windowID == "" {
114 return
115 }
116 r.mu.Lock()
117 for key, state := range r.contexts {
118 if key.OwnerWindowID == windowID || state.HostWindowID == windowID {
119 delete(r.contexts, key)
120 }
121 }
122 r.mu.Unlock()
123}