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}
72
73impl DiscoveryReply {
74 pub fn new(
75 identity: &DeviceIdentity,
76 mac: String,
77 server_nonce: Vec<u8>,
78 capabilities: CapabilitySet,
79 signature: Vec<u8>,
80 device_identity_pubkey: Vec<u8>,
81 ) -> Self {
82 Self {
83 message_type: MessageType::AlpineDiscoverReply,
84 alpine_version: ALPINE_VERSION.to_string(),
85 device_id: identity.device_id.clone(),
86 manufacturer_id: identity.manufacturer_id.clone(),
87 model_id: identity.model_id.clone(),
88 hardware_rev: identity.hardware_rev.clone(),
89 firmware_rev: identity.firmware_rev.clone(),
90 mac,
91 server_nonce,
92 capabilities,
93 signature,
94 device_identity_pubkey,
95 }
96 }
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
101pub struct DeviceIdentity {
102 pub device_id: String,
103 pub manufacturer_id: String,
104 pub model_id: String,
105 pub hardware_rev: String,
106 pub firmware_rev: String,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
111pub struct CapabilitySet {
112 pub channel_formats: Vec<ChannelFormat>,
113 pub max_channels: u32,
114 pub grouping_supported: bool,
115 pub streaming_supported: bool,
116 pub encryption_supported: bool,
117 pub vendor_extensions: Option<HashMap<String, serde_json::Value>>,
118}
119
120impl Default for CapabilitySet {
121 fn default() -> Self {
122 Self {
123 channel_formats: vec![ChannelFormat::U8],
124 max_channels: 512,
125 grouping_supported: false,
126 streaming_supported: true,
127 encryption_supported: true,
128 vendor_extensions: None,
129 }
130 }
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
135#[serde(rename_all = "lowercase")]
136pub enum ChannelFormat {
137 U8,
138 U16,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
143pub struct SessionInit {
144 #[serde(rename = "type")]
145 pub message_type: MessageType,
146 #[serde(with = "serde_bytes")]
147 pub controller_nonce: Vec<u8>,
148 #[serde(with = "serde_bytes")]
149 pub controller_pubkey: Vec<u8>,
150 pub requested: CapabilitySet,
151 pub session_id: String,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
156pub struct SessionAck {
157 #[serde(rename = "type")]
158 pub message_type: MessageType,
159 #[serde(with = "serde_bytes")]
160 pub device_nonce: Vec<u8>,
161 #[serde(with = "serde_bytes")]
162 pub device_pubkey: Vec<u8>,
163 #[serde(
164 with = "serde_bytes",
165 default,
166 alias = "identity_pubkey",
167 alias = "device_identity_key",
168 alias = "identity_public_key",
169 alias = "device_identity_public_key"
170 )]
171 pub device_identity_pubkey: Vec<u8>,
172 pub device_identity: DeviceIdentity,
173 pub capabilities: CapabilitySet,
174 #[serde(with = "serde_bytes")]
175 pub signature: Vec<u8>,
176 pub session_id: String,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
181pub struct SessionReady {
182 #[serde(rename = "type")]
183 pub message_type: MessageType,
184 pub session_id: String,
185 #[serde(with = "serde_bytes")]
186 pub mac: Vec<u8>,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
191pub struct SessionComplete {
192 #[serde(rename = "type")]
193 pub message_type: MessageType,
194 pub session_id: String,
195 pub ok: bool,
196 pub error: Option<ErrorCode>,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
201pub struct SessionEstablished {
202 pub session_id: String,
203 #[serde(with = "serde_bytes")]
204 pub controller_nonce: Vec<u8>,
205 #[serde(with = "serde_bytes")]
206 pub device_nonce: Vec<u8>,
207 pub capabilities: CapabilitySet,
208 pub device_identity: DeviceIdentity,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
213pub struct ControlEnvelope {
214 #[serde(rename = "type")]
215 pub message_type: MessageType,
216 pub session_id: String,
217 pub seq: u64,
218 pub op: ControlOp,
219 pub payload: serde_json::Value,
220 #[serde(with = "serde_bytes")]
221 pub mac: Vec<u8>,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
226pub struct Acknowledge {
227 #[serde(rename = "type")]
228 pub message_type: MessageType,
229 pub session_id: String,
230 pub seq: u64,
231 pub ok: bool,
232 pub detail: Option<String>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub payload: Option<Vec<u8>>,
235 #[serde(with = "serde_bytes")]
236 pub mac: Vec<u8>,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
241#[serde(rename_all = "snake_case")]
242pub enum ControlOp {
243 GetInfo,
244 GetCaps,
245 Identify,
246 Restart,
247 GetStatus,
248 SetConfig,
249 SetMode,
250 TimeSync,
251 Vendor,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
256pub struct FrameEnvelope {
257 #[serde(rename = "type")]
258 pub message_type: MessageType,
259 pub session_id: String,
260 pub timestamp_us: u64,
261 pub priority: u8,
262 pub channel_format: ChannelFormat,
263 pub channels: Vec<u16>,
264 pub groups: Option<HashMap<String, Vec<u16>>>,
265 pub metadata: Option<HashMap<String, serde_json::Value>>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
270pub struct Keepalive {
271 #[serde(rename = "type")]
272 pub message_type: MessageType,
273 pub session_id: String,
274 pub tick_ms: u64,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
279#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
280pub enum ErrorCode {
281 DiscoveryInvalidSignature,
282 DiscoveryNonceMismatch,
283 DiscoveryUnsupportedVersion,
284 HandshakeSignatureInvalid,
285 HandshakeKeyDerivationFailed,
286 HandshakeTimeout,
287 HandshakeReplay,
288 SessionExpired,
289 SessionInvalidToken,
290 SessionMacMismatch,
291 ControlUnknownOp,
292 ControlPayloadInvalid,
293 ControlUnauthorized,
294 StreamBadFormat,
295 StreamTooLarge,
296 StreamUnsupportedChannelMode,
297}