attachment_connection.go RawHistoryFolder

1package daemon
2
3import "github.com/bnema/vev/internal/ports"
4
5// attachmentCapability is the exact capability for one registered
6// Attachment Connection incarnation. It is invalid as soon as its Session
7// membership, generation, Transport incarnation, or render lease changes.
8type attachmentCapability struct {
9	sess       *session
10	ac         *attachedClient
11	generation uint64
12	transport  transportSnapshot
13	lease      *attachmentLease
14	// rebase marks a cross-session move whose first paint starts a dependency-
15	// free output chain after publication releases architecture locks.
16	rebase bool
17}
18
19func captureAttachmentCapability(entry *session, ac *attachedClient, tr ports.ServerConnection) attachmentCapability {
20	if entry == nil || entry.core() == nil || ac == nil || tr == nil {
21		return attachmentCapability{}
22	}
23	// Capture one concrete link incarnation before taking the session lock. The
24	// same snapshot is revalidated below; do not take a second snapshot and
25	// accidentally bind a replacement link.
26	transport := ac.transportSnapshot()
27	if transport.transport != tr {
28		return attachmentCapability{}
29	}
30	if ac.beforeAttachmentCapabilityValidation != nil {
31		ac.beforeAttachmentCapabilityValidation()
32	}
33	core := entry.core()
34	core.mu.Lock()
35	if !attachmentRegisteredLocked(entry, ac) || !ac.transportSnapshotCurrent(transport) {
36		core.mu.Unlock()
37		return attachmentCapability{}
38	}
39	generation := ac.lifecycle.generation.Load()
40	token := attachmentCapability{
41		sess:       entry,
42		ac:         ac,
43		generation: generation,
44		transport:  transport,
45	}
46	if rc := core.coordinator.Load(); rc != nil {
47		token.lease = rc.attachmentLease(ac)
48	}
49	core.mu.Unlock()
50	if !token.current() {
51		return attachmentCapability{}
52	}
53	ac.lifecycle.installInitialCapability(token)
54	return token
55}
56
57func (s *session) captureAttachmentCapability(ac *attachedClient, tr ports.ServerConnection) attachmentCapability {
58	return captureAttachmentCapability(s, ac, tr)
59}
60
61// admitCurrentAttachmentCapabilityEffect re-admits the attachment's current
62// capability after an exact capability stopped being admissible. It re-reads the
63// attachment's current session and transport, so it never sends through a stale
64// capability or resurrects a detached transport. A detached attachment, or one
65// whose current session no longer registers this link, admits nothing.
66func admitCurrentAttachmentCapabilityEffect(capability attachmentCapability) (attachmentCapability, *attachmentEffect, bool) {
67	ac := capability.ac
68	if ac == nil {
69		return attachmentCapability{}, nil, false
70	}
71	sess := ac.currentAttachmentSession()
72	if sess == nil {
73		return attachmentCapability{}, nil, false
74	}
75	token, effect, admitted := ac.beginCurrentAttachmentEffect(sess, ac.transport())
76	if !admitted {
77		return attachmentCapability{}, nil, false
78	}
79	// The re-admitted link replaces the superseded capability's identity but
80	// inherits its post-publication paint semantics, so a recovered cross-session
81	// first paint still rebases the output chain on the current link.
82	if capability.rebase {
83		token.rebase = true
84	}
85	return token, effect, true
86}
87
88func (t attachmentCapability) sameIdentity(other attachmentCapability) bool {
89	return t.sess != nil && t.ac != nil && t.sess == other.sess && t.ac == other.ac &&
90		t.generation == other.generation && t.transport.transport == other.transport.transport &&
91		t.transport.incarnation == other.transport.incarnation && t.lease == other.lease
92}
93
94func (t attachmentCapability) matchesConnectionSnapshot(sess *session, ac *attachedClient, transport transportSnapshot) bool {
95	return t.sess == sess && t.ac == ac && ac != nil && t.transport == transport &&
96		ac.lifecycle.identityCurrent(t)
97}
98
99func (l *attachmentLifecycle) identityCurrent(capability attachmentCapability) bool {
100	return l != nil && capability.sess != nil && capability.ac != nil &&
101		capability.ac.lifecycle.generation.Load() == capability.generation &&
102		capability.ac.currentAttachmentSession() == capability.sess &&
103		capability.ac.transportSnapshotCurrent(capability.transport)
104}
105
106// current validates every immutable identity captured by the capability.
107// Membership is the sole authority; there is no owner, replacement, or
108// compatibility role.
109func (l *attachmentLifecycle) current(capability attachmentCapability) bool {
110	if !l.identityCurrent(capability) || !attachmentRegistered(capability.sess, capability.ac) {
111		return false
112	}
113	if capability.lease == nil {
114		return true
115	}
116	rc := capability.sess.core().coordinator.Load()
117	return rc != nil && capability.lease.attachment == capability.ac && rc.leaseCurrent(capability.lease, false)
118}
119
120func (t attachmentCapability) current() bool {
121	return t.ac != nil && t.ac.lifecycle.current(t)
122}
123
124func beginAttachmentLeaseEffect(sess *session, ac *attachedClient, lease *attachmentLease) (*attachmentEffect, bool) {
125	if sess == nil || ac == nil || lease == nil {
126		return nil, false
127	}
128	token := captureAttachmentCapability(sess, ac, ac.transport())
129	token.lease = lease
130	return ac.beginAttachmentEffect(token)
131}
132
133func (t attachmentCapability) currentInSessionLocked(sess *session) bool {
134	return t.sess == sess && t.ac != nil && t.ac.lifecycle.currentSessionLocked(t)
135}
136
137func (t attachmentCapability) currentInSessionAndLeaseLocked(sess *session, ac *attachedClient, coordinator *renderCoordinator) bool {
138	return t.sess == sess && t.ac == ac && ac != nil &&
139		ac.lifecycle.currentSessionAndLeaseLocked(t, coordinator)
140}
141
142// currentSessionLocked validates capability authority where sess.core().mu is
143// already held. An admitted effect does not use this comparison: a transition
144// cannot change identity until that effect ends.
145func (l *attachmentLifecycle) currentSessionLocked(capability attachmentCapability) bool {
146	if !l.identityCurrent(capability) || !attachmentRegisteredLocked(capability.sess, capability.ac) {
147		return false
148	}
149	if capability.lease == nil {
150		return true
151	}
152	rc := capability.sess.core().coordinator.Load()
153	return rc != nil && capability.lease.attachment == capability.ac && rc.leaseCurrent(capability.lease, false)
154}
155
156// currentSessionAndLeaseLocked validates the same capability tuple when the
157// caller already holds both the Session and coordinator locks.
158func (l *attachmentLifecycle) currentSessionAndLeaseLocked(capability attachmentCapability, coordinator *renderCoordinator) bool {
159	if !l.identityCurrent(capability) || !attachmentRegisteredLocked(capability.sess, capability.ac) {
160		return false
161	}
162	if capability.lease == nil {
163		return true
164	}
165	return coordinator != nil && capability.lease.attachment == capability.ac &&
166		coordinator.leaseCurrentLocked(capability.lease, false)
167}

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