micodus_server/src/parser/mod.rs

470 lines
15 KiB
Rust

#![allow(unused_variables)]
mod body;
mod error;
mod header;
use body::*;
use error::*;
use header::*;
use super::db::*;
use std::collections::VecDeque;
const FLAG_DELIMITER: u8 = 0x7E;
const FLAG_DELIMITER_ESCAPE: u8 = 0x7D;
pub fn parse_inbound_msg(
rawdata: &mut InboundDataWrapper,
) -> std::result::Result<Message, MessageError> {
let mut msg: Message = Message::default();
if rawdata.first_byte() != FLAG_DELIMITER {
return Err(MessageError::NotOurProtocolError);
}
match msg.parse_header(rawdata) {
Ok(_) => {
msg.inbound_check(rawdata);
}
Err(e) => {
println!("error parsing header {e}");
return Err(MessageError::BasicError);
}
};
Ok(msg)
}
#[derive(Default, Debug)]
pub struct InboundDataWrapper {
pub data: VecDeque<u8>,
pub index: usize,
pub started: bool,
#[allow(dead_code)]
pub ended: bool,
pub escaped: Option<u8>,
}
impl InboundDataWrapper {
pub fn new(data: Vec<u8>) -> InboundDataWrapper {
InboundDataWrapper {
data: data.into(),
index: 0,
started: false,
ended: false,
escaped: None,
}
}
fn first_byte(&self) -> u8 {
self.data[0]
}
}
impl Iterator for InboundDataWrapper {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
let mut res: Option<u8> = None;
match self.escaped {
Some(o) => return Some(o),
None => {}
}
loop {
match self.data.pop_front() {
Some(o) => {
if self.started {
match o {
FLAG_DELIMITER_ESCAPE => match self.data.pop_front() {
Some(o) => match o {
0x02 => res = Some(FLAG_DELIMITER),
0x01 => res = Some(FLAG_DELIMITER_ESCAPE),
_ => {
self.escaped = Some(o);
}
},
None => res = None,
},
FLAG_DELIMITER => {
res = None;
}
_ => {
res = Some(o);
}
}
}
if o == FLAG_DELIMITER && self.index == 0 {
self.started = true;
continue;
}
}
None => {
res = None;
}
};
break;
}
self.index += 1;
res
}
}
#[derive(Default, Debug)]
pub struct Message {
pub header: MessageHeader,
pub content: MessageType,
pub body: Vec<u8>,
pub checksum: u8,
valid: bool,
}
impl Message {
#[allow(dead_code)]
pub fn new() -> Self {
let msg = Self::default();
return msg;
}
fn parse_header(
&mut self,
rawdata: &mut InboundDataWrapper,
) -> std::result::Result<(), NotOurProtocolError> {
let data = rawdata.into_iter();
self.header.set_id(u16::from_be_bytes(
vec![data.next().unwrap(), data.next().unwrap()]
.try_into()
.unwrap(),
));
self.header.set_properties(u16::from_be_bytes(
vec![data.next().unwrap(), data.next().unwrap()]
.try_into()
.unwrap(),
));
self.header.parse_properties();
let mut rtid: [u8; 6] = [0; 6];
for i in 0..rtid.len() {
rtid[i] = data.next().unwrap();
}
self.header.set_raw_terminal_id(rtid);
self.header.parse_terminal_id();
self.header.serial_number = u16::from_be_bytes(
vec![data.next().unwrap(), data.next().unwrap()]
.try_into()
.unwrap(),
);
for _ in 0..self.header.bodylength as usize {
self.body.push(data.next().unwrap());
}
self.checksum = data.next().unwrap();
self.parse_body();
Ok(())
}
pub fn inbound_check(&mut self, rawdata: &mut InboundDataWrapper) {
let data = rawdata.into_iter();
let mut check: u8 = 0;
let _ = data.map(|b| check ^= b);
self.inbound_validate(check);
}
fn inbound_validate(&mut self, check: u8) {
self.valid = check == 0;
}
fn _is_valid(&self) -> bool {
self.valid
}
fn parse_body(&mut self) {
match self.header.get_id() {
TerminalUniversalResponse::ID => {
let obj = TerminalUniversalResponse::new(&self.body);
self.content = MessageType::TerminalUniversalResponse(obj)
}
PlatformUniversalResponse::ID => {
let obj = PlatformUniversalResponse::new(&self.body);
self.content = MessageType::PlatformUniversalResponse(obj)
}
TerminalHeartbeat::ID => {
let obj = TerminalHeartbeat::new(&self.body);
self.content = MessageType::TerminalHeartbeat(obj)
}
TerminalRegistration::ID => {
let obj = TerminalRegistration::new(&self.body);
self.content = MessageType::TerminalRegistration(obj)
}
TerminalRegistrationReply::ID => {
let obj = TerminalRegistrationReply::new(&self.body);
self.content = MessageType::TerminalRegistrationReply(obj)
}
TerminalLogout::ID => {
let obj = TerminalLogout::new(&self.body);
self.content = MessageType::TerminalLogout(obj)
}
TerminalAuthentication::ID => {
let obj = TerminalAuthentication::new(&self.body);
self.content = MessageType::TerminalAuthentication(obj)
}
TerminalParameterSetting::ID => {
let obj = TerminalParameterSetting::new(&self.body);
self.content = MessageType::TerminalParameterSetting(obj)
}
QueryTerminalParameter::ID => {
let obj = QueryTerminalParameter::new(&self.body);
self.content = MessageType::QueryTerminalParameter(obj)
}
QueryTerminalParameterResponse::ID => {
let obj = QueryTerminalParameterResponse::new(&self.body);
self.content = MessageType::QueryTerminalParameterResponse(obj)
}
TerminalControl::ID => {
let obj = TerminalControl::new(&self.body);
self.content = MessageType::TerminalControl(obj)
}
LocationInformationReport::ID => {
let obj = LocationInformationReport::new(&self.body);
self.content = MessageType::LocationInformationReport(obj)
}
StartOfTrip::ID => {
let obj = StartOfTrip::new(&self.body);
self.content = MessageType::StartOfTrip(obj)
}
EndOfTrip::ID => {
let obj = EndOfTrip::new(&self.body);
self.content = MessageType::EndOfTrip(obj)
}
_ => {
let obj = TerminalUniversalResponse::new(&self.body);
self.content = MessageType::TerminalUniversalResponse(obj)
}
}
}
pub fn send_reply(inmsg: Option<Message>) -> Option<Message> {
let mut reply: Message = Message::default();
match inmsg {
Some(inmsg) => {
let terminal_id = inmsg.header.get_raw_terminal_id().clone();
match inmsg.content {
MessageType::TerminalRegistration(t) => {
let content =
t.generate_reply(terminal_id.into(), inmsg.header.serial_number);
reply.header.build(
TerminalRegistrationReply::ID,
content.to_raw().len(),
terminal_id,
);
reply.content = MessageType::TerminalRegistrationReply(content);
}
MessageType::TerminalAuthentication(t) => {
let content = t
.generate_reply(TerminalAuthentication::ID, inmsg.header.serial_number);
reply.header.build(
PlatformUniversalResponse::ID,
content.to_raw().len(),
terminal_id,
);
reply.content = MessageType::PlatformUniversalResponse(content);
}
MessageType::LocationInformationReport(t) => {
let content = t.generate_reply(
LocationInformationReport::ID,
inmsg.header.serial_number,
);
reply.header.build(
PlatformUniversalResponse::ID,
content.to_raw().len(),
terminal_id,
);
reply.content = MessageType::PlatformUniversalResponse(content);
}
MessageType::TerminalHeartbeat(t) => {
let content =
t.generate_reply(TerminalHeartbeat::ID, inmsg.header.serial_number);
reply.header.build(
PlatformUniversalResponse::ID,
content.to_raw().len(),
terminal_id,
);
reply.content = MessageType::PlatformUniversalResponse(content);
}
MessageType::TerminalLogout(t) => {
let content =
t.generate_reply(TerminalHeartbeat::ID, inmsg.header.serial_number);
reply.header.build(
PlatformUniversalResponse::ID,
content.to_raw().len(),
terminal_id,
);
reply.content = MessageType::PlatformUniversalResponse(content);
}
_ => {
println!("no type");
return None;
}
}
}
None => {}
}
reply.outbound_finalize();
Some(reply)
}
pub fn store(inmsg: &Message) -> Option<DbLog> {
let res = match inmsg.content {
MessageType::LocationInformationReport(ref t) => Some(DbLog {
serial: inmsg.header.serial_number,
time: t.time.format("%Y-%m-%d %H:%M:%S").to_string(),
latitude: t.latitude,
longitude: t.longitude,
speed: t.speed,
height: t.height,
direction: t.direction,
is_satellite: t.is_satellite(),
}),
_ => None,
};
res
}
pub fn outbound_finalize(&mut self) {
let mut checksum: u8 = 0;
for v in vec![self.header.to_raw(), self.content.to_raw()] {
for b in v {
checksum = checksum ^ b;
}
}
self.checksum = checksum;
self.valid = true;
}
pub fn to_raw(&self) -> VecDeque<u8> {
let mut resp: VecDeque<u8> = VecDeque::new();
for b in self.header.to_raw() {
for i in Self::escape_outbound(b) {
resp.push_back(i);
}
}
for b in self.content.to_raw() {
for i in Self::escape_outbound(b) {
resp.push_back(i);
}
}
resp.push_back(self.checksum);
resp.push_front(FLAG_DELIMITER);
resp.push_back(FLAG_DELIMITER);
resp
}
fn escape_outbound(in_data: u8) -> Vec<u8> {
let mut res: Vec<u8> = Vec::new();
match in_data {
FLAG_DELIMITER => res = vec![FLAG_DELIMITER_ESCAPE, 0x02],
FLAG_DELIMITER_ESCAPE => res = vec![FLAG_DELIMITER_ESCAPE, 0x01],
_ => {
res.push(in_data);
}
}
res
}
}
impl std::fmt::Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Message: (header: {}), (content: {}), checksum: {}, valid: {}",
self.header, self.content, self.checksum, self.valid
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum MessageType {
None,
TerminalUniversalResponse(TerminalUniversalResponse),
PlatformUniversalResponse(PlatformUniversalResponse),
TerminalHeartbeat(TerminalHeartbeat),
TerminalRegistration(TerminalRegistration),
TerminalRegistrationReply(TerminalRegistrationReply),
TerminalLogout(TerminalLogout),
TerminalAuthentication(TerminalAuthentication),
TerminalParameterSetting(TerminalParameterSetting),
QueryTerminalParameter(QueryTerminalParameter),
QueryTerminalParameterResponse(QueryTerminalParameterResponse),
TerminalControl(TerminalControl),
LocationInformationReport(LocationInformationReport),
StartOfTrip(StartOfTrip),
EndOfTrip(EndOfTrip),
}
impl Default for MessageType {
fn default() -> Self {
Self::None
}
}
impl BodyMessage for MessageType {
fn to_raw(&self) -> Vec<u8> {
let res = match self {
MessageType::TerminalRegistrationReply(o) => o.to_raw(),
MessageType::PlatformUniversalResponse(o) => o.to_raw(),
//MessageType::TerminalHeartbeat(o) => o.to_raw(),
_ => vec![],
};
res
}
}
impl std::fmt::Display for MessageType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let res = match self {
MessageType::TerminalRegistration(o) => o.fmt(f),
MessageType::LocationInformationReport(o) => o.fmt(f),
MessageType::TerminalHeartbeat(o) => o.fmt(f),
MessageType::TerminalAuthentication(o) => o.fmt(f),
_ => write!(f, "{:?}", self),
};
res
}
}
/*
{
use std::fs::OpenOptions;
use std::io::prelude::*;
let mut file = OpenOptions::new()
.write(true)
.append(true)
.open("data/log.txt")
.unwrap();
//if let Err(e) = writeln!(file, ) {
// eprintln!("Couldn't write to file: {}", e);
//}
file.write(format!("{},{},{}\n", t.time, t.latitude, t.longitude).as_bytes())
.unwrap();
}
*/