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 #[serde(with = "serde_bytes")]
30 pub client_nonce: Vec<u8>,
31 pub requested: Vec<String>,
32}
33
34impl DiscoveryRequest {
35 pub fn new(requested: Vec<String>, client_nonce: Vec<u8>) -> Self {
36 Self {
37 message_type: MessageType::AlpineDiscover,
38 version: ALPINE_VERSION.to_string(),
39 client_nonce,
40 requested,
41 }
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
47pub struct DiscoveryReply {
48 #[serde(rename = "type")]
49 pub message_type: MessageType,
50 pub alpine_version: String,
51 pub device_id: String,
52 pub manufacturer_id: String,
53 pub model_id: String,
54 pub hardware_rev: String,
55 pub firmware_rev: String,
56 pub mac: String,
57 pub server_nonce: Vec<u8>,
58 pub capabilities: CapabilitySet,
59 pub signature: Vec<u8>,
60}
61
62impl DiscoveryReply {
63 pub fn new(
64 identity: &DeviceIdentity,
65 mac: String,
66 server_nonce: Vec<u8>,
67 capabilities: CapabilitySet,
68 signature: Vec<u8>,
69 ) -> Self {
70 Self {
71 message_type: MessageType::AlpineDiscoverReply,
72 alpine_version: ALPINE_VERSION.to_string(),
73 device_id: identity.device_id.clone(),
74 manufacturer_id: identity.manufacturer_id.clone(),
75 model_id: identity.model_id.clone(),
76 hardware_rev: identity.hardware_rev.clone(),
77 firmware_rev: identity.firmware_rev.clone(),
78 mac,
79 server_nonce,
80 capabilities,
81 signature,
82 }
83 }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
88pub struct DeviceIdentity {
89 pub device_id: String,
90 pub manufacturer_id: String,
91 pub model_id: String,
92 pub hardware_rev: String,
93 pub firmware_rev: String,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
98pub struct CapabilitySet {
99 pub channel_formats: Vec<ChannelFormat>,
100 pub max_channels: u32,
101 pub grouping_supported: bool,
102 pub streaming_supported: bool,
103 pub encryption_supported: bool,
104 pub vendor_extensions: Option<HashMap<String, serde_json::Value>>,
105}
106
107impl Default for CapabilitySet {
108 fn default() -> Self {
109 Self {
110 channel_formats: vec![ChannelFormat::U8],
111 max_channels: 512,
112 grouping_supported: false,
113 streaming_supported: true,
114 encryption_supported: true,
115 vendor_extensions: None,
116 }
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
122#[serde(rename_all = "lowercase")]
123pub enum ChannelFormat {
124 U8,
125 U16,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
130pub struct SessionInit {
131 #[serde(rename = "type")]
132 pub message_type: MessageType,
133 pub controller_nonce: Vec<u8>,
134 pub controller_pubkey: Vec<u8>,
135 pub requested: CapabilitySet,
136 pub session_id: Uuid,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
141pub struct SessionAck {
142 #[serde(rename = "type")]
143 pub message_type: MessageType,
144 pub device_nonce: Vec<u8>,
145 pub device_pubkey: Vec<u8>,
146 pub device_identity: DeviceIdentity,
147 pub capabilities: CapabilitySet,
148 pub signature: Vec<u8>,
149 pub session_id: Uuid,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
154pub struct SessionReady {
155 #[serde(rename = "type")]
156 pub message_type: MessageType,
157 pub session_id: Uuid,
158 pub mac: Vec<u8>,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
163pub struct SessionComplete {
164 #[serde(rename = "type")]
165 pub message_type: MessageType,
166 pub session_id: Uuid,
167 pub ok: bool,
168 pub error: Option<ErrorCode>,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
173pub struct SessionEstablished {
174 pub session_id: Uuid,
175 pub controller_nonce: Vec<u8>,
176 pub device_nonce: Vec<u8>,
177 pub capabilities: CapabilitySet,
178 pub device_identity: DeviceIdentity,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
183pub struct ControlEnvelope {
184 #[serde(rename = "type")]
185 pub message_type: MessageType,
186 pub session_id: Uuid,
187 pub seq: u64,
188 pub op: ControlOp,
189 pub payload: serde_json::Value,
190 pub mac: Vec<u8>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
195pub struct Acknowledge {
196 #[serde(rename = "type")]
197 pub message_type: MessageType,
198 pub session_id: Uuid,
199 pub seq: u64,
200 pub ok: bool,
201 pub detail: Option<String>,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub payload: Option<Vec<u8>>,
204 pub mac: Vec<u8>,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
209#[serde(rename_all = "snake_case")]
210pub enum ControlOp {
211 GetInfo,
212 GetCaps,
213 Identify,
214 Restart,
215 GetStatus,
216 SetConfig,
217 SetMode,
218 TimeSync,
219 Vendor,
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
224pub struct FrameEnvelope {
225 #[serde(rename = "type")]
226 pub message_type: MessageType,
227 pub session_id: Uuid,
228 pub timestamp_us: u64,
229 pub priority: u8,
230 pub channel_format: ChannelFormat,
231 pub channels: Vec<u16>,
232 pub groups: Option<HashMap<String, Vec<u16>>>,
233 pub metadata: Option<HashMap<String, serde_json::Value>>,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
238pub struct Keepalive {
239 #[serde(rename = "type")]
240 pub message_type: MessageType,
241 pub session_id: Uuid,
242 pub tick_ms: u64,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
247#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
248pub enum ErrorCode {
249 DiscoveryInvalidSignature,
250 DiscoveryNonceMismatch,
251 DiscoveryUnsupportedVersion,
252 HandshakeSignatureInvalid,
253 HandshakeKeyDerivationFailed,
254 HandshakeTimeout,
255 HandshakeReplay,
256 SessionExpired,
257 SessionInvalidToken,
258 SessionMacMismatch,
259 ControlUnknownOp,
260 ControlPayloadInvalid,
261 ControlUnauthorized,
262 StreamBadFormat,
263 StreamTooLarge,
264 StreamUnsupportedChannelMode,
265}