pub mod codec;
use std::sync::Arc;
use codec::{CameraPacket, JpegCodec};
use futures_util::SinkExt;
use smol_str::SmolStr;
use tokio::net::TcpStream;
use tokio_rustls::{
client::TlsStream,
rustls::{
pki_types::{IpAddr, ServerName},
ClientConfig,
},
TlsConnector,
};
use tokio_util::codec::Framed;
use crate::tls::NoVerifier;
const DEFAULT_CAMERA_USERNAME: &str = "bblp";
pub struct CameraClient {
hostname: String,
access_code: String,
port: u16,
}
impl CameraClient {
pub fn new(hostname: &str, access_code: &str, port: u16) -> Self {
Self {
hostname: hostname.to_string(),
access_code: access_code.to_string(),
port,
}
}
pub async fn connect_and_stream_codec(
&self,
) -> Result<Framed<TlsStream<TcpStream>, JpegCodec>, Box<dyn std::error::Error>> {
let addr = format!("{}:{}", self.hostname, self.port);
let tcp_stream = TcpStream::connect(&addr).await?;
let config = ClientConfig::builder()
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoVerifier))
.with_no_client_auth();
let config = Arc::new(config);
let connector = TlsConnector::from(config);
let ip_address = IpAddr::try_from(self.hostname.as_str()).unwrap();
let tls_stream = connector
.connect(ServerName::IpAddress(ip_address), tcp_stream)
.await?;
let mut framed = Framed::new(tls_stream, JpegCodec::default());
framed
.send(CameraPacket::Auth {
username: DEFAULT_CAMERA_USERNAME.into(),
access_code: SmolStr::from(self.access_code.clone()),
})
.await?;
framed.flush().await?;
Ok(framed)
}
}