This commit is contained in:
Dominik Werder
2021-11-05 21:22:23 +01:00
parent daf3f6c14c
commit 8c7dbf9ed3
33 changed files with 527 additions and 260 deletions

View File

@@ -2,7 +2,10 @@
name = "netfetch"
version = "0.0.1-a.0"
authors = ["Dominik Werder <dominik.werder@gmail.com>"]
edition = "2018"
edition = "2021"
[lib]
path = "src/netfetch.rs"
[dependencies]
serde = { version = "1.0", features = ["derive"] }

100
netfetch/src/bsread.rs Normal file
View File

@@ -0,0 +1,100 @@
use crate::zmtp::ZmtpMessage;
use err::Error;
#[allow(unused)]
use netpod::log::*;
use netpod::ByteOrder;
use netpod::ScalarType;
use netpod::Shape;
use serde::Deserialize;
use serde_json::Value as JsVal;
use std::fmt;
// TODO
pub struct ParseError {
pub err: Error,
pub msg: ZmtpMessage,
}
#[derive(Debug, Deserialize)]
pub struct GlobalTimestamp {
sec: u64,
ns: u64,
}
#[derive(Debug, Deserialize)]
pub struct ChannelDesc {
name: String,
#[serde(rename = "type")]
ty: String,
shape: JsVal,
encoding: String,
}
#[derive(Debug, Deserialize)]
pub struct HeadA {
htype: String,
hash: String,
pulse_id: serde_json::Number,
global_timestamp: GlobalTimestamp,
}
#[derive(Debug, Deserialize)]
pub struct HeadB {
htype: String,
channels: Vec<ChannelDesc>,
}
#[derive(Debug)]
pub struct BsreadMessage {
head_a: HeadA,
head_b: HeadB,
values: Vec<Box<dyn fmt::Debug>>,
}
pub fn parse_zmtp_message(msg: &ZmtpMessage) -> Result<BsreadMessage, Error> {
if msg.frames().len() < 3 {
return Err(Error::with_msg_no_trace("not enough frames for bsread"));
}
let head_a: HeadA = serde_json::from_slice(&msg.frames()[0].data())?;
let head_b: HeadB = serde_json::from_slice(&msg.frames()[1].data())?;
let mut values = vec![];
if msg.frames().len() == head_b.channels.len() + 3 {
for (ch, fr) in head_b.channels.iter().zip(msg.frames()[2..].iter()) {
let sty = ScalarType::from_bsread_str(ch.ty.as_str())?;
let bo = ByteOrder::from_bsread_str(&ch.encoding)?;
let shape = Shape::from_bsread_jsval(&ch.shape)?;
match sty {
ScalarType::I64 => match &bo {
ByteOrder::LE => match &shape {
Shape::Scalar => {
assert_eq!(fr.data().len(), 8);
let v = i64::from_le_bytes(fr.data().try_into()?);
values.push(Box::new(v) as _);
}
Shape::Wave(_) => {}
Shape::Image(_, _) => {}
},
_ => {}
},
_ => {}
}
}
}
{
let fr = &msg.frames()[msg.frames().len() - 1];
if fr.data().len() == 8 {
let pulse = u64::from_le_bytes(fr.data().try_into()?);
info!("pulse {}", pulse);
}
}
let ret = BsreadMessage { head_a, head_b, values };
Ok(ret)
}
pub struct BsreadCollector {}
impl BsreadCollector {
pub fn new<S: Into<String>>(_addr: S) -> Self {
err::todoval()
}
}

View File

@@ -1,3 +1,4 @@
pub mod bsread;
pub mod ca;
#[cfg(test)]
pub mod test;

View File

@@ -9,6 +9,18 @@ use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio::net::TcpStream;
use crate::bsread::parse_zmtp_message;
#[test]
fn test_listen() -> Result<(), Error> {
use std::time::Duration;
let fut = async move {
let _ = tokio::time::timeout(Duration::from_millis(16000), zmtp_client("camtest:9999")).await;
Ok::<_, Error>(())
};
taskrun::run(fut)
}
pub async fn zmtp_00() -> Result<(), Error> {
let addr = "S10-CPPM-MOT0991:9999";
zmtp_client(addr).await?;
@@ -18,8 +30,32 @@ pub async fn zmtp_00() -> Result<(), Error> {
pub async fn zmtp_client(addr: &str) -> Result<(), Error> {
let conn = tokio::net::TcpStream::connect(addr).await?;
let mut zmtp = Zmtp::new(conn);
while let Some(ev) = zmtp.next().await {
info!("got zmtp event: {:?}", ev);
let mut i1 = 0;
while let Some(item) = zmtp.next().await {
match item {
Ok(ev) => match ev {
ZmtpEvent::ZmtpMessage(msg) => {
info!("Message frames: {}", msg.frames.len());
match parse_zmtp_message(&msg) {
Ok(msg) => info!("{:?}", msg),
Err(e) => {
error!("{}", e);
for frame in &msg.frames {
info!("Frame: {:?}", frame);
}
}
}
}
},
Err(e) => {
error!("{}", e);
return Err(e);
}
}
i1 += 1;
if i1 > 100 {
break;
}
}
Ok(())
}
@@ -36,6 +72,7 @@ enum ConnState {
struct Zmtp {
done: bool,
complete: bool,
conn: TcpStream,
conn_state: ConnState,
buf: NetBuf,
@@ -55,6 +92,7 @@ impl Zmtp {
//info!("recv_buffer_size {:8}", conn.recv_buffer_size()?);
Self {
done: false,
complete: false,
conn,
conn_state: ConnState::InitSend,
buf: NetBuf::new(),
@@ -238,30 +276,46 @@ impl NetBuf {
}
#[derive(Debug)]
struct ZmtpMessage {
pub struct ZmtpMessage {
frames: Vec<ZmtpFrame>,
}
struct ZmtpFrame {
impl ZmtpMessage {
pub fn frames(&self) -> &Vec<ZmtpFrame> {
&self.frames
}
}
pub struct ZmtpFrame {
msglen: usize,
has_more: bool,
is_command: bool,
data: Vec<u8>,
}
impl ZmtpFrame {
pub fn data(&self) -> &[u8] {
&self.data
}
}
impl fmt::Debug for ZmtpFrame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = String::from_utf8(self.data.clone()).unwrap_or_else(|_| String::new());
let s = if s.is_ascii() && !s.contains("\x00") {
s
} else {
"...".into()
let data = match String::from_utf8(self.data.clone()) {
Ok(s) => s
.chars()
.filter(|x| {
//
x.is_ascii_alphanumeric() || x.is_ascii_punctuation() || x.is_ascii_whitespace()
})
.collect::<String>(),
Err(_) => format!("Binary {{ len: {} }}", self.data.len()),
};
f.debug_struct("ZmtpFrame")
.field("msglen", &self.msglen)
.field("has_more", &self.has_more)
.field("is_command", &self.is_command)
.field("data", &s)
.field("data", &data)
.finish()
}
}
@@ -276,7 +330,10 @@ impl Stream for Zmtp {
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
use Poll::*;
if self.done {
if self.complete {
panic!("poll_next on complete")
} else if self.done {
self.complete = true;
return Ready(None);
}
'outer: loop {