robotrt-cli 0.1.0-beta.1

RobotRT modular robotics runtime and middleware components.
use std::time::Duration;

use crate::helpers::{first_positional, has_flag, parse_u64_option, parse_usize_option};

use super::data_source::load_status_snapshot;
use super::info::action_matches;

pub(super) fn action_watch(args: &[String]) -> Result<(), String> {
    let json = has_flag(args, "--json");
    let iterations = parse_usize_option(args, "--iterations", 1)?;
    let interval_ms = parse_u64_option(args, "--interval-ms", 1000)?;
    let action_name = first_positional(args);

    let mut snapshots = Vec::new();
    let mut source_meta = serde_json::json!({"mode": "unknown"});
    let mut source_label = String::from("unknown");
    let mut latest_captured_at_unix_nanos = 0u128;

    for idx in 0..iterations {
        let (snapshot, source) = load_status_snapshot(args)?;
        source_meta = source.json;
        source_label = source.label;
        latest_captured_at_unix_nanos = snapshot.captured_at_unix_nanos;

        let actions = snapshot
            .actions
            .iter()
            .filter(|action| {
                action_name
                    .as_ref()
                    .map(|name| action_matches(&action.name, name))
                    .unwrap_or(true)
            })
            .cloned()
            .collect::<Vec<_>>();

        snapshots.push(serde_json::json!({
            "iteration": idx + 1,
            "captured_at_unix_nanos": snapshot.captured_at_unix_nanos,
            "actions": actions,
        }));

        if idx + 1 < iterations {
            std::thread::sleep(Duration::from_millis(interval_ms));
        }
    }

    if json {
        let payload = serde_json::json!({
            "api_version": "robotrt.action.watch.v1",
            "kind": "action_watch",
            "captured_at_unix_nanos": latest_captured_at_unix_nanos,
            "source": source_meta,
            "query": {
                "action_name": action_name,
                "iterations": iterations,
                "interval_ms": interval_ms,
            },
            "result": {
                "samples": snapshots,
            },
        });
        println!(
            "{}",
            serde_json::to_string_pretty(&payload)
                .map_err(|err| format!("serialize action watch failed: {err}"))?
        );
    } else {
        println!("RobotRT Action Watch");
        println!("source: {}", source_label);
        for snapshot in snapshots {
            println!("{}", snapshot);
        }
    }

    Ok(())
}

pub(super) fn mission_watch(args: &[String]) -> Result<(), String> {
    let json = has_flag(args, "--json");
    let iterations = parse_usize_option(args, "--iterations", 1)?;
    let interval_ms = parse_u64_option(args, "--interval-ms", 1000)?;
    let mission_name = first_positional(args);

    let mut snapshots = Vec::new();
    let mut source_meta = serde_json::json!({"mode": "unknown"});
    let mut source_label = String::from("unknown");
    let mut latest_captured_at_unix_nanos = 0u128;

    for idx in 0..iterations {
        let (snapshot, source) = load_status_snapshot(args)?;
        source_meta = source.json;
        source_label = source.label;
        latest_captured_at_unix_nanos = snapshot.captured_at_unix_nanos;

        let missions = snapshot
            .missions
            .iter()
            .filter(|mission| {
                mission_name
                    .as_ref()
                    .map(|name| mission.name == *name)
                    .unwrap_or(true)
            })
            .cloned()
            .collect::<Vec<_>>();

        snapshots.push(serde_json::json!({
            "iteration": idx + 1,
            "captured_at_unix_nanos": snapshot.captured_at_unix_nanos,
            "missions": missions,
        }));

        if idx + 1 < iterations {
            std::thread::sleep(Duration::from_millis(interval_ms));
        }
    }

    if json {
        let payload = serde_json::json!({
            "api_version": "robotrt.mission.watch.v1",
            "kind": "mission_watch",
            "captured_at_unix_nanos": latest_captured_at_unix_nanos,
            "source": source_meta,
            "query": {
                "mission_name": mission_name,
                "iterations": iterations,
                "interval_ms": interval_ms,
            },
            "result": {
                "samples": snapshots,
            },
        });
        println!(
            "{}",
            serde_json::to_string_pretty(&payload)
                .map_err(|err| format!("serialize mission watch failed: {err}"))?
        );
    } else {
        println!("RobotRT Mission Watch");
        println!("source: {}", source_label);
        for snapshot in snapshots {
            println!("{}", snapshot);
        }
    }

    Ok(())
}