From 7999ac61033f5394855cbd41e6d9e617418b3ccd Mon Sep 17 00:00:00 2001 From: Raine Date: Thu, 30 Nov 2023 21:52:49 +0100 Subject: [PATCH] feat: rewrite spec and proto --- doc/{proto.md => protocol.md} | 195 +++++++++++------- doc/specification.md | 46 +++++ .../src/commands/node_management/mod.rs | 43 ++-- .../src/commands/node_management/vec.rs | 25 ++- .../src/commands/property_control/mod.rs | 125 ++++++++--- .../src/commands/property_control/vec.rs | 8 + 6 files changed, 298 insertions(+), 144 deletions(-) rename doc/{proto.md => protocol.md} (67%) create mode 100644 doc/specification.md diff --git a/doc/proto.md b/doc/protocol.md similarity index 67% rename from doc/proto.md rename to doc/protocol.md index be71967..f0eb6cb 100644 --- a/doc/proto.md +++ b/doc/protocol.md @@ -1,10 +1,69 @@ > **Version:** `1` > **Authored by:** `Raine ` -> **Status**: `planning` +> +# Table of contents +- [Table of contents](#table-of-contents) +- [Prelude](#prelude) + - [Interpretation of types](#interpretation-of-types) + - [Booleans](#booleans) + - [Reserved fields](#reserved-fields) +- [Structure](#structure) +- [Data types](#data-types) + - [Dynamic data (`dynamic_data`)](#dynamic-data-dynamic_data) +- [Commands](#commands) + - [`0x0*` - Node management](#0x0---node-management) + - [`0x00` - Ping](#0x00---ping) + - [Command data](#command-data) + - [`0x01` - Register node](#0x01---register-node) + - [Command data](#command-data-1) + - [`0x02` - Remove node](#0x02---remove-node) + - [Command data](#command-data-2) + - [`0x0A` - Acknowledge packets](#0x0a---acknowledge-packets) + - [`0x0E` - Error](#0x0e---error) + - [Command data](#command-data-3) + - [Error codes](#error-codes) + - [`0x1*` - Properties control](#0x1---properties-control) + - [`0x10` - Register property](#0x10---register-property) + - [Command data](#command-data-4) + - [`0x11` - Remove property](#0x11---remove-property) + - [Command data](#command-data-5) + - [`0x12` - Get property](#0x12---get-property) + - [Command data](#command-data-6) + - [`0x13` - Set property](#0x13---set-property) + - [Command data](#command-data-7) + - [`0x14` - Reset property](#0x14---reset-property) + - [Command data](#command-data-8) + - [`0x1A` - Subscribe to property](#0x1a---subscribe-to-property) + - [`0x1B` - Unsubscribe to property](#0x1b---unsubscribe-to-property) + - [`0x1F` - All properties](#0x1f---all-properties) + - [Command data](#command-data-9) + - [`0xF*` - Raw data transmission](#0xf---raw-data-transmission) + - [`0xF0` - Setup transfer](#0xf0---setup-transfer) + - [Command data](#command-data-10) + - [`0xF1` - Data](#0xf1---data) + - [Command data](#command-data-11) + # Prelude -Version 1 has zero security on itself. +This document only describes what the protocol looks like. +The specification can be found at `./specification.md`. + +## Interpretation of types + +### Booleans + +If in the description of a property it's marked as a boolean the exact logic that should be executed is: +`value != 0` + +## Reserved fields + +The "reserved" column (if present) will state what should be filled in by each side. + +- "no": this should be filled in by both sides. (default) +- "request": this should only be filled in the request. +- "response": this should only be filled in the response. + # Structure @@ -22,30 +81,6 @@ Packets are sent in big endian. | `0x14` | `<0x11-0x12:data_length>` | `data` | This is the data of the command | `0x0000` | | `0x14 + <0x11-0x12:data_length>` | 4 bytes | `checksum` | This is the CRC32 checksum of the packet without the checksum. | `0x00000000` | -# Packets in practice - -## Statuses - -When an error occurs the response should be a `0x0E` (error command). -This can contain error data. - -To mark a success, you should just send back the expected response. - -## Reserved fields - -The "reserved" column (if present) will state what should be filled in by each side. - -- "no": this should be filled in by both sides. (default) -- "request": this should only be filled in the request. -- "response": this should only be filled in the response. - -# Error checking - -If the CRC32 doesn't match up the receiver will send a `0x0E` (error) packet to the probable source. -The error code `0x01`/`net_broken_packet` should be used. The metadata may contain some textual info on what went -wrong. -The master will not track the broken packet's `packet_id`, so the slave can send it again. - # Data types Domo has a data framework reliant on data types. @@ -64,23 +99,16 @@ These define what kind of data the property holds. | `0x2*` | | | **Color** | | `0x20` | 3 bytes | RGB | An RGB value. | - - ## Dynamic data (`dynamic_data`) Dynamic data is a data snippet with a `prop_data_type` byte and the data next to it. > **Note**: this section uses relative offset -| offset | size | name | description | example | -| ------ | ----------------------------- | ---------------- | ----------------------- | ------- | -| `0x00` | 1 byte | `prop_data_type` | Describes the data type | `0x00` | -| `0x01` | depending on `prop_data_type` | `data` | The data | | +| offset | size | name | description | example | +| ------ | --------------------------- | ---------------- | ----------------------- | ------- | +| `0x00` | 1 byte | `prop_data_type` | Describes the data type | `0x00` | +| `0x01` | depends on `prop_data_type` | `data` | The data | | # Commands @@ -121,23 +149,13 @@ Remove node from network there is no extra data required. -### `0x03` - Register property +### `0x0A` - Acknowledge packets -#### Command data +Acknowledge received packets. -| offset | size | name | description | reserved | example | -| ------ | -------- | --------------- | ------------------------------------------------------------------ | -------- | ------- | -| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | -| `0x34` | 1 byte | `data_type` | The type of data; see "Data types". | no | `0x01` | -| `0x35` | 1 byte | `read_only` | Whether the property is readonly.
(`0x00` = no, `0x01` = yes) | no | `0x00` | - -### `0x04` - Remove property - -#### Command data - -| offset | size | name | description | reserved | example | -| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------- | -| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | +| offset | size | name | description | reserved | example | +| ------ | ------------- | ----------- | ---------------------------------- | ----------- | ------- | +| `0x14` | 4 bytes * `n` | `packet_id` | list of packet_id's to acknowledge | origin node | | ### `0x0E` - Error @@ -145,10 +163,10 @@ Send a packet to state an error occurred. #### Command data -| offset | size | name | description | example | -| ------ | ----------------------------- | ------------ | ------------------------------- | ------- | -| `0x14` | 1 byte | `error_code` | error code; check 'Error codes' | `0x00` | -| `0x15` | `<0x14-0x15:metadata_length>` | `metadata` | metadata | | +| offset | size | name | description | example | +| ------ | ------------- | ------------ | ------------------------------- | ------- | +| `0x14` | 1 byte | `error_code` | error code; check 'Error codes' | `0x00` | +| `0x15` | `data_length` | `metadata` | metadata | | #### Error codes @@ -167,20 +185,40 @@ Send a packet to state an error occurred. | `0x20` | `node_invalid_property` | the property specified is invalid | no | | `0x21` | `node_failed_request` | the request could not be completed. | consult metadata | + ## `0x1*` - Properties control -### `0x10` - Get property +### `0x10` - Register property + +#### Command data + +| offset | size | name | description | reserved | example | +| ------ | -------- | --------------- | ---------------------------------------------- | -------- | ------- | +| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | +| `0x34` | 1 byte | `data_type` | The type of data; see "Data types". | no | `0x01` | +| `0x35` | 1 byte | `read_only` | Whether the property is readonly. (boolean) | no | `0x00` | +| `0x36` | 1 byte | `descriptive` | Whether the property is descriptive. (boolean) | no | `0x00` | + +### `0x11` - Remove property + +#### Command data + +| offset | size | name | description | reserved | example | +| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------- | +| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | + +### `0x12` - Get property Get a properties value #### Command data -| offset | size | name | description | reserved | example | -| ------ | -------- | --------------- | ------------------------------------------- | -------- | -------- | -| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | -| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | response | `0x0100` | +| offset | size | name | description | reserved | example | +| ------ | -------- | --------------- | ------------------------------------------- | ---------------- | -------- | +| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | +| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | destination node | `0x0100` | -### `0x11` - Set property +### `0x13` - Set property #### Command data @@ -189,7 +227,7 @@ Get a properties value | `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | | `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | no | `0x0100` | -### `0x12` - Reset property +### `0x14` - Reset property #### Command data @@ -204,13 +242,26 @@ Get a properties value | `0x14` | 4 bytes | `device_id` | Who's property? | no | `0x00000000` | | `0x18` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | -### `0x1A` - Unsubscribe to property +### `0x1B` - Unsubscribe to property | offset | size | name | description | reserved | example | | ------ | -------- | --------------- | ------------------------------------------- | -------- | ------------ | | `0x14` | 4 bytes | `device_id` | Who's property? | no | `0x00000000` | | `0x18` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" | +### `0x1F` - All properties + +Return all properties. + +#### Command data + +| offset | size | name | description | reserved | example | +| ------ | ------ | ------ | ------------------------- | -------- | ------- | +| `0x14` | 1 byte | `type` | | no | `0x00` | +| | | | `0x00` - all | | | +| | | | `0x01` - descriptive only | | | +| | | | `0x02` - m only | | | + ## `0xF*` - Raw data transmission This is useful for things like OTA updates. @@ -221,10 +272,10 @@ Since this procedure is quite expensive (network wise), the sides must shake han #### Command data -| offset | size | name | description | reserved | example | -| ------ | --------- | ------ | -------------------- | -------- | ------- | -| `0x14` | 8 bytes | `size` | u64 size of the data | request | `0x00` | -| `0x1c` | 128 bytes | `mime` | media type of data | request | `0x00` | +| offset | size | name | description | reserved | example | +| ------ | --------- | ------ | -------------------- | ----------- | ------- | +| `0x14` | 8 bytes | `size` | u64 size of the data | origin node | `0x00` | +| `0x1c` | 128 bytes | `mime` | media type of data | origin node | `0x00` | ### `0xF1` - Data @@ -235,7 +286,7 @@ This may be sent without the initial transfer setup for custom implementations. The `sequence_number` is added for redundancy, all data sent will always reply to it's previous data segment. -| offset | size | name | description | example | -| ------ | -------- | ----------------- | ------------------------------- | ------------ | -| `0x14` | 4 bytes | `sequence_number` | the sequence number of the data | `0x00000000` | -| `0x18` | `` | `data` | the data | | +| offset | size | name | description | example | +| ------ | ------------- | ----------------- | ------------------------------- | ------------ | +| `0x14` | 4 bytes | `sequence_number` | the sequence number of the data | `0x00000000` | +| `0x18` | `data_length` | `data` | the data | | diff --git a/doc/specification.md b/doc/specification.md new file mode 100644 index 0000000..6f3d7f2 --- /dev/null +++ b/doc/specification.md @@ -0,0 +1,46 @@ +# Protocol Design + +In this document I will define how this document is designed and how it should be implemented. + +# Prelude + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL", +"NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and +"OPTIONAL" in this document are to be interpreted as described in +RFC 2119. + +"node" or "nodes" are referring to a device that implements the Domo protocol. + +## Transactions + +All interactions between 2 nodes is called a transaction; a request and response. +The initial packet sent in the transaction is called the "origin packet". +A initial packet MUST NOT have a `reply_to`. +A transaction consists of 2 nodes; +- "Origin node"; the node who sent the origin packet. +- "Destination node"; the node who is marked as the destination by the origin packet. + +# Behaviour + +This chapter describes the behaviour of a node. + +## Statuses + +When an error occurs on the destination node in result of a request, the response to the origin node MUST be a `0x0E` (error command). +This MAY contain error data. +To mark a success, you MUST send back the request packet altered with the data specified in the protocol. + +## Reserved addresses + +### Broadcast (`0xFFFFFFFF`) + +Nodes MUST listen to this address. +Owner nodes MUST forward this address to their owners if applicable. + +# Packet inspection + +## Error checking + +If the CRC32 doesn't match up the destination node MUST send a `0x0E` (error) packet to the origin node. +The error code `0x01`/`net_broken_packet` MUST be used. The metadata MAY contain some textual info on what went wrong. +The master MUST not track the broken packet's `packet_id`, so the slave can send it again. diff --git a/domo_proto/src/commands/node_management/mod.rs b/domo_proto/src/commands/node_management/mod.rs index 4790bec..668e24a 100644 --- a/domo_proto/src/commands/node_management/mod.rs +++ b/domo_proto/src/commands/node_management/mod.rs @@ -12,13 +12,8 @@ pub enum NodeManagementCommand { Ping, RegisterNode { device_id: Identifier }, RemoveNode, - RegisterProperty { - property_name: String, - data_type: u8, - read_only: bool, - }, - RemoveProperty { - property_name: String, + AcknowledgePackets { + packet_ids: Vec }, Error { error_code: u8, @@ -32,9 +27,8 @@ impl NodeManagementCommand { NodeManagementCommand::Ping => 0x00, NodeManagementCommand::RegisterNode { .. } => 0x01, NodeManagementCommand::RemoveNode => 0x02, - NodeManagementCommand::RegisterProperty { .. } => 0x03, - NodeManagementCommand::RemoveProperty { .. } => 0x04, - NodeManagementCommand::Error { .. } => 0x0E + NodeManagementCommand::AcknowledgePackets { .. } => 0x0A, + NodeManagementCommand::Error { .. } => 0x0E, } } } @@ -67,27 +61,16 @@ impl TryFrom for NodeManagementCommand { build_invalid_input_err("expected 4 bytes") }, // remove node - 0x02 => Ok(NodeManagementCommand::RemoveNode), - // register property - 0x03 => if raw_packet.data_length == 34 { - Ok(NodeManagementCommand::RegisterProperty { - property_name: String::from_utf8(raw_packet.data[..32].to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?, - data_type: raw_packet.data[33], - read_only: raw_packet.data[34] != 0, - }) + 0x02 => Ok(NodeManagementCommand::RemoveNode), + 0x0A => if raw_packet.data_length >= 4 && (raw_packet.data_length % 4 == 0) { + Ok(NodeManagementCommand::AcknowledgePackets { + packet_ids: raw_packet.data.chunks(4) + .map(|c| Identifier::from(c)) + .collect() + }) } else { - build_invalid_input_err("expected 34 bytes") - }, - // remove property - 0x04 => if raw_packet.data_length == 32 { - Ok(NodeManagementCommand::RemoveProperty { - property_name: String::from_utf8(raw_packet.data.to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))? - }) - } else { - build_invalid_input_err("expected 32 bytes") - }, + build_invalid_input_err("expected at least 4 bytes and data_length%4=0") + } // error 0x0E => if raw_packet.data_length >= 1 { Ok(NodeManagementCommand::Error { diff --git a/domo_proto/src/commands/node_management/vec.rs b/domo_proto/src/commands/node_management/vec.rs index 610a0d4..2ffecf5 100644 --- a/domo_proto/src/commands/node_management/vec.rs +++ b/domo_proto/src/commands/node_management/vec.rs @@ -6,18 +6,21 @@ impl Into> for NodeManagementCommand { match self { NodeManagementCommand::Ping => vec![], NodeManagementCommand::RegisterNode { device_id } => { - vec![device_id.bytes[0], device_id.bytes[1], device_id.bytes[2], device_id.bytes[3]] - }, + vec![ + device_id.bytes[0], + device_id.bytes[1], + device_id.bytes[2], + device_id.bytes[3], + ] + } NodeManagementCommand::RemoveNode => vec![], - NodeManagementCommand::RegisterProperty { property_name, data_type, read_only } => { - let mut vec = vec![]; - vec.extend(property_name.into_bytes()); - vec.push(data_type); - vec.push(read_only as u8); - vec - }, - NodeManagementCommand::RemoveProperty { property_name } => property_name.into_bytes(), - NodeManagementCommand::Error { error_code, metadata } => { + NodeManagementCommand::AcknowledgePackets { packet_ids } => + packet_ids.iter().map(|i| i.bytes).flatten().collect(), + + NodeManagementCommand::Error { + error_code, + metadata, + } => { let mut vec = vec![]; vec.push(error_code); vec.extend(metadata); diff --git a/domo_proto/src/commands/property_control/mod.rs b/domo_proto/src/commands/property_control/mod.rs index 186d40b..270b32c 100644 --- a/domo_proto/src/commands/property_control/mod.rs +++ b/domo_proto/src/commands/property_control/mod.rs @@ -1,15 +1,24 @@ -use std::io; use crate::data_types::DataType; use crate::identifier::Identifier; +use crate::packet::packet_data::PacketData; use crate::packet::raw_packet::RawPacket; use crate::packet::{Packet, ToPacket}; -use crate::packet::packet_data::PacketData; use crate::prelude::as_u32_be; +use std::io; pub mod vec; #[derive(Debug, Clone)] pub enum PropertyControlCommand { + Register { + property_name: String, + data_type: u8, + read_only: bool, + // TODO: descriptive + }, + Remove { + property_name: String, + }, Get { property_name: String, data: DataType, @@ -34,21 +43,32 @@ pub enum PropertyControlCommand { impl PropertyControlCommand { pub fn command(&self) -> u8 { match self { - PropertyControlCommand::Get { .. } => 0x10, - PropertyControlCommand::Set { .. } => 0x11, - PropertyControlCommand::Reset { .. } => 0x12, + PropertyControlCommand::Register { .. } => 0x10, + PropertyControlCommand::Remove { .. } => 0x11, + PropertyControlCommand::Get { .. } => 0x12, + PropertyControlCommand::Set { .. } => 0x13, + PropertyControlCommand::Reset { .. } => 0x14, PropertyControlCommand::Subscribe { .. } => 0x1A, - PropertyControlCommand::Unsubscribe { .. } => 0x1B + PropertyControlCommand::Unsubscribe { .. } => 0x1B, } } } impl ToPacket for PropertyControlCommand { - 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 { Packet { - src, dest, packet_id, reply_to, + src, + dest, + packet_id, + reply_to, command: self.command(), - data: PacketData::PropertyControl(self.clone()) + data: PacketData::PropertyControl(self.clone()), } } } @@ -56,26 +76,56 @@ impl ToPacket for PropertyControlCommand { impl TryFrom for PropertyControlCommand { type Error = io::Error; fn try_from(raw_packet: RawPacket) -> io::Result { - let build_invalid_input_err = |r: &str| { - Err(io::Error::new(io::ErrorKind::InvalidInput, r)) - }; + let build_invalid_input_err = |r: &str| Err(io::Error::new(io::ErrorKind::InvalidInput, r)); match raw_packet.command { - // get property - 0x10 => if raw_packet.data_length == 33 { - Ok(PropertyControlCommand::Get { - property_name: String::from_utf8(raw_packet.data[..0x34].to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?, - data: DataType::try_from(raw_packet.data[0x34..].to_vec())?, - }) - } else { - build_invalid_input_err("expected 33 bytes") - }, - // set property + // remove node + 0x10 => { + if raw_packet.data_length == 34 { + Ok(PropertyControlCommand::Register { + property_name: String::from_utf8(raw_packet.data[..32].to_vec()).map_err( + |_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"), + )?, + data_type: raw_packet.data[33], + read_only: raw_packet.data[34] != 0, + }) + } else { + build_invalid_input_err("expected 34 bytes") + } + } + // remove property 0x11 => { + if raw_packet.data_length == 32 { + Ok(PropertyControlCommand::Remove { + property_name: String::from_utf8(raw_packet.data.to_vec()).map_err( + |_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"), + )?, + }) + } else { + build_invalid_input_err("expected 32 bytes") + } + } + // get property + 0x12 => { + if raw_packet.data_length == 33 { + Ok(PropertyControlCommand::Get { + property_name: String::from_utf8(raw_packet.data[..0x34].to_vec()) + .map_err(|_| { + io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8") + })?, + data: DataType::try_from(raw_packet.data[0x34..].to_vec())?, + }) + } else { + build_invalid_input_err("expected 33 bytes") + } + } + // set property + 0x13 => { if raw_packet.data_length == 33 { Ok(PropertyControlCommand::Set { property_name: String::from_utf8(raw_packet.data[..0x34].to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?, + .map_err(|_| { + io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8") + })?, data: DataType::try_from(raw_packet.data[0x34..].to_vec())?, }) } else { @@ -83,11 +133,13 @@ impl TryFrom for PropertyControlCommand { } } // reset property - 0x12 => { + 0x14 => { if raw_packet.data_length == 33 { Ok(PropertyControlCommand::Reset { property_name: String::from_utf8(raw_packet.data[..0x34].to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?, + .map_err(|_| { + io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8") + })?, }) } else { build_invalid_input_err("expected 33 bytes") @@ -97,9 +149,13 @@ impl TryFrom for PropertyControlCommand { 0x1A => { if raw_packet.data_length == 36 { Ok(PropertyControlCommand::Subscribe { - device_id: Identifier::from(as_u32_be(raw_packet.data[0x14..0x18].as_ref())), + device_id: Identifier::from(as_u32_be( + raw_packet.data[0x14..0x18].as_ref(), + )), property_name: String::from_utf8(raw_packet.data[0x18..0x4C].to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?, + .map_err(|_| { + io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8") + })?, }) } else { build_invalid_input_err("expected 36 bytes") @@ -109,15 +165,22 @@ impl TryFrom for PropertyControlCommand { 0x1B => { if raw_packet.data_length == 36 { Ok(PropertyControlCommand::Unsubscribe { - device_id: Identifier::from(as_u32_be(raw_packet.data[0x14..0x18].as_ref())), + device_id: Identifier::from(as_u32_be( + raw_packet.data[0x14..0x18].as_ref(), + )), property_name: String::from_utf8(raw_packet.data[0x18..0x4C].to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?, + .map_err(|_| { + io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8") + })?, }) } else { build_invalid_input_err("expected 36 bytes") } } - _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "command group is unsupported")) + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "command group is unsupported", + )), } } } diff --git a/domo_proto/src/commands/property_control/vec.rs b/domo_proto/src/commands/property_control/vec.rs index b7eee23..5cf6c0a 100644 --- a/domo_proto/src/commands/property_control/vec.rs +++ b/domo_proto/src/commands/property_control/vec.rs @@ -4,6 +4,14 @@ use crate::commands::property_control::PropertyControlCommand; impl Into> for PropertyControlCommand { fn into(self) -> Vec { match self { + PropertyControlCommand::Register { property_name, data_type, read_only } => { + let mut vec = vec![]; + vec.extend(property_name.into_bytes()); + vec.push(data_type); + vec.push(read_only as u8); + vec + }, + PropertyControlCommand::Remove { property_name } => property_name.into_bytes(), PropertyControlCommand::Get { property_name, data } => { let mut v = vec![]; v.extend(property_name.into_bytes());