Skip to main content

PrinterMonitor

Struct PrinterMonitor 

Source
pub struct PrinterMonitor { /* private fields */ }
Expand description

Printer monitoring and querying functionality.

PrinterMonitor is cheaply cloneable (uses Arc internally) and can be shared across tasks without creating multiple backend connections.

Implementations§

Source§

impl PrinterMonitor

Source

pub fn monitor(&self, printer_name: impl Into<String>) -> MonitorBuilder<'_>

Starts a fluent monitoring run via MonitorBuilder.

Replaces the positional-parameter monitor_printer* methods for new code. The old methods remain available (the builder delegates to them internally) but the builder form is the recommended entry point.

Source§

impl PrinterMonitor

Source

pub async fn list_printers_cancellable( &self, cancel_token: Option<CancellationToken>, ) -> Result<Vec<Printer>>

Retrieves a list of all printers available on the system, with an optional CancellationToken to abort the in-flight backend query.

When cancel_token is provided, the backend query is raced against token.cancelled() and the call returns [PrinterError::Cancelled] as soon as the token fires. Passing None waits for the query to complete normally.

Note that the backend query (a WMI call on Windows, an lpstat exec or libcups call on Linux) is not itself abortable - cancellation surfaces as soon as the current poll completes, not mid-flight.

§Example
use printer_event_handler::PrinterMonitor;

let monitor = PrinterMonitor::new().await.unwrap();
let printers = monitor.list_printers_cancellable(None).await.unwrap();
for printer in printers {
    println!("{}: {}", printer.name(), printer.status_description());
}
Source

pub async fn find_printer_cancellable( &self, name: &str, cancel_token: Option<CancellationToken>, ) -> Result<Option<Printer>>

Searches for a specific printer by name (case-insensitive), with an optional CancellationToken.

See Self::list_printers_cancellable for the cancellation semantics (token races against the in-flight backend query and yields [PrinterError::Cancelled]).

§Example
use printer_event_handler::PrinterMonitor;

let monitor = PrinterMonitor::new().await.unwrap();
if let Some(p) = monitor.find_printer_cancellable("HP LaserJet", None).await.unwrap() {
    println!("Found printer: {}", p.name());
}
Source

pub async fn list_jobs( &self, printer_name: Option<&str>, cancel_token: Option<CancellationToken>, ) -> Result<Vec<Job>>

Lists print jobs across all printers (printer_name = None) or for a single printer (Some(name)).

Backends that cannot enumerate jobs return Ok(vec![]) - this is the case for the Linux/CUPS backend in 1.5.0; first-class CUPS support is queued for a later release. The Windows backend pulls from WMI’s Win32_PrintJob.

The optional CancellationToken is raced against the backend query; when fired the call returns crate::PrinterError::Cancelled.

Source

pub async fn monitor_printer<F>( &self, printer_name: &str, interval_ms: u64, cancel_token: Option<CancellationToken>, callback: F, ) -> Result<()>
where F: FnMut(&Printer, Option<&Printer>) + Send,

Continuously monitors a specific printer for status changes.

This function runs indefinitely, polling the specified printer every interval_ms milliseconds and calling the provided callback function whenever the printer’s status changes. The callback receives both the current printer state and the previous state (if any).

§Arguments
  • printer_name - The name of the printer to monitor
  • interval_ms - Polling interval in milliseconds
  • callback - Function called when printer status changes, receives (current, previous)
§Returns
  • Result<()> - Never returns Ok normally (runs indefinitely), only Err on failure
§Errors
  • PrinterError::PrinterNotFound - If the specified printer is not found initially
  • PrinterError::WmiError - If WMI queries fail on Windows
  • PrinterError::CupsError - If CUPS queries fail on Linux
  • PrinterError::IoError - If there are system I/O issues
§Behavior
  • If the printer disappears during monitoring, the callback is called with a synthetic Offline snapshot to indicate the printer is no longer available
  • The first check always triggers the callback to provide the initial status
  • Subsequent calls only trigger the callback if the status actually changes
§Example
use printer_event_handler::PrinterMonitor;
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
    let cancel_token = CancellationToken::new();

    monitor.monitor_printer("HP LaserJet", 30000, Some(cancel_token.clone()), |current, previous| {
        if let Some(prev) = previous {
            if prev != current {
                println!("Status changed: {} -> {}",
                    prev.status_description(),
                    current.status_description());
            }
        } else {
            println!("Initial status: {}", current.status_description());
        }
    }).await.unwrap();
}
Source

pub async fn printer_summary(&self) -> Result<HashMap<String, PrinterSummary>>

Retrieves a comprehensive summary of all printers and their current states.

This method provides a convenient way to get an overview of all printers in a structured format, useful for status dashboards or reports.

§Returns
  • Result<HashMap<String, PrinterSummary>> - Map of printer names to their summaries
§Errors
  • PrinterError::WmiError - If the WMI query fails on Windows
  • PrinterError::CupsError - If the CUPS query fails on Linux
  • PrinterError::IoError - If there are system I/O issues
§Example
use printer_event_handler::PrinterMonitor;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
    let summary = monitor.printer_summary().await.unwrap();

    for (name, info) in summary {
        println!("{}: {} ({})", name, info.status,
            if info.has_error { "ERROR" } else { "OK" });
    }
}
Source

pub async fn printer_summary_iter( &self, ) -> Result<impl Iterator<Item = (String, PrinterSummary)>>

Iterator counterpart to Self::printer_summary.

Returns the same (name, summary) pairs without allocating a HashMap. Prefer this when you just need to iterate once - for example to log every printer or feed a UI list - and don’t need key-based lookup.

Order matches the underlying backend’s enumeration order (insertion order via the source Vec<Printer>), not the unspecified order a HashMap iterator would yield.

§Errors

Same errors as Self::printer_summary.

§Example
use printer_event_handler::PrinterMonitor;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
    for (name, info) in monitor.printer_summary_iter().await.unwrap() {
        println!("{name}: {} ({})", info.status,
            if info.has_error { "ERROR" } else { "OK" });
    }
}
Source

pub async fn monitor_printer_changes<F>( &self, printer_name: &str, interval_ms: u64, cancel_token: Option<CancellationToken>, callback: F, ) -> Result<()>
where F: FnMut(&PrinterChanges) + Send,

Monitors a printer with detailed property change detection.

This enhanced monitoring method provides detailed information about exactly which properties changed between checks, enabling fine-grained monitoring and alerting.

§Arguments
  • printer_name - The name of the printer to monitor
  • interval_ms - Polling interval in milliseconds
  • cancel_token - Optional cancellation token for graceful shutdown
  • callback - Function called when properties change, receives PrinterChanges
§Returns
  • Result<()> - Returns Ok when cancelled, or Err on failure
§Behavior
  • The callback is NOT called on the initial state capture
  • Only actual property changes trigger the callback
  • Changes are always non-empty when the callback is invoked
  • The initial state is captured silently for comparison with future states
  • Disappearance fires a synthetic IsOffline: false -> true change
  • Reappearance fires a change set comparing the missing-state snapshot with the current printer (typically includes IsOffline: true -> false)
  • Monitoring stops gracefully when the cancellation token is cancelled
§Example
use printer_event_handler::PrinterMonitor;
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
    let cancel_token = CancellationToken::new();

    // Clone the token for the monitoring task
    let token_clone = cancel_token.clone();
    let handle = tokio::spawn(async move {
        monitor.monitor_printer_changes("HP LaserJet", 30000, Some(token_clone), |changes| {
            println!("Detected {} changes:", changes.change_count());
            for change in &changes.changes {
                println!("  - {}", change.description());
            }
        }).await
    });

    // Later: cancel monitoring
    cancel_token.cancel();
    handle.await.unwrap().unwrap();
}
Source

pub async fn monitor_property<F>( &self, printer_name: &str, property: MonitorableProperty, interval_ms: u64, cancel_token: Option<CancellationToken>, callback: F, ) -> Result<()>
where F: FnMut(&PropertyChange) + Send,

Monitors a specific property of a printer for changes.

This method allows monitoring just a single property, useful for alerting on specific conditions like offline status or error state changes.

§Arguments
  • printer_name - The name of the printer to monitor
  • property - The specific property to watch using MonitorableProperty enum
  • interval_ms - Polling interval in milliseconds
  • cancel_token - Optional cancellation token for graceful shutdown
  • callback - Function called when the property changes
§Example
use printer_event_handler::{PrinterMonitor, MonitorableProperty};
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
    let cancel_token = CancellationToken::new();

    monitor.monitor_property(
        "HP LaserJet",
        MonitorableProperty::IsOffline,
        60000,
        Some(cancel_token.clone()),
        |change| {
            println!("Offline status changed: {}", change.description());
        }
    ).await.unwrap();
}
Source§

impl PrinterMonitor

Source

pub async fn monitor_multiple_printers<F>( &self, printer_names: Vec<String>, interval_ms: u64, cancel_token: Option<CancellationToken>, callback: F, ) -> Result<()>
where F: Fn(&PrinterChanges) + Send + Sync + 'static,

Monitors multiple printers concurrently and reports changes for any of them.

This method allows monitoring several printers simultaneously, with a single callback that receives changes from any of the monitored printers.

§Arguments
  • printer_names - List of printer names to monitor
  • interval_ms - Polling interval in milliseconds
  • cancel_token - Optional cancellation token for graceful shutdown
  • callback - Function called when any printer changes (NOT called on initial state)
§Returns
  • Result<()> - Returns Ok when cancelled or all tasks complete, or Err on failure
§Behavior
  • The callback is NOT called on the initial state capture for each printer
  • Only actual property changes trigger the callback
  • Disappearance fires a synthetic IsOffline: false -> true change once per gap
  • Reappearance fires a change set comparing the missing-state snapshot with the current printer (typically includes IsOffline: true -> false)
  • Each printer is monitored in a separate task for true concurrent monitoring
  • Callbacks are called outside of internal locks to prevent contention with slow callbacks
  • The monitor is cloned (cheaply via Arc) for each task, sharing the same backend connection
  • Monitoring stops gracefully when the cancellation token is cancelled
§Example
use printer_event_handler::PrinterMonitor;
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
    let printers = vec!["HP LaserJet".to_string(), "Canon Printer".to_string()];
    let cancel_token = CancellationToken::new();

    let token_clone = cancel_token.clone();
    let handle = tokio::spawn(async move {
        monitor.monitor_multiple_printers(printers, 30000, Some(token_clone), |changes| {
            println!("Printer '{}' changed: {}", changes.printer_name, changes.summary());
        }).await
    });

    // Later: cancel monitoring
    cancel_token.cancel();
    handle.await.unwrap().unwrap();
}
Source§

impl PrinterMonitor

Source

pub async fn new() -> Result<Self>

Creates a new PrinterMonitor instance with the appropriate platform backend.

This function automatically selects and initializes the correct backend for the current platform (WMI for Windows, CUPS for Linux).

§Returns
  • Result<Self> - A new PrinterMonitor instance or an error if initialization fails
§Errors
  • PrinterError::PlatformNotSupported - If the current platform is not supported
  • PrinterError::WmiError - If WMI initialization fails on Windows
  • PrinterError::CupsError - If CUPS initialization fails on Linux
§Example
use printer_event_handler::PrinterMonitor;

#[tokio::main]
async fn main() {
    let monitor = PrinterMonitor::new().await.unwrap();
}
Source

pub fn from_backend(backend: Arc<dyn PrinterBackend>) -> Self

Constructs a monitor around a caller-supplied backend.

Intended for tests and advanced users who need to substitute the platform backend (e.g. recording, fault injection, scripted responses for end-to-end change-detection tests). Production code should use PrinterMonitor::new instead - it auto-selects the real WMI/CUPS backend for the current platform.

§Example
use std::sync::Arc;
use printer_event_handler::PrinterMonitor;
use printer_event_handler::backend::PrinterBackend;

fn make_monitor(backend: Arc<dyn PrinterBackend>) -> PrinterMonitor {
    PrinterMonitor::from_backend(backend)
}

Trait Implementations§

Source§

impl Clone for PrinterMonitor

Source§

fn clone(&self) -> PrinterMonitor

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.