fix: implement new proto spec

This commit is contained in:
Strix 2023-11-05 20:52:29 +01:00
parent 53f1b36505
commit 5811d29032
No known key found for this signature in database
GPG key ID: 49B2E37B8915B774
9 changed files with 161 additions and 46 deletions

View file

@ -1,8 +1,15 @@
use crate::packet::packet_data::PacketData; use crate::packet::packet_data::PacketData;
/// NM = Node Management
/// This is the abstraction for managing nodes.
pub mod node_management; pub mod node_management;
/// PC = Property Control
/// This is the abstraction for controling properties on a node.
pub mod property_control; pub mod property_control;
/// RDT = Raw Data Transmission
/// This is the abstraction for sending raw data over domo.
pub mod raw_data_transmission;
impl_into_enum_variant!(PacketData::NodeManagement, node_management::NodeManagementCommand); impl_into_enum_variant!(PacketData::NodeManagement, node_management::NodeManagementCommand);
impl_into_enum_variant!(PacketData::PropertyControl, property_control::PropertyControlCommand); impl_into_enum_variant!(PacketData::PropertyControl, property_control::PropertyControlCommand);
impl_into_enum_variant!(PacketData::Raw, Vec<u8>); impl_into_enum_variant!(PacketData::Unknown, Vec<u8>);

View file

@ -0,0 +1,78 @@
use std::io;
use crate::{
identifier::Identifier,
packet::{packet_data::PacketData, raw_packet::RawPacket, Packet, ToPacket},
prelude::as_u32_be,
};
pub mod vec;
#[derive(Debug, Clone)]
pub enum RawDataTransmission {
SetupTransmission {
/// The total size of the data being sent.
size: u64,
/// This string is the mime type of the data being sent.
/// By default this should be `application/octet-stream`.
/// The maximum length of this string is 128 bytes since the mime rfc states the recommended max is 127 bytes.
mime_type: String,
},
Data {
/// The number of the segment in the sequence of segments being sent.
sequence_number: u32,
/// Segment size in bytes
size: u32,
/// A segment of the data being sent
data: Vec<u8>,
},
}
impl ToPacket for RawDataTransmission {
fn to_packet(
self,
src: Identifier,
dest: Identifier,
packet_id: Identifier,
reply_to: Identifier,
) -> Packet {
Packet {
src,
dest,
packet_id,
reply_to,
command: 0x20,
data: PacketData::RawDataTransmission(self.clone()),
}
}
}
impl TryFrom<RawPacket> for RawDataTransmission {
type Error = io::Error;
fn try_from(raw_packet: RawPacket) -> io::Result<Self> {
let build_invalid_input_err = |r: &str| Err(io::Error::new(io::ErrorKind::InvalidInput, r));
let mut data = raw_packet.data;
match raw_packet.command {
0x20 => {
let size = u64::from_be_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]);
let mime_type = String::from_utf8(data[8..].to_vec()).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidInput, "Invalid mime type string")
})?;
Ok(RawDataTransmission::SetupTransmission { size, mime_type })
}
0x21 => {
let sequence_number = as_u32_be(&mut data);
let size = as_u32_be(&mut data);
Ok(RawDataTransmission::Data {
sequence_number,
size,
data,
})
}
_ => build_invalid_input_err("Invalid command"),
}
}
}

View file

@ -0,0 +1,21 @@
use super::RawDataTransmission;
impl Into<Vec<u8>> for RawDataTransmission {
fn into(self) -> Vec<u8> {
match self {
RawDataTransmission::SetupTransmission { size, mime_type } => {
let mut v = vec![];
v.extend(size.to_be_bytes().to_vec());
v.extend(mime_type.into_bytes());
v
},
RawDataTransmission::Data { sequence_number, size, data } => {
let mut v = vec![];
v.extend(sequence_number.to_be_bytes().to_vec());
v.extend(size.to_be_bytes().to_vec());
v.extend(data);
v
}
}
}
}

View file

@ -11,39 +11,30 @@ pub enum DataType {
Array(Vec<DataType>), Array(Vec<DataType>),
// Basic types // Basic types
/// Basic Type: Switch (`0x10`] /// Basic Type: Boolean (`0x10`]
Switch(bool), Boolean(bool),
/// Basic Type: Slider (`0x11`) /// Basic Type: Slider (`0x11`)
Slider(u8), Number(u64),
/// Basic Type: Text (`0x12`) /// Basic Type: Text (`0x12`)
Text(String), Text(String),
/// Basic Type: Identifier (`0x13`)
Identifier(Identifier),
// Cosmetic // Color
/// Cosmetic Type: RGB (`0x20`) /// Color Type: RGB (`0x20`)
RGB(u8, u8, u8), RGB(u8, u8, u8),
// Time & Space
/// Time & Space Type: Seconds (`0x90`)
Seconds(u64),
// Domo Types
/// Domo type: Node Ref (`0xF0`)
NodeRef(Identifier),
} }
impl DataType { impl DataType {
pub fn get_data_size(data_type: u8) -> usize { pub fn get_data_size(data_type: u8) -> usize {
match data_type { match data_type {
0x00 => 0, 0x00 => 0,
0x01 => { 0x01 => 2,
2
},
0x10 => 1, 0x10 => 1,
0x11 => 1, 0x11 => 8,
0x12 => 256, 0x12 => 256,
0x13 => 4,
0x20 => 3, 0x20 => 3,
0x90 => 8,
0xF0 => 4,
_ => 0, _ => 0,
} }
} }

View file

@ -1,6 +1,6 @@
use std::io; use std::io;
use crate::data_types::{DataType, get_data_types}; use crate::data_types::{DataType, get_data_types};
use crate::identifier::Identifier; use crate::identifier::{Identifier, self};
use crate::prelude::as_u64_be; use crate::prelude::as_u64_be;
impl Into<Vec<u8>> for DataType { impl Into<Vec<u8>> for DataType {
@ -14,24 +14,23 @@ impl Into<Vec<u8>> for DataType {
} }
res res
}, },
DataType::Switch(b) => vec![0x10, b as u8], DataType::Boolean(b) => vec![0x10, b as u8],
DataType::Slider(v) => vec![0x11, v], DataType::Number(v) => {
let mut bytes = vec![0x11];
bytes.extend(v.to_be_bytes());
bytes
},
DataType::Text(s) => { DataType::Text(s) => {
let mut bytes = vec![0x12]; let mut bytes = vec![0x12];
bytes.extend(s.into_bytes()); bytes.extend(s.into_bytes());
bytes bytes
}, },
DataType::Identifier(identifier) => {
let mut bytes = vec![0x13];
bytes.extend(identifier.bytes);
bytes
},
DataType::RGB(r, g, b) => vec![0x20, r, g, b], DataType::RGB(r, g, b) => vec![0x20, r, g, b],
DataType::Seconds(s) => {
let mut bytes = vec![0x90];
bytes.extend_from_slice(s.to_be_bytes().as_ref());
bytes
},
DataType::NodeRef(id) => {
let mut bytes = vec![0xF0];
bytes.extend_from_slice(id.bytes.as_ref());
bytes
},
} }
} }
} }
@ -61,8 +60,11 @@ impl TryFrom<Vec<u8>> for DataType {
if value.len() - 1 < size as usize { return Err(io::Error::new(io::ErrorKind::InvalidData, "Array specified data length != array data length")) } if value.len() - 1 < size as usize { return Err(io::Error::new(io::ErrorKind::InvalidData, "Array specified data length != array data length")) }
Ok(DataType::Array(get_data_types(value[3..(size as usize)].to_vec()))) Ok(DataType::Array(get_data_types(value[3..(size as usize)].to_vec())))
}, },
0x10 => impl_data_type!(value, 1, DataType::Switch(value[1] != 0)), 0x10 => impl_data_type!(value, 1, DataType::Boolean(value[1] != 0)),
0x11 => impl_data_type!(value, 1, DataType::Slider(value[1])), 0x11 => impl_data_type!(value, 8, DataType::Number(u64::from_be_bytes([
value[1], value[2], value[3], value[4],
value[5], value[6], value[7], value[8]
]))),
0x12 => impl_data_type!( 0x12 => impl_data_type!(
value, value,
256, 256,
@ -72,9 +74,8 @@ impl TryFrom<Vec<u8>> for DataType {
DataType::Nothing DataType::Nothing
} }
), ),
0x13 => impl_data_type!(value, 4, DataType::Identifier(Identifier::from(&value[1..5]))),
0x20 => impl_data_type!(value, 3, DataType::RGB(value[1], value[2], value[3])), 0x20 => impl_data_type!(value, 3, DataType::RGB(value[1], value[2], value[3])),
0x90 => impl_data_type!(value, 8, DataType::Seconds(as_u64_be(&value[1..9]))),
0xF0 => impl_data_type!(value, 4, DataType::NodeRef(Identifier::from(&value[1..5]))),
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "Could not match data type header to a data type.")), _ => Err(io::Error::new(io::ErrorKind::InvalidData, "Could not match data type header to a data type.")),
} }
} }

View file

@ -1,6 +1,6 @@
//! Welcome to the Domo protocol rust implementation. //! Welcome to the Domo protocol rust implementation.
//! //!
//! This implementation is up-to-date with DomoProto v1. //! This implementation is up-to-date with Domo protocol v1.
//! //!
//! Most code that should/is actually used (usually) has documentation with it. //! Most code that should/is actually used (usually) has documentation with it.
@ -27,7 +27,6 @@ mod tests {
use crate::packet; use crate::packet;
use crate::data_types::{DataType, get_data_types}; use crate::data_types::{DataType, get_data_types};
use crate::identifier::Identifier; use crate::identifier::Identifier;
use crate::packet::Packet;
use crate::packet::packet_data::PacketData; use crate::packet::packet_data::PacketData;
#[test] #[test]
@ -37,12 +36,12 @@ mod tests {
get_data_types(vec![0x00, 0x10, 0x00]), get_data_types(vec![0x00, 0x10, 0x00]),
vec![ vec![
DataType::Nothing, DataType::Nothing,
DataType::Switch(false), DataType::Boolean(false),
]); ]);
// test DataType -> Vec<u8> // test DataType -> Vec<u8>
assert_eq!( assert_eq!(
Into::<Vec<u8>>::into(DataType::Switch(true)), Into::<Vec<u8>>::into(DataType::Boolean(true)),
vec![0x10, 0x01] vec![0x10, 0x01]
) )
} }

View file

@ -17,7 +17,7 @@ pub const FULL_PACKET_SIZE: usize = 65559;
pub const BASE_PACKET_SIZE: usize = 65555; pub const BASE_PACKET_SIZE: usize = 65555;
/// The abstraction for all DomoProto packets. /// The abstraction for all DomoProto packets.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Packet { pub struct Packet {
pub dest: Identifier, pub dest: Identifier,
pub src: Identifier, pub src: Identifier,
@ -31,6 +31,20 @@ pub trait ToPacket {
fn to_packet(self, src: Identifier, dest: Identifier, packet_id: Identifier, reply_to: Identifier) -> Packet; fn to_packet(self, src: Identifier, dest: Identifier, packet_id: Identifier, reply_to: Identifier) -> Packet;
} }
/// Default packet is a ping from 0x0 to 0xFFFFFFFF
impl Default for Packet {
fn default() -> Self {
Self {
dest: Identifier::from(0xFFFFFFFF),
src: Identifier::from(0),
command: 0x00,
packet_id: Identifier::random(),
reply_to: Identifier::default(),
data: PacketData::Unknown(vec![])
}
}
}
/// Secretly calls RawPacket::try_from().into() /// Secretly calls RawPacket::try_from().into()
impl TryFrom<Vec<u8>> for Packet { impl TryFrom<Vec<u8>> for Packet {
type Error = io::Error; type Error = io::Error;

View file

@ -1,6 +1,7 @@
use std::io; use std::io;
use crate::commands::property_control::PropertyControlCommand; use crate::commands::property_control::PropertyControlCommand;
use crate::commands::node_management::NodeManagementCommand; use crate::commands::node_management::NodeManagementCommand;
use crate::commands::raw_data_transmission::RawDataTransmission;
use crate::packet::raw_packet::RawPacket; use crate::packet::raw_packet::RawPacket;
/// Abstraction used for interpreting the data in a packet. /// Abstraction used for interpreting the data in a packet.
@ -8,13 +9,14 @@ use crate::packet::raw_packet::RawPacket;
pub enum PacketData { pub enum PacketData {
NodeManagement(NodeManagementCommand), NodeManagement(NodeManagementCommand),
PropertyControl(PropertyControlCommand), PropertyControl(PropertyControlCommand),
Raw(Vec<u8>) RawDataTransmission(RawDataTransmission),
Unknown(Vec<u8>)
} }
/// Returns an empty `PacketData::Raw` /// Returns an empty `PacketData::Raw`
impl Default for PacketData { impl Default for PacketData {
fn default() -> Self { fn default() -> Self {
PacketData::Raw(vec![]) PacketData::Unknown(vec![])
} }
} }
@ -23,7 +25,8 @@ impl PacketData {
match self { match self {
PacketData::NodeManagement(v) => v.into(), PacketData::NodeManagement(v) => v.into(),
PacketData::PropertyControl(v) => v.into(), PacketData::PropertyControl(v) => v.into(),
PacketData::Raw(v) => v PacketData::RawDataTransmission(v) => v.into(),
PacketData::Unknown(v) => v
} }
} }
} }
@ -36,6 +39,7 @@ impl TryFrom<RawPacket> for PacketData {
} { } {
0x0 => Ok(PacketData::NodeManagement(NodeManagementCommand::try_from(raw_packet)?)), 0x0 => Ok(PacketData::NodeManagement(NodeManagementCommand::try_from(raw_packet)?)),
0x1 => Ok(PacketData::PropertyControl(PropertyControlCommand::try_from(raw_packet)?)), 0x1 => Ok(PacketData::PropertyControl(PropertyControlCommand::try_from(raw_packet)?)),
0xF => Ok(PacketData::RawDataTransmission(RawDataTransmission::try_from(raw_packet)?)),
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "command group is unsupported")) _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "command group is unsupported"))
} }
} }

View file

@ -44,7 +44,7 @@ impl Into<Packet> for RawPacket {
println!("{}", e); println!("{}", e);
e e
}) })
.unwrap_or(PacketData::Raw(self.data)), .unwrap_or(PacketData::Unknown(self.data)),
} }
} }
} }