vox_types/handshake.rs
1use facet::Facet;
2
3use crate::{ConnectionSettings, Parity, Schema, SessionResumeKey};
4
5// r[impl session.handshake]
6// r[impl session.handshake.cbor]
7/// CBOR-encoded handshake message exchanged before postcard traffic begins.
8#[derive(Debug, Clone, Facet)]
9#[repr(u8)]
10pub enum HandshakeMessage {
11 Hello(Hello),
12 HelloYourself(HelloYourself),
13 LetsGo(LetsGo),
14 Sorry(Sorry),
15}
16
17// r[impl session.handshake]
18/// Sent by the initiator as the first handshake message.
19#[derive(Debug, Clone, Facet)]
20pub struct Hello {
21 /// The identifier partition desired by the initiator.
22 pub parity: Parity,
23 /// Connection limits advertised by the initiator for the root connection.
24 pub connection_settings: ConnectionSettings,
25 // r[impl session.handshake.protocol-schema]
26 /// The initiator's schema for MessagePayload — the postcard enum used
27 /// for all subsequent communication.
28 pub message_payload_schema: Vec<Schema>,
29 /// Whether the initiator supports operation-level retry.
30 #[facet(default)]
31 pub supports_retry: bool,
32 /// Session resume key (present only when resuming an existing session).
33 #[facet(default)]
34 pub resume_key: Option<ResumeKeyBytes>,
35}
36
37// r[impl session.handshake]
38/// Sent by the acceptor in response to Hello.
39#[derive(Debug, Clone, Facet)]
40pub struct HelloYourself {
41 /// Connection limits advertised by the acceptor for the root connection.
42 pub connection_settings: ConnectionSettings,
43 // r[impl session.handshake.protocol-schema]
44 /// The acceptor's schema for MessagePayload.
45 pub message_payload_schema: Vec<Schema>,
46 /// Whether the acceptor supports operation-level retry.
47 #[facet(default)]
48 pub supports_retry: bool,
49 /// Session resume key (generated by acceptor for future resumption).
50 #[facet(default)]
51 pub resume_key: Option<ResumeKeyBytes>,
52}
53
54// r[impl session.handshake]
55/// Sent by the initiator to confirm schema compatibility and establish the session.
56#[derive(Debug, Clone, Facet)]
57pub struct LetsGo {}
58
59// r[impl session.handshake.sorry]
60/// Sent by either peer to reject the session due to schema incompatibility.
61#[derive(Debug, Clone, Facet)]
62pub struct Sorry {
63 pub reason: String,
64}
65
66/// Fixed-size resume key bytes, CBOR-serializable.
67#[derive(Debug, Clone, Facet)]
68pub struct ResumeKeyBytes {
69 pub bytes: Vec<u8>,
70}
71
72impl ResumeKeyBytes {
73 pub fn from_key(key: &SessionResumeKey) -> Self {
74 Self {
75 bytes: key.0.to_vec(),
76 }
77 }
78
79 pub fn to_key(&self) -> Option<SessionResumeKey> {
80 if self.bytes.len() == 16 {
81 let mut arr = [0u8; 16];
82 arr.copy_from_slice(&self.bytes);
83 Some(SessionResumeKey(arr))
84 } else {
85 None
86 }
87 }
88}
89
90/// Result of a completed CBOR handshake.
91#[derive(Debug, Clone)]
92pub struct HandshakeResult {
93 pub role: crate::SessionRole,
94 pub our_settings: ConnectionSettings,
95 pub peer_settings: ConnectionSettings,
96 pub peer_supports_retry: bool,
97 /// The resume key for this session. For the acceptor, this is the key
98 /// we generated and sent in HelloYourself. For the initiator, this is
99 /// the key the acceptor sent us.
100 pub session_resume_key: Option<SessionResumeKey>,
101 /// The resume key the peer sent in their Hello (initiator→acceptor only).
102 /// Used by the acceptor to look up existing sessions for resumption.
103 pub peer_resume_key: Option<SessionResumeKey>,
104 pub our_schema: Vec<Schema>,
105 pub peer_schema: Vec<Schema>,
106}