use crc::{CRC_32_ISO_HDLC, Crc};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use thiserror::Error;
use uuid::Uuid;
#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
pub struct BlobDescriptor {
pub length: u32,
pub checksum: u32,
}
#[derive(Clone, Copy, Debug, Error)]
#[error("Blob too big")]
pub struct BlobTooBig;
impl BlobDescriptor {
const CRC: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
pub fn describe(blob: &[u8]) -> Result<Self, BlobTooBig> {
let crc = Self::CRC.checksum(blob);
let len = blob.len().try_into().map_err(|_| BlobTooBig)?;
Ok(Self {
length: len,
checksum: crc,
})
}
#[must_use]
pub fn verify_checksum(&self, blob: &[u8]) -> bool {
let crc = Self::CRC.checksum(blob);
crc == self.checksum
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct BlobMarker {
#[serde(rename = "$blob")]
pub blob_idx: u32,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Request {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<u32>,
#[serde(flatten)]
pub data: RequestData,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub enum RequestData {
List,
Methods {
#[serde(rename = "data")]
uuid: Uuid,
},
Invoke {
#[serde(rename = "data")]
invocation: MethodInvocation,
#[serde(skip_serializing_if = "Option::is_none")]
blobs: Option<Vec<BlobDescriptor>>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MethodInvocation {
pub device_id: Uuid,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<Vec<JsonValue>>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Response {
#[serde(default)]
pub id: u32,
#[serde(rename = "gen")]
pub generation: Option<u32>,
#[serde(flatten)]
pub data: ResponseData,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub enum ResponseData {
List {
#[serde(rename = "data")]
device_list: Vec<DeviceInfo>,
},
Methods {
#[serde(rename = "data")]
device_methods: Vec<MethodInfo>,
},
Result {
#[serde(rename = "data")]
#[serde(skip_serializing_if = "Option::is_none")]
return_value: Option<JsonValue>,
#[serde(skip_serializing_if = "Option::is_none")]
blobs: Option<Vec<BlobDescriptor>>,
},
Error {
#[serde(rename = "data")]
msg: String,
},
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeviceInfo {
pub device_id: Uuid,
pub type_names: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MethodInfo {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_value_description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<Vec<MethodParameterInfo>>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MethodParameterInfo {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "type")]
#[serde(skip_serializing_if = "Option::is_none")]
pub typ: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeviceEvent {
#[serde(rename = "type")]
pub typ: String,
pub device_id: Uuid,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<JsonValue>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Event {
#[serde(rename = "gen")]
pub generation: u32,
#[serde(flatten)]
pub data: EventData,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type")]
#[serde(rename_all = "camelCase")]
#[serde(rename_all_fields = "camelCase")]
#[non_exhaustive]
pub enum EventData {
DevicesChanged,
EventsDropped {
#[serde(rename = "data")]
events_dropped: u32,
},
#[serde(untagged)]
Device(DeviceEvent),
#[serde(untagged)]
Other(JsonValue),
}