e9a5e4e34a
* stop using deprecated failure crate and its deps * more uniformly detailed error messages * an enum of the type of error, currently internal-only. I'm not confident enough I understand what cases a caller might want to distinguish, so I added a comment inviting input instead of exposing it now. * while I'm at it, separate connection context and message contexts. This shrinks some of the data memmoved around in PacketItem and CodecItem.
50 lines
1.4 KiB
Rust
50 lines
1.4 KiB
Rust
// Copyright (C) 2021 Scott Lamb <slamb@slamb.org>
|
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
use anyhow::{anyhow, Error};
|
|
use futures::StreamExt;
|
|
use log::info;
|
|
use retina::codec::CodecItem;
|
|
|
|
#[derive(structopt::StructOpt)]
|
|
pub struct Opts {
|
|
#[structopt(flatten)]
|
|
src: super::Source,
|
|
}
|
|
|
|
pub async fn run(opts: Opts) -> Result<(), Error> {
|
|
let stop = tokio::signal::ctrl_c();
|
|
|
|
let creds = super::creds(opts.src.username, opts.src.password);
|
|
let mut session = retina::client::Session::describe(opts.src.url, creds).await?;
|
|
let onvif_stream_i = session
|
|
.streams()
|
|
.iter()
|
|
.position(|s| matches!(s.parameters(), Some(retina::codec::Parameters::Message(..))))
|
|
.ok_or_else(|| anyhow!("couldn't find onvif stream"))?;
|
|
session.setup(onvif_stream_i).await?;
|
|
let session = session
|
|
.play(retina::client::PlayPolicy::default().ignore_zero_seq(true))
|
|
.await?
|
|
.demuxed()?;
|
|
|
|
tokio::pin!(session);
|
|
tokio::pin!(stop);
|
|
loop {
|
|
tokio::select! {
|
|
item = session.next() => {
|
|
match item.ok_or_else(|| anyhow!("EOF"))?? {
|
|
CodecItem::MessageFrame(m) => {
|
|
info!("{}: {}\n", &m.timestamp, std::str::from_utf8(&m.data[..]).unwrap());
|
|
},
|
|
_ => continue,
|
|
};
|
|
},
|
|
_ = &mut stop => {
|
|
break;
|
|
},
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|