1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use uuid::Uuid;
4
5pub const ALPINE_VERSION: &str = "1.0";
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(rename_all = "snake_case")]
10pub enum MessageType {
11 AlpineDiscover,
12 AlpineDiscoverReply,
13 SessionInit,
14 SessionAck,
15 SessionReady,
16 SessionComplete,
17 AlpineControl,
18 AlpineControlAck,
19 AlpineFrame,
20 Keepalive,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25pub struct DiscoveryRequest {
26 #[serde(rename = "type")]
27 pub message_type: MessageType,
28 pub version: String,
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 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 pub server_nonce: Vec<u8>,
57 pub capabilities: CapabilitySet,
58 pub signature: Vec<u8>,
59}
60
61impl DiscoveryReply {
62 pub fn new(
63 identity: &DeviceIdentity,
64 mac: String,
65 server_nonce: Vec<u8>,
66 capabilities: CapabilitySet,
67 signature: Vec<u8>,
68 ) -> Self {
69 Self {
70 message_type: MessageType::AlpineDiscoverReply,
71 alpine_version: ALPINE_VERSION.to_string(),
72 device_id: identity.device_id.clone(),
73 manufacturer_id: identity.manufacturer_id.clone(),
74 model_id: identity.model_id.clone(),
75 hardware_rev: identity.hardware_rev.clone(),
76 firmware_rev: identity.firmware_rev.clone(),
77 mac,
78 server_nonce,
79 capabilities,
80 signature,
81 }
82 }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
87pub struct DeviceIdentity {
88 pub device_id: String,
89 pub manufacturer_id: String,
90 pub model_id: String,
91 pub hardware_rev: String,
92 pub firmware_rev: String,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
97pub struct CapabilitySet {
98 pub channel_formats: Vec<ChannelFormat>,
99 pub max_channels: u32,
100 pub grouping_supported: bool,
101 pub streaming_supported: bool,
102 pub encryption_supported: bool,
103 pub vendor_extensions: Option<HashMap<String, serde_json::Value>>,
104}
105
106impl Default for CapabilitySet {
107 fn default() -> Self {
108 Self {
109 channel_formats: vec![ChannelFormat::U8],
110 max_channels: 512,
111 grouping_supported: false,
112 streaming_supported: true,
113 encryption_supported: true,
114 vendor_extensions: None,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
121#[serde(rename_all = "lowercase")]
122pub enum ChannelFormat {
123 U8,
124 U16,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
129pub struct SessionInit {
130 #[serde(rename = "type")]
131 pub message_type: MessageType,
132 pub controller_nonce: Vec<u8>,
133 pub controller_pubkey: Vec<u8>,
134 pub requested: CapabilitySet,
135 pub session_id: Uuid,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
140pub struct SessionAck {
141 #[serde(rename = "type")]
142 pub message_type: MessageType,
143 pub device_nonce: Vec<u8>,
144 pub device_pubkey: Vec<u8>,
145 pub device_identity: DeviceIdentity,
146 pub capabilities: CapabilitySet,
147 pub signature: Vec<u8>,
148 pub session_id: Uuid,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
153pub struct SessionReady {
154 #[serde(rename = "type")]
155 pub message_type: MessageType,
156 pub session_id: Uuid,
157 pub mac: Vec<u8>,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
162pub struct SessionComplete {
163 #[serde(rename = "type")]
164 pub message_type: MessageType,
165 pub session_id: Uuid,
166 pub ok: bool,
167 pub error: Option<ErrorCode>,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
172pub struct SessionEstablished {
173 pub session_id: Uuid,
174 pub controller_nonce: Vec<u8>,
175 pub device_nonce: Vec<u8>,
176 pub capabilities: CapabilitySet,
177 pub device_identity: DeviceIdentity,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
182pub struct ControlEnvelope {
183 #[serde(rename = "type")]
184 pub message_type: MessageType,
185 pub session_id: Uuid,
186 pub seq: u64,
187 pub op: ControlOp,
188 pub payload: serde_json::Value,
189 pub mac: Vec<u8>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
194pub struct Acknowledge {
195 #[serde(rename = "type")]
196 pub message_type: MessageType,
197 pub session_id: Uuid,
198 pub seq: u64,
199 pub ok: bool,
200 pub detail: Option<String>,
201 pub mac: Vec<u8>,
202}
203
204#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
206#[serde(rename_all = "snake_case")]
207pub enum ControlOp {
208 GetInfo,
209 GetCaps,
210 Identify,
211 Restart,
212 GetStatus,
213 SetConfig,
214 SetMode,
215 TimeSync,
216 Vendor,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
221pub struct FrameEnvelope {
222 #[serde(rename = "type")]
223 pub message_type: MessageType,
224 pub session_id: Uuid,
225 pub timestamp_us: u64,
226 pub priority: u8,
227 pub channel_format: ChannelFormat,
228 pub channels: Vec<u16>,
229 pub groups: Option<HashMap<String, Vec<u16>>>,
230 pub metadata: Option<HashMap<String, serde_json::Value>>,
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
235pub struct Keepalive {
236 #[serde(rename = "type")]
237 pub message_type: MessageType,
238 pub session_id: Uuid,
239 pub tick_ms: u64,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
244#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
245pub enum ErrorCode {
246 DiscoveryInvalidSignature,
247 DiscoveryNonceMismatch,
248 DiscoveryUnsupportedVersion,
249 HandshakeSignatureInvalid,
250 HandshakeKeyDerivationFailed,
251 HandshakeTimeout,
252 HandshakeReplay,
253 SessionExpired,
254 SessionInvalidToken,
255 SessionMacMismatch,
256 ControlUnknownOp,
257 ControlPayloadInvalid,
258 ControlUnauthorized,
259 StreamBadFormat,
260 StreamTooLarge,
261 StreamUnsupportedChannelMode,
262}