session_core.go RawHistoryFolder
1package daemon
2
3import (
4 "sync"
5 "sync/atomic"
6
7 "github.com/bnema/vev/internal/domain"
8)
9
10// sessionCore is the state shared by every attachment-capable session. It is
11// embedded as the first field of session so the existing s.mu selector remains
12// the one lock guarding both attachment membership and local tab state.
13// Geometry claim paths use the partial order mu -> geometryMu -> sizeMu; no
14// path acquires an architectural lock while holding sizeMu.
15type sessionCore struct {
16 mu sync.Mutex
17
18 id domain.SessionID
19 name string
20 ephemeral bool
21 caps sessionCapabilities
22 // attachments is the session-owned membership registry. Connection
23 // generation and effect state remain attachment-local; admission and view
24 // code use this collection as their membership source.
25 attachments map[*attachedClient]struct{}
26 attachmentOrder map[*attachedClient]uint64
27 nextAttachmentID uint64
28 // geometryOwner is the attachment whose latest attach/resume/resize claim
29 // controls shared PTY/layout geometry. The pointer is published atomically
30 // so resize transactions can reject stale claims without taking session.mu.
31 // geometryMu serializes claim publication with the final shared-layout commit.
32 geometryMu sync.Mutex
33 geometryOwner atomic.Pointer[attachedClient]
34 // geometryClaimSeq is mutated while mu and geometryMu are held; its value
35 // is copied into attachedClient.geometryClaim.
36 geometryClaimSeq uint64
37 createdAt int64
38 incarnation domain.IncarnationID
39 mruAt atomic.Uint64
40 coordinator atomic.Pointer[renderCoordinator]
41}
42
43func (s *session) core() *sessionCore {
44 if s == nil {
45 return nil
46 }
47 return &s.sessionCore
48}
49
50func (s *session) captureRenderState(ac *attachedClient, req renderCaptureRequest) (*capturedRenderState, bool) {
51 return captureLocalRenderState(s, ac, req)
52}
53
54// validTargetTabLocked validates a target tab index without changing any
55// attachment view. Client-facing navigation updates attachment views through
56// selectAttachmentTab.
57func (s *session) validTargetTabLocked(tabIndex int) bool {
58 if tabIndex < 0 {
59 return true
60 }
61 return tabIndex < len(s.tabs)
62}
63
64func sessionsSnapshot(entries map[domain.SessionID]*session) []*session {
65 sessions := make([]*session, 0, len(entries))
66 for _, sess := range entries {
67 if sess != nil {
68 sessions = append(sessions, sess)
69 }
70 }
71 return sessions
72}