vox_types/handshake.rs
1use facet::Facet;
2
3use crate::{ConnectionSettings, Metadata, 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 /// Metadata sent by the initiator (e.g. `vox-service` for service routing).
36 #[facet(default)]
37 pub metadata: Metadata<'static>,
38}
39
40// r[impl session.handshake]
41/// Sent by the acceptor in response to Hello.
42#[derive(Debug, Clone, Facet)]
43pub struct HelloYourself {
44 /// Connection limits advertised by the acceptor for the root connection.
45 pub connection_settings: ConnectionSettings,
46 // r[impl session.handshake.protocol-schema]
47 /// The acceptor's schema for MessagePayload.
48 pub message_payload_schema: Vec<Schema>,
49 /// Whether the acceptor supports operation-level retry.
50 #[facet(default)]
51 pub supports_retry: bool,
52 /// Session resume key (generated by acceptor for future resumption).
53 #[facet(default)]
54 pub resume_key: Option<ResumeKeyBytes>,
55 /// Metadata sent by the acceptor.
56 #[facet(default)]
57 pub metadata: Metadata<'static>,
58}
59
60// r[impl session.handshake]
61/// Sent by the initiator to confirm schema compatibility and establish the session.
62#[derive(Debug, Clone, Facet)]
63pub struct LetsGo {}
64
65// r[impl session.handshake.sorry]
66/// Sent by either peer to reject the session due to schema incompatibility.
67#[derive(Debug, Clone, Facet)]
68pub struct Sorry {
69 pub reason: String,
70}
71
72/// Fixed-size resume key bytes, CBOR-serializable.
73#[derive(Debug, Clone, Facet)]
74pub struct ResumeKeyBytes {
75 pub bytes: Vec<u8>,
76}
77
78impl ResumeKeyBytes {
79 pub fn from_key(key: &SessionResumeKey) -> Self {
80 Self {
81 bytes: key.0.to_vec(),
82 }
83 }
84
85 pub fn to_key(&self) -> Option<SessionResumeKey> {
86 if self.bytes.len() == 16 {
87 let mut arr = [0u8; 16];
88 arr.copy_from_slice(&self.bytes);
89 Some(SessionResumeKey(arr))
90 } else {
91 None
92 }
93 }
94}
95
96/// Result of a completed CBOR handshake.
97#[derive(Debug, Clone)]
98pub struct HandshakeResult {
99 pub role: crate::SessionRole,
100 pub our_settings: ConnectionSettings,
101 pub peer_settings: ConnectionSettings,
102 pub peer_supports_retry: bool,
103 /// The resume key for this session. For the acceptor, this is the key
104 /// we generated and sent in HelloYourself. For the initiator, this is
105 /// the key the acceptor sent us.
106 pub session_resume_key: Option<SessionResumeKey>,
107 /// The resume key the peer sent in their Hello (initiator→acceptor only).
108 /// Used by the acceptor to look up existing sessions for resumption.
109 pub peer_resume_key: Option<SessionResumeKey>,
110 pub our_schema: Vec<Schema>,
111 pub peer_schema: Vec<Schema>,
112 /// Metadata received from the peer during handshake.
113 pub peer_metadata: Metadata<'static>,
114}