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 #[serde(skip_serializing_if = "Option::is_none")]
202 pub payload: Option<Vec<u8>>,
203 pub mac: Vec<u8>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
208#[serde(rename_all = "snake_case")]
209pub enum ControlOp {
210 GetInfo,
211 GetCaps,
212 Identify,
213 Restart,
214 GetStatus,
215 SetConfig,
216 SetMode,
217 TimeSync,
218 Vendor,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
223pub struct FrameEnvelope {
224 #[serde(rename = "type")]
225 pub message_type: MessageType,
226 pub session_id: Uuid,
227 pub timestamp_us: u64,
228 pub priority: u8,
229 pub channel_format: ChannelFormat,
230 pub channels: Vec<u16>,
231 pub groups: Option<HashMap<String, Vec<u16>>>,
232 pub metadata: Option<HashMap<String, serde_json::Value>>,
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
237pub struct Keepalive {
238 #[serde(rename = "type")]
239 pub message_type: MessageType,
240 pub session_id: Uuid,
241 pub tick_ms: u64,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
246#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
247pub enum ErrorCode {
248 DiscoveryInvalidSignature,
249 DiscoveryNonceMismatch,
250 DiscoveryUnsupportedVersion,
251 HandshakeSignatureInvalid,
252 HandshakeKeyDerivationFailed,
253 HandshakeTimeout,
254 HandshakeReplay,
255 SessionExpired,
256 SessionInvalidToken,
257 SessionMacMismatch,
258 ControlUnknownOp,
259 ControlPayloadInvalid,
260 ControlUnauthorized,
261 StreamBadFormat,
262 StreamTooLarge,
263 StreamUnsupportedChannelMode,
264}