WIP: custom #ingest#protocol parser #23
4 changed files with 49 additions and 37 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -225,17 +225,6 @@ dependencies = [
|
|||
"syn 2.0.95",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
|
@ -1081,7 +1070,6 @@ dependencies = [
|
|||
name = "iotishnik-server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"bytes 1.9.0",
|
||||
"chrono",
|
||||
"clap",
|
||||
|
|
|
@ -6,7 +6,6 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bstr = { version = "1.9.0", features = ["serde"] }
|
||||
bytes = { version = "1.4.0", features = ["serde"] }
|
||||
chrono = { version = "0.4.26", features = ["serde"] }
|
||||
clap = { version = "4.3.8", features = ["derive", "env"] }
|
||||
|
|
|
@ -4,22 +4,36 @@ use snafu::Snafu;
|
|||
#[derive(Debug, Snafu)]
|
||||
#[snafu(visibility(pub))]
|
||||
pub enum Error {
|
||||
Incomplete,
|
||||
|
||||
#[snafu(display("Cannot parse packet: {msg}"))]
|
||||
PacketParseError { msg: &'static str },
|
||||
PacketParseError {
|
||||
msg: &'static str,
|
||||
},
|
||||
|
||||
#[snafu(display("Cannot parse MAC address: unexpected byte {value}"))]
|
||||
MacInvalidChar { value: u8 },
|
||||
MacInvalidChar {
|
||||
value: u8,
|
||||
},
|
||||
|
||||
#[snafu(display("Cannot decode as UTF-8 String"))]
|
||||
Utf8Error { source: std::string::FromUtf8Error },
|
||||
Utf8Error {
|
||||
source: std::string::FromUtf8Error,
|
||||
},
|
||||
|
||||
// TODO: can we merge these two errors?
|
||||
#[snafu(display("Cannot decode as UTF-8 &str"))]
|
||||
Utf8StrError { source: std::str::Utf8Error },
|
||||
Utf8StrError {
|
||||
source: std::str::Utf8Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Cannot parse timestamp"))]
|
||||
TimestampParseError { source: std::num::ParseFloatError },
|
||||
TimestampParseError {
|
||||
source: std::num::ParseFloatError,
|
||||
},
|
||||
|
||||
#[snafu(display("Cannot parse number"))]
|
||||
DecimalParseError { source: rust_decimal::Error },
|
||||
DecimalParseError {
|
||||
source: rust_decimal::Error,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,23 +3,25 @@ use std::str::FromStr;
|
|||
use hifitime::Epoch;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use bstr::ByteSlice;
|
||||
use snafu::ResultExt;
|
||||
|
||||
use super::error::{DecimalParseSnafu, TimestampParseSnafu, Utf8Snafu, Utf8StrSnafu};
|
||||
use crate::ingest_protocol::error::Error;
|
||||
use crate::ingest_protocol::{NMDeviceDataPacket, SensorValue};
|
||||
|
||||
pub fn parse_packet(mut input: &[u8]) -> Result<NMDeviceDataPacket, Error> {
|
||||
input = input
|
||||
.find_byte(b'#')
|
||||
.and_then(|idx| input.get(idx + 1..))
|
||||
.ok_or(Error::PacketParseError { msg: "# expected" })?;
|
||||
pub fn parse_packet(input: impl AsRef<[u8]>) -> Result<NMDeviceDataPacket, Error> {
|
||||
let input = input.as_ref();
|
||||
|
||||
let (mac, name) = {
|
||||
let idx_lf = input.find_byte(b'\n').ok_or(Error::PacketParseError {
|
||||
msg: "newline expected",
|
||||
let input = if input.first().ok_or(Error::Incomplete)? != &b'#' {
|
||||
return Err(Error::PacketParseError {
|
||||
msg: "# expected at beginning",
|
||||
})?;
|
||||
} else {
|
||||
&input[1..]
|
||||
};
|
||||
|
||||
let (input, mac, name) = {
|
||||
let idx_lf = find_byte(input, b'\n')?;
|
||||
|
||||
let mut args = input[..idx_lf].split(|b| b == &b'#');
|
||||
|
||||
|
@ -38,8 +40,7 @@ pub fn parse_packet(mut input: &[u8]) -> Result<NMDeviceDataPacket, Error> {
|
|||
None => None,
|
||||
};
|
||||
|
||||
input = &input[idx_lf..];
|
||||
(mac, name)
|
||||
(&input[idx_lf..], mac, name)
|
||||
};
|
||||
|
||||
let mut packet = NMDeviceDataPacket {
|
||||
|
@ -48,11 +49,14 @@ pub fn parse_packet(mut input: &[u8]) -> Result<NMDeviceDataPacket, Error> {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let mut input = input;
|
||||
|
||||
loop {
|
||||
input = input
|
||||
.find_byte(b'#')
|
||||
.and_then(|idx| input.get(idx + 1..))
|
||||
.ok_or(Error::PacketParseError { msg: "# expected" })?;
|
||||
// TODO: searching for # and \n duplicates code above
|
||||
|
||||
if input.first().ok_or(Error::Incomplete)? != &b'#' {
|
||||
return Err(Error::PacketParseError { msg: "# expected" })?;
|
||||
}
|
||||
|
||||
// end of packet marker
|
||||
// ##
|
||||
|
@ -60,9 +64,7 @@ pub fn parse_packet(mut input: &[u8]) -> Result<NMDeviceDataPacket, Error> {
|
|||
break;
|
||||
}
|
||||
|
||||
let idx_lf = input.find_byte(b'\n').ok_or(Error::PacketParseError {
|
||||
msg: "newline expected",
|
||||
})?;
|
||||
let idx_lf = find_byte(input, b'\n')?;
|
||||
|
||||
let mut args = input[..idx_lf].split(|b| b == &b'#');
|
||||
|
||||
|
@ -183,3 +185,12 @@ pub fn parse_mac_address(input: &[u8]) -> Result<[u8; 6], Error> {
|
|||
|
||||
Ok(mac)
|
||||
}
|
||||
|
||||
fn find_byte(haystack: &[u8], needle: u8) -> Result<usize, Error> {
|
||||
for (idx, byte) in haystack.as_ref().iter().enumerate() {
|
||||
if byte == &needle {
|
||||
return Ok(idx);
|
||||
}
|
||||
}
|
||||
Err(Error::Incomplete)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue