1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3pub const ALPINE_VERSION: &str = "1.0";
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7#[serde(rename_all = "snake_case")]
8pub enum MessageType {
9 AlpineDiscover,
10 AlpineDiscoverReply,
11 SessionInit,
12 SessionAck,
13 SessionReady,
14 SessionComplete,
15 AlpineControl,
16 AlpineControlAck,
17 AlpineFrame,
18 Keepalive,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
23pub struct DiscoveryRequest {
24 #[serde(rename = "type")]
25 pub message_type: MessageType,
26 #[serde(rename = "alpine_version")]
27 pub alpine_version: String,
28 #[serde(with = "serde_bytes")]
29 pub client_nonce: Vec<u8>,
30 pub requested: Vec<String>,
31}
32
33impl DiscoveryRequest {
34 pub fn new(requested: Vec<String>, client_nonce: Vec<u8>) -> Self {
35 Self {
36 message_type: MessageType::AlpineDiscover,
37 alpine_version: ALPINE_VERSION.to_string(),
38 client_nonce,
39 requested,
40 }
41 }
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
46pub struct DiscoveryReply {
47 #[serde(rename = "type")]
48 pub message_type: MessageType,
49 pub alpine_version: String,
50 pub device_id: String,
51 pub manufacturer_id: String,
52 pub model_id: String,
53 pub hardware_rev: String,
54 pub firmware_rev: String,
55 pub mac: String,
56 #[serde(with = "serde_bytes")]
57 pub server_nonce: Vec<u8>,
58 pub capabilities: CapabilitySet,
59 #[serde(with = "serde_bytes")]
60 pub signature: Vec<u8>,
61 #[serde(
63 with = "serde_bytes",
64 default,
65 alias = "identity_pubkey",
66 alias = "device_identity_key",
67 alias = "identity_public_key",
68 alias = "device_identity_public_key"
69 )]
70 pub device_identity_pubkey: Vec<u8>,
71 #[serde(with = "serde_bytes", default)]
73 pub device_identity_attestation: Vec<u8>,
74 #[serde(default)]
76 pub device_identity_trusted: bool,
77}
78
79impl DiscoveryReply {
80 pub fn new(
81 identity: &DeviceIdentity,
82 mac: String,
83 server_nonce: Vec<u8>,
84 capabilities: CapabilitySet,
85 signature: Vec<u8>,
86 device_identity_pubkey: Vec<u8>,
87 device_identity_attestation: Vec<u8>,
88 device_identity_trusted: bool,
89 ) -> Self {
90 Self {
91 message_type: MessageType::AlpineDiscoverReply,
92 alpine_version: ALPINE_VERSION.to_string(),
93 device_id: identity.device_id.clone(),
94 manufacturer_id: identity.manufacturer_id.clone(),
95 model_id: identity.model_id.clone(),
96 hardware_rev: identity.hardware_rev.clone(),
97 firmware_rev: identity.firmware_rev.clone(),
98 mac,
99 server_nonce,
100 capabilities,
101 signature,
102 device_identity_pubkey,
103 device_identity_attestation,
104 device_identity_trusted,
105 }
106 }
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
111pub struct DeviceIdentity {
112 pub device_id: String,
113 pub manufacturer_id: String,
114 pub model_id: String,
115 pub hardware_rev: String,
116 pub firmware_rev: String,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
121pub struct CapabilitySet {
122 pub channel_formats: Vec<ChannelFormat>,
123 pub max_channels: u32,
124 pub grouping_supported: bool,
125 pub streaming_supported: bool,
126 pub encryption_supported: bool,
127 pub vendor_extensions: Option<HashMap<String, serde_json::Value>>,
128}
129
130impl Default for CapabilitySet {
131 fn default() -> Self {
132 Self {
133 channel_formats: vec![ChannelFormat::U8],
134 max_channels: 512,
135 grouping_supported: false,
136 streaming_supported: true,
137 encryption_supported: true,
138 vendor_extensions: None,
139 }
140 }
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
145#[serde(rename_all = "lowercase")]
146pub enum ChannelFormat {
147 U8,
148 U16,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
153pub struct SessionInit {
154 #[serde(rename = "type")]
155 pub message_type: MessageType,
156 #[serde(with = "serde_bytes")]
157 pub controller_nonce: Vec<u8>,
158 #[serde(with = "serde_bytes")]
159 pub controller_pubkey: Vec<u8>,
160 pub requested: CapabilitySet,
161 pub session_id: String,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
166pub struct SessionAck {
167 #[serde(rename = "type")]
168 pub message_type: MessageType,
169 #[serde(with = "serde_bytes")]
170 pub device_nonce: Vec<u8>,
171 #[serde(with = "serde_bytes")]
172 pub device_pubkey: Vec<u8>,
173 #[serde(
174 with = "serde_bytes",
175 default,
176 alias = "identity_pubkey",
177 alias = "device_identity_key",
178 alias = "identity_public_key",
179 alias = "device_identity_public_key"
180 )]
181 pub device_identity_pubkey: Vec<u8>,
182 pub device_identity: DeviceIdentity,
183 pub capabilities: CapabilitySet,
184 #[serde(with = "serde_bytes")]
185 pub signature: Vec<u8>,
186 pub session_id: String,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
191pub struct SessionReady {
192 #[serde(rename = "type")]
193 pub message_type: MessageType,
194 pub session_id: String,
195 #[serde(with = "serde_bytes")]
196 pub mac: Vec<u8>,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
201pub struct SessionComplete {
202 #[serde(rename = "type")]
203 pub message_type: MessageType,
204 pub session_id: String,
205 pub ok: bool,
206 pub error: Option<ErrorCode>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
211pub struct SessionEstablished {
212 pub session_id: String,
213 #[serde(with = "serde_bytes")]
214 pub controller_nonce: Vec<u8>,
215 #[serde(with = "serde_bytes")]
216 pub device_nonce: Vec<u8>,
217 pub capabilities: CapabilitySet,
218 pub device_identity: DeviceIdentity,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
223pub struct ControlEnvelope {
224 #[serde(rename = "type")]
225 pub message_type: MessageType,
226 pub session_id: String,
227 pub seq: u64,
228 pub op: ControlOp,
229 pub payload: serde_json::Value,
230 #[serde(with = "serde_bytes")]
231 pub mac: Vec<u8>,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
236pub struct Acknowledge {
237 #[serde(rename = "type")]
238 pub message_type: MessageType,
239 pub session_id: String,
240 pub seq: u64,
241 pub ok: bool,
242 pub detail: Option<String>,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub payload: Option<Vec<u8>>,
245 #[serde(with = "serde_bytes")]
246 pub mac: Vec<u8>,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
251#[serde(rename_all = "snake_case")]
252pub enum ControlOp {
253 GetInfo,
254 GetCaps,
255 Identify,
256 Restart,
257 GetStatus,
258 SetConfig,
259 SetMode,
260 TimeSync,
261 Vendor,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
266pub struct FrameEnvelope {
267 #[serde(rename = "type")]
268 pub message_type: MessageType,
269 pub session_id: String,
270 pub timestamp_us: u64,
271 pub priority: u8,
272 pub channel_format: ChannelFormat,
273 pub channels: Vec<u16>,
274 pub groups: Option<HashMap<String, Vec<u16>>>,
275 pub metadata: Option<HashMap<String, serde_json::Value>>,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
280pub struct Keepalive {
281 #[serde(rename = "type")]
282 pub message_type: MessageType,
283 pub session_id: String,
284 pub tick_ms: u64,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
289#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
290pub enum ErrorCode {
291 DiscoveryInvalidSignature,
292 DiscoveryNonceMismatch,
293 DiscoveryUnsupportedVersion,
294 HandshakeSignatureInvalid,
295 HandshakeKeyDerivationFailed,
296 HandshakeTimeout,
297 HandshakeReplay,
298 SessionExpired,
299 SessionInvalidToken,
300 SessionMacMismatch,
301 ControlUnknownOp,
302 ControlPayloadInvalid,
303 ControlUnauthorized,
304 StreamBadFormat,
305 StreamTooLarge,
306 StreamUnsupportedChannelMode,
307}