use super::net_handle;
pub use crate::wire::{WebcamStatus, WebcamStream};
pub(crate) mod ops {
use serde_json::json;
use crate::error::{Error, Result};
use crate::nets::debug::base64_decode;
use crate::wire::{
net_command, value_as, CommandResponse, Op, Timeout, WebcamStatus, WebcamStream,
};
const ROLE: &str = "webcam";
fn parse_stopped(resp: CommandResponse) -> Result<bool> {
let status: WebcamStopped = value_as(resp)?;
Ok(status.stopped)
}
#[derive(serde::Deserialize)]
struct WebcamStopped {
#[serde(default)]
stopped: bool,
}
fn parse_url(resp: CommandResponse) -> Result<Option<String>> {
let status: WebcamStatus = value_as(resp)?;
Ok(status.url)
}
pub(crate) fn start(name: &str) -> Op<WebcamStream> {
start_with(name, json!({}))
}
pub(crate) fn start_as(name: &str, source: &str, started_by: Option<&str>) -> Op<WebcamStream> {
let mut params = json!({ "source": source });
if let Some(who) = started_by {
params["started_by"] = json!(who);
}
start_with(name, params)
}
fn start_with(name: &str, params: serde_json::Value) -> Op<WebcamStream> {
Op {
req: net_command(
name,
ROLE,
"start",
params,
Timeout::After(std::time::Duration::from_secs(30)),
),
parse: value_as::<WebcamStream>,
}
}
#[derive(serde::Deserialize)]
struct Snapshot {
jpeg_base64: String,
}
fn parse_snapshot(resp: CommandResponse) -> Result<Vec<u8>> {
let snap: Snapshot = value_as(resp)?;
base64_decode(&snap.jpeg_base64)
.ok_or_else(|| Error::Decode("snapshot 'jpeg_base64' is not valid base64".to_string()))
}
pub(crate) fn snapshot(name: &str) -> Op<Vec<u8>> {
Op {
req: net_command(
name,
ROLE,
"snapshot",
json!({}),
Timeout::After(std::time::Duration::from_secs(20)),
),
parse: parse_snapshot,
}
}
pub(crate) fn stop(name: &str) -> Op<bool> {
Op {
req: net_command(name, ROLE, "stop", json!({}), Timeout::Default),
parse: parse_stopped,
}
}
pub(crate) fn status(name: &str) -> Op<WebcamStatus> {
Op {
req: net_command(name, ROLE, "status", json!({}), Timeout::Default),
parse: value_as::<WebcamStatus>,
}
}
pub(crate) fn url(name: &str) -> Op<Option<String>> {
Op {
req: net_command(name, ROLE, "url", json!({}), Timeout::Default),
parse: parse_url,
}
}
}
net_handle! {
sync: Webcam,
async: AsyncWebcam,
methods: {
fn start() -> WebcamStream = ops::start;
fn start_as(source: &str, started_by: Option<&str>) -> WebcamStream = ops::start_as;
fn stop() -> bool = ops::stop;
fn status() -> WebcamStatus = ops::status;
fn url() -> Option<String> = ops::url;
}
}
#[cfg(feature = "blocking")]
impl Webcam<'_> {
pub fn snapshot(&self) -> crate::error::Result<Vec<u8>> {
self.client
.run(ops::snapshot(&self.name))
.map_err(|e| crate::wire::unknown_action_compat(e, "snapshot", ">= 0.47.0"))
}
}
#[cfg(feature = "async")]
impl AsyncWebcam<'_> {
pub async fn snapshot(&self) -> crate::error::Result<Vec<u8>> {
self.client
.run(ops::snapshot(&self.name))
.await
.map_err(|e| crate::wire::unknown_action_compat(e, "snapshot", ">= 0.47.0"))
}
}