attachment_routes.go RawHistoryFolder

1package client
2
3import (
4	"github.com/bnema/vev/internal/domain"
5	"github.com/bnema/vev/internal/protocol"
6)
7
8// Route publication and daemon navigation seams of the attached foreground.
9// The worker owns the stream, so the supervisor reaches the
10// daemon only through these bounded channels: the newest route snapshot
11// replaces an unsent one, and navigation failures are dropped rather than
12// blocking when the worker is gone. In the other direction the worker hands
13// every daemon navigation request to the supervisor, which resolves it
14// through the broker catalogue exactly like a picker commit.
15
16// attachmentReplyCapacity bounds queued navigation failures per foreground.
17const attachmentReplyCapacity = 4
18
19// demandRoutes wakes the supervisor to republish routes for this foreground.
20func (f *attachmentForeground) demandRoutes() {
21	if f == nil || f.host == nil || !f.authority.actionAuthorized(f) {
22		return
23	}
24	select {
25	case f.host.routeDemand <- struct{}{}:
26	default:
27	}
28}
29
30func (f *attachmentForeground) routeSnapshots() <-chan protocol.RecentRouteSnapshot {
31	if f == nil {
32		return nil
33	}
34	return f.routes
35}
36
37func (f *attachmentForeground) navigationReplies() <-chan protocol.ClientMessage {
38	if f == nil {
39		return nil
40	}
41	return f.replies
42}
43
44// requestNavigation hands one daemon navigation request to the supervisor.
45// The newest request replaces one the supervisor has not taken yet.
46func (f *attachmentForeground) requestNavigation(message protocol.ServerMessage) {
47	if f == nil || f.host == nil || !f.authority.actionAuthorized(f) {
48		return
49	}
50	for {
51		select {
52		case f.host.navigations <- message:
53			return
54		default:
55		}
56		select {
57		case <-f.host.navigations:
58		default:
59		}
60	}
61}
62
63// RouteDemands wakes the supervisor when the attached session changed.
64func (h *attachmentHost) RouteDemands() <-chan struct{} {
65	if h == nil {
66		return nil
67	}
68	return h.routeDemand
69}
70
71// Navigations carries the daemon's navigation requests to the supervisor.
72func (h *attachmentHost) Navigations() <-chan protocol.ServerMessage {
73	if h == nil {
74		return nil
75	}
76	return h.navigations
77}
78
79// takeNavigation returns a navigation request left behind by a worker that
80// already settled, if any.
81func (h *attachmentHost) takeNavigation() (protocol.ServerMessage, bool) {
82	if h == nil {
83		return nil, false
84	}
85	select {
86	case message := <-h.navigations:
87		return message, true
88	default:
89		return nil, false
90	}
91}
92
93// publishRoutes hands the newest route snapshot to the current foreground's
94// worker. It reports false when token no longer owns the foreground.
95func (h *attachmentHost) publishRoutes(token AttachmentToken, snapshot protocol.RecentRouteSnapshot) bool {
96	fg := h.currentForeground(token)
97	if fg == nil {
98		return false
99	}
100	for {
101		select {
102		case fg.routes <- snapshot:
103			return true
104		default:
105		}
106		select {
107		case <-fg.routes:
108		default:
109		}
110	}
111}
112
113// replyNavigation queues one navigation failure for the current worker.
114func (h *attachmentHost) replyNavigation(token AttachmentToken, message protocol.ClientMessage) bool {
115	fg := h.currentForeground(token)
116	if fg == nil {
117		return false
118	}
119	select {
120	case fg.replies <- message:
121		return true
122	default:
123		return false
124	}
125}
126
127// inPlaceSwitch is one supervisor-committed session on the daemon already
128// serving the attachment. The worker asks that daemon to move the live
129// attachment there instead of reconnecting. seq identifies this choice, so a
130// result for an older one is never mistaken for it.
131type inPlaceSwitch struct {
132	seq    uint64
133	target protocol.ExactSessionTarget
134	tab    domain.TabStableID
135}
136
137// inPlaceOutcome is how one in-place switch ended.
138type inPlaceOutcome uint8
139
140const (
141	// inPlaceArrived: the daemon moved the attachment to the target.
142	inPlaceArrived inPlaceOutcome = iota + 1
143	// inPlaceRefused: the daemon kept the source; reconnect to the target.
144	inPlaceRefused
145	// inPlaceSuperseded: a newer navigation replaced this one; drop it.
146	inPlaceSuperseded
147)
148
149// inPlaceResult reports the outcome of the in-place switch seq.
150type inPlaceResult struct {
151	seq     uint64
152	outcome inPlaceOutcome
153}
154
155// requestInPlace hands one in-place switch to the current foreground's worker.
156// The newest request replaces an unsent one. It reports false when token no
157// longer owns the foreground.
158func (h *attachmentHost) requestInPlace(token AttachmentToken, request inPlaceSwitch) bool {
159	fg := h.currentForeground(token)
160	if fg == nil {
161		return false
162	}
163	for {
164		select {
165		case fg.inPlace <- request:
166			return true
167		default:
168		}
169		select {
170		case <-fg.inPlace:
171		default:
172		}
173	}
174}
175
176// InPlaceResults carries the outcome of each in-place switch to the
177// supervisor.
178func (h *attachmentHost) InPlaceResults() <-chan inPlaceResult {
179	if h == nil {
180		return nil
181	}
182	return h.inPlaceResults
183}
184
185func (f *attachmentForeground) inPlaceSwitches() <-chan inPlaceSwitch {
186	if f == nil {
187		return nil
188	}
189	return f.inPlace
190}
191
192// reportInPlace hands the outcome of one in-place switch to the supervisor.
193// The newest outcome replaces one the supervisor has not taken yet; it is
194// always the latest choice, the only one the supervisor still waits for.
195func (f *attachmentForeground) reportInPlace(seq uint64, outcome inPlaceOutcome) {
196	if f == nil || f.host == nil || seq == 0 {
197		return
198	}
199	result := inPlaceResult{seq: seq, outcome: outcome}
200	for {
201		select {
202		case f.host.inPlaceResults <- result:
203			return
204		default:
205		}
206		select {
207		case <-f.host.inPlaceResults:
208		default:
209		}
210	}
211}
212
213func (h *attachmentHost) currentForeground(token AttachmentToken) *attachmentForeground {
214	if h == nil {
215		return nil
216	}
217	fg := h.authority.foreground()
218	if fg == nil || fg.token != token {
219		return nil
220	}
221	return fg
222}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close