Skip to main content

ops/
lib.rs

1//! The `rxp` commands as functions. `cli` wraps them in clap and prints
2//! through [`Stdio`]; `daemon` runs them as jobs and collects their lines.
3//! Every command takes a [`Ctx`] (the former global flags) and, when it has
4//! anything to say, a `&mut dyn Progress`.
5
6pub mod capture;
7pub mod config;
8pub mod display;
9pub mod firmware;
10pub mod flash;
11pub mod ingest;
12pub mod model;
13pub mod params;
14pub mod probe;
15pub mod provision;
16pub mod restore;
17pub mod screen;
18pub mod upgrade;
19pub mod util;
20
21pub use colorlight as protocol;
22pub use panelspec;
23pub use panelspec::{read_library, Loader};
24pub use rcvbp;
25pub use receivers;
26
27use receivers::CardModel;
28
29use anyhow::{Context, Result};
30use std::io::{IsTerminal, Write};
31
32/// The former global flags.
33#[derive(Clone, Debug)]
34pub struct Ctx {
35    /// Network interface directly connected to the receiving card.
36    pub iface: String,
37    /// Panel size used when no layout file is given.
38    pub width: u16,
39    pub height: u16,
40    /// Color order on the wire.
41    pub order: protocol::ColorOrder,
42    /// Brightness 0-255, sent in sync frames.
43    pub brightness: u8,
44    /// The card's model: `--card`, the daemon's `card` setting, or what
45    /// discovery returned; `None` until one of those has named it.
46    pub model: Option<&'static CardModel>,
47}
48
49impl Ctx {
50    /// The card model a flash or configuration command works from.
51    ///
52    /// # Errors
53    /// Fails when nothing has named the card yet.
54    pub fn model(&self) -> Result<&'static CardModel> {
55        self.model
56            .context("no card model: no card discovered and none named (--card NAME)")
57    }
58}
59
60/// Where a command's lines go. `out` is what the CLI prints to stdout, `err`
61/// what it prints to stderr: progress, plans, warnings.
62pub trait Progress {
63    fn out(&mut self, line: &str);
64    fn err(&mut self, line: &str);
65    /// A line that replaces the previous transient one: the `N frames, F fps`
66    /// counter of `show video`. A terminal redraws it; a job keeps every one.
67    fn transient(&mut self, line: &str) {
68        self.err(line);
69    }
70    /// The transient line is finished with.
71    fn clear_transient(&mut self) {}
72    /// True once the caller wants the command to stop; polled between steps.
73    fn cancelled(&self) -> bool {
74        false
75    }
76}
77
78/// The CLI's sink: `println!` and `eprintln!`, the transient line redrawn
79/// with `\r` when stderr is a terminal and dropped otherwise.
80pub struct Stdio;
81
82impl Progress for Stdio {
83    fn out(&mut self, line: &str) {
84        println!("{line}");
85    }
86
87    fn err(&mut self, line: &str) {
88        eprintln!("{line}");
89    }
90
91    fn transient(&mut self, line: &str) {
92        let mut stderr = std::io::stderr();
93        if stderr.is_terminal() {
94            let _ = write!(stderr, "\r{line}");
95        }
96    }
97
98    fn clear_transient(&mut self) {
99        let mut stderr = std::io::stderr();
100        if stderr.is_terminal() {
101            let _ = write!(stderr, "\r");
102        }
103    }
104}
105
106/// Fails with `cancelled` once the sink asks the command to stop.
107///
108/// # Errors
109/// When `p.cancelled()` is true.
110pub fn check(p: &dyn Progress) -> Result<()> {
111    anyhow::ensure!(!p.cancelled(), "cancelled");
112    Ok(())
113}
114