1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use DispatchInner;
use *;
/// Refuse to open a session when the role's drive cannot run under this
/// machine's placement.
///
/// The one rule is `onlyne_config::validate_drive_placement`: `acp` pairs only
/// with `headless`, because stdio carries the ACP channel and cannot also be a
/// pane's terminal. It is checked in the config crate, where both halves of
/// what `backend` used to be are defined, and again here, where the two of them
/// meet for the first time — the drive arrives with `welcome` from the spec and
/// the placement from the machine.
///
/// A refusal is the delivery's, not a retry's: nothing this client can do makes
/// the pair work, so the row is refused with the sentence and an operator reads
/// the fix in the ledger. Running anyway — a pane printing protocol frames, or
/// an ACP child with no pane it could ever have — is the silent drift the split
/// exists to remove.
pub
/// The socket a session spawned in `workspace` dials.
///
/// `dispatch` passes this to [`session_env`] and the same tree lands in
/// `SpawnSpec.cwd`, so one resolve answers both halves of the spawn, and a
/// workspace past the unix bound yields the short path the client bound.
pub
/// The environment one spawned session process carries.
///
/// The three `ONLYNE_` identity variables are what the plugin mounts with. The
/// obligation a session owes is not among them: the guard is this client's own
/// (`guards.rs`), read off the role's `allowed_targets`, so there is no policy
/// for a session process to carry and no variable for it to read.
///
/// `ONLYNE_CLUSTER` names the server's topology and is the address a host
/// backend groups sessions under. No welcome yet means no variable, and a pane
/// host then keeps its own default-labelled tree.
///
/// `ONLYNE_SOCKET` is the path the client is serving: the same accessor the
/// daemon bound, so a short endpoint reaches the session as the served path and
/// the plugin needs no guess of its own. A hand-started pi keeps its own
/// resolution as the fallback, which is the reason an empty path injects no key
/// at all.
pub
/// Agent name this binary reports during the handshake.
pub const AGENT: &str = "onlyne-client";
/// Wait bound for one request round trip.
pub const REQUEST_TIMEOUT: Duration = from_secs;
/// Server heartbeat interval from the observation rules of §4.
pub const HEARTBEAT_INTERVAL: Duration = from_secs;
/// How many heartbeat intervals a live connection may go quiet before the
/// reconnect sweep reads the silence as an agent that stopped.
///
/// The protocol already answers this question once: `heartbeat_timeout_ms`
/// (`onlyne_config::DEFAULT_HEARTBEAT_TIMEOUT_MS`) is the presence liveness
/// timeout, and it is exactly three of these intervals — the plugin's own
/// comment on its cadence names it as the pair. Taking the margin from that
/// number keeps one answer in the tree instead of inventing a second threshold
/// beside `[client] reconnect_grace_secs`, and it is a margin over the cadence
/// rather than a fixed duration, so a plugin configured to beat slower than the
/// default is not swept for keeping its own word.
pub const HEARTBEAT_SILENCE_MARGIN: u32 = 3;