From 824e382e8908df274f5f778ea37e9bd68c8c4d2f Mon Sep 17 00:00:00 2001 From: nm17 Date: Fri, 23 Feb 2024 20:51:32 +0400 Subject: [PATCH] feat(ingest_protocol): improve parser --- src/{protocol => ingest_protocol}/error.rs | 5 +- src/{protocol => ingest_protocol}/mod.rs | 3 + .../packet_types.rs | 10 +- src/{protocol => ingest_protocol}/parser.rs | 120 ++++++++++-------- src/{protocol => ingest_protocol}/server.rs | 0 src/ingest_protocol/tests/mod.rs | 37 ++++++ src/main.rs | 32 +---- src/web_server/old_app_api/types/mod.rs | 1 + 8 files changed, 124 insertions(+), 84 deletions(-) rename src/{protocol => ingest_protocol}/error.rs (78%) rename src/{protocol => ingest_protocol}/mod.rs (77%) rename src/{protocol => ingest_protocol}/packet_types.rs (79%) rename src/{protocol => ingest_protocol}/parser.rs (50%) rename src/{protocol => ingest_protocol}/server.rs (100%) create mode 100644 src/ingest_protocol/tests/mod.rs diff --git a/src/protocol/error.rs b/src/ingest_protocol/error.rs similarity index 78% rename from src/protocol/error.rs rename to src/ingest_protocol/error.rs index 3c9d1b6..037bb1a 100644 --- a/src/protocol/error.rs +++ b/src/ingest_protocol/error.rs @@ -12,5 +12,8 @@ pub enum Error { TimestampParseError(ParseFloatError), #[error("Oops it blew up")] - UnknownUnit(I) + UnknownUnit(I), + + #[error("Oops it blew up")] + DecimalParseError(#[from] rust_decimal::Error) } \ No newline at end of file diff --git a/src/protocol/mod.rs b/src/ingest_protocol/mod.rs similarity index 77% rename from src/protocol/mod.rs rename to src/ingest_protocol/mod.rs index e292848..2ec627c 100644 --- a/src/protocol/mod.rs +++ b/src/ingest_protocol/mod.rs @@ -3,5 +3,8 @@ pub mod error; pub mod parser; mod server; +#[cfg(test)] +mod tests; + pub use packet_types::*; diff --git a/src/protocol/packet_types.rs b/src/ingest_protocol/packet_types.rs similarity index 79% rename from src/protocol/packet_types.rs rename to src/ingest_protocol/packet_types.rs index 36f0d74..504a0d7 100644 --- a/src/protocol/packet_types.rs +++ b/src/ingest_protocol/packet_types.rs @@ -6,7 +6,7 @@ use rust_decimal::Decimal; use crate::hashes::SupportedUnit; #[derive(Debug, Clone)] -pub struct NarodMonValues<'a> { +pub struct SensorValue<'a> { pub mac: Cow<'a, str>, pub value: Decimal, pub time: Option, @@ -14,19 +14,19 @@ pub struct NarodMonValues<'a> { pub name: Option>, } -impl<'a> Hash for NarodMonValues<'a> { +impl<'a> Hash for SensorValue<'a> { fn hash(&self, state: &mut H) { self.mac.hash(state); } } -impl<'a> PartialEq for NarodMonValues<'a> { +impl<'a> PartialEq for SensorValue<'a> { fn eq(&self, other: &Self) -> bool { self.mac == other.mac } } -impl<'a> Eq for NarodMonValues<'a> { +impl<'a> Eq for SensorValue<'a> { } @@ -34,7 +34,7 @@ impl<'a> Eq for NarodMonValues<'a> { pub struct NarodMonPacket<'a> { pub mac: [u8; 6], pub name: Option>, - pub values: HashSet>, + pub values: HashSet>, pub owner: Option>, pub lat: Option, pub lon: Option, diff --git a/src/protocol/parser.rs b/src/ingest_protocol/parser.rs similarity index 50% rename from src/protocol/parser.rs rename to src/ingest_protocol/parser.rs index 635b573..c202a63 100644 --- a/src/protocol/parser.rs +++ b/src/ingest_protocol/parser.rs @@ -10,6 +10,7 @@ use nom::bytes::complete::tag; use nom::bytes::streaming::take_till; use nom::character::streaming::{anychar, char, hex_digit0, newline}; use nom::character::complete::hex_digit1; +use nom::character::is_digit; use nom::combinator::{map, map_opt, map_parser, opt, recognize, rest}; use nom::Err as NomErr; @@ -17,9 +18,9 @@ use nom::error::{context, ContextError, ErrorKind as NomErrorKind, ParseError as use nom::multi::{count, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, separated_pair}; use rust_decimal::Decimal; -use crate::protocol::error::Error; -use crate::protocol::{NarodMonPacket, NarodMonValues}; -use crate::protocol::error::Error::TimestampParseError; +use crate::ingest_protocol::error::Error; +use crate::ingest_protocol::{NarodMonPacket, SensorValue}; +use crate::ingest_protocol::error::Error::TimestampParseError; type MyIError = Result<(I, O), Error>; @@ -32,7 +33,6 @@ pub fn parse_mac_address(input: &str) -> MyIError<&str, [u8; 6]> { let (leftovers, i) = context("17 символов для MAC адреса", take(17usize))(input)?; let (_, out) = count(|inp| { - //dbg!(inp); let (mut i, o) = context("Октет", map_parser(take(2usize), hex_digit1))(inp)?; if counter != 5 { (i, _) = tag("-")(i)?; @@ -41,65 +41,61 @@ pub fn parse_mac_address(input: &str) -> MyIError<&str, [u8; 6]> { Ok((i, o)) }, 6)(i)?; - //dbg!(&out); - hex::decode_to_slice(out.join(""), &mut mac).unwrap(); Ok((leftovers, mac)) } -pub fn parse_packet(input: &str) -> MyIError<&str, NarodMonPacket> { - let (input, _) = tag("#")(input)?; +fn handle_special_sensor_macs ( + mac: &str, + sensor_value: &str, + packet: &mut NarodMonPacket, +) -> Result> { + match mac.to_uppercase().as_str() { + "LAT" => packet.lat = Some(Decimal::from_str(sensor_value)?), + "LON" => packet.lon = Some(Decimal::from_str(sensor_value)?), + "ALT" => packet.alt = Some(Decimal::from_str(sensor_value)?), + _ => { + return Ok(false); + } + } + return Ok(true); +} - let (input, mac) = parse_mac_address(input)?; +pub fn parse_packet_body<'a>(line: &'a str, packet: &mut NarodMonPacket<'a>) -> MyIError<&'a str, ()> { + let (line, _) = tag("#")(line)?; + let (line, sensor_mac) = take_while1(|c| c != '\n' && c != '#')(line)?; - let (input, opt_name) = opt(delimited(tag("#"), take_while(|c| c != '\n'), tag("\n")))(input)?; + let (line, _) = tag("#")(line)?; - let mut packet = NarodMonPacket::default(); - packet.mac = mac; + match sensor_mac { + "OWNER" => { + let (line, owner_value) = take_while1(|c| c != '\n')(line)?; - let mut hs = HashSet::new(); + packet.owner = Some(owner_value.into()) - let (input, asd) = context( - "Получение значений до тега терминатора", - map_parser( - take_until1("##"), - separated_list0(tag("\n"), take_while1(|c| c != '\n')) - ) - )(input)?; + //hs.insert(NarodMonValues::Owner(owner_value.into())); + //let (line, _) = tag("\n")(line)?; + } + _ => { + let (line, sensor_value) = take_while1(|c| c != '\n' && c != '#')(line)?; + let (line, sensor_time) = opt(preceded(tag("#"), take_while1(|c| c != '\n' && c != '#' && "1234567890.".contains(c))))(line)?; + let (line, sensor_name) = opt(preceded(tag("#"), take_while1(|c| c != '\n')))(line)?; - println!("ASDASD: {:?}", asd); + let sensor_time = match sensor_time { + Some(v) => Some( + Epoch::from_unix_seconds( + v.parse().map_err(|e| TimestampParseError(e))? + ) + ), + None => None + }; - for line in asd { - let (line, _) = tag("#")(line)?; - let (line, sensor_mac) = take_while1(|c| c != '\n' && c != '#')(line)?; - - let (line, _) = tag("#")(line)?; - - match sensor_mac { - "OWNER" => { - let (line, owner_value) = take_while1(|c| c != '\n')(line)?; - - packet.owner = Some(owner_value.into()) - - //hs.insert(NarodMonValues::Owner(owner_value.into())); - //let (line, _) = tag("\n")(line)?; - } - _ => { - let (line, sensor_value) = take_while1(|c| c != '\n' && c != '#')(line)?; - let (line, sensor_time) = opt(preceded(tag("#"), take_while1(|c| c != '\n' && c != '#')))(line)?; - let (line, sensor_name) = opt(preceded(tag("#"), take_while1(|c| c != '\n')))(line)?; - - - let sensor_time = match sensor_time { - Some(v) => Some(Epoch::from_unix_seconds(v.parse().map_err(|e| TimestampParseError(e))?)), - None => None - }; - - hs.insert(NarodMonValues { + if !handle_special_sensor_macs(sensor_mac, sensor_value, packet)? { + packet.values.insert(SensorValue { mac: sensor_mac.into(), - value: Decimal::from_str(sensor_value).unwrap(), + value: Decimal::from_str(sensor_value)?, time: sensor_time, // TODO unit: None, name: sensor_name.map(|v| Cow::from(v)), @@ -108,10 +104,34 @@ pub fn parse_packet(input: &str) -> MyIError<&str, NarodMonPacket> { } } + return Ok((line, ())) +} + +pub fn parse_packet(input: &str) -> MyIError<&str, NarodMonPacket> { + let (input, _) = tag("#")(input)?; + + let (input, device_mac) = parse_mac_address(input)?; + + let (input, opt_name) = opt(delimited(tag("#"), take_while(|c| c != '\n'), tag("\n")))(input)?; + + let mut packet = NarodMonPacket::default(); + packet.mac = device_mac; + + let (input, lines) = context( + "Получение значений до тега терминатора", + map_parser( + take_until1("##"), + separated_list0(tag("\n"), take_while1(|c| c != '\n')) + ) + )(input)?; + + for line in lines { + parse_packet_body(line, &mut packet)?; + } + let (input, _) = tag("##")(input)?; packet.name = opt_name.map(|v| Cow::from(v)); - packet.values = hs; Ok((input, packet)) } \ No newline at end of file diff --git a/src/protocol/server.rs b/src/ingest_protocol/server.rs similarity index 100% rename from src/protocol/server.rs rename to src/ingest_protocol/server.rs diff --git a/src/ingest_protocol/tests/mod.rs b/src/ingest_protocol/tests/mod.rs new file mode 100644 index 0000000..73ed710 --- /dev/null +++ b/src/ingest_protocol/tests/mod.rs @@ -0,0 +1,37 @@ +use crate::ingest_protocol::parser::{parse_mac_address, parse_packet}; + +#[test] +fn test_asd() { + let asd = r#" +#A2-C6-47-01-DF-E1#Метео +#OWNER#unknown +#T1#13.44#Outdoor +#T2#27.74#Indoor +#P1#691.02#Barometer +#LAT#55.738178 +#LON#37.6068 +#ALT#38 +## +"#.trim(); + dbg!(parse_packet(asd)); +} + +#[test] +fn test_mac() { + //assert_eq!(parse_mac_address("12-34-AA-12-55-AA"), Ok(("", [18, 52, 170, 18, 85, 170])) ); + + println!("{:?}", parse_mac_address("12-34-AA-12-55-AA")); +} + +#[test] +fn test_packet() { + let inp = r#"#26-94-1D-75-C2-F8#Метео +#OWNER#nm17 +#T1#1.12 +#T2#10000#1231410321#sensorName +#T2#1.2#3400005345 +##"#; + + + println!("{:#?}", parse_packet(inp)); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c416024..9ed99b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,7 +38,7 @@ extern crate core; mod hashes; mod web_server; -mod protocol; +mod ingest_protocol; use std::borrow::Cow; use std::collections::{BTreeSet, HashMap, HashSet}; @@ -50,9 +50,9 @@ use axum::routing::post; use hifitime::Epoch; use rust_decimal::Decimal; -use crate::protocol::{NarodMonPacket, NarodMonValues}; -use crate::protocol::error::Error; -use crate::protocol::error::Error::TimestampParseError; +use crate::ingest_protocol::{NarodMonPacket, SensorValue}; +use crate::ingest_protocol::error::Error; +use crate::ingest_protocol::error::Error::TimestampParseError; use crate::web_server::old_app_api::old_api_handler; use crate::web_server::server_main; @@ -84,28 +84,4 @@ async fn main() { web_server_hndl.await.unwrap(); } -#[cfg(test)] -mod tests { - use crate::protocol::parser::{parse_mac_address, parse_packet}; - use super::*; - #[test] - fn test_mac() { - //assert_eq!(parse_mac_address("12-34-AA-12-55-AA"), Ok(("", [18, 52, 170, 18, 85, 170])) ); - - println!("{:?}", parse_mac_address("12-34-AA-12-55-AA")); - } - - #[test] - fn test_packet() { - let inp = r#"#26-94-1D-75-C2-F8#Метео -#OWNER#nm17 -#T1#1.12 -#T2#10000#1231410321#sensorName -#T2#1.2#3400005345 -##"#; - - - println!("{:#?}", parse_packet(inp)); - } -} diff --git a/src/web_server/old_app_api/types/mod.rs b/src/web_server/old_app_api/types/mod.rs index 7842745..2241015 100644 --- a/src/web_server/old_app_api/types/mod.rs +++ b/src/web_server/old_app_api/types/mod.rs @@ -20,6 +20,7 @@ pub struct AppInitRequest<'a> { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AddLikeRequest { + /// TODO: WTF is this? i dont remember pub version: u64, }