src/source/stdin.rs

//! Stdin-backed [`Source`].
//!
//! Mostly useful when piping the output of another command (`journalctl -f |
//! ripgrab --stdin`). There's no rotation or follow logic; we simply hand
//! lines out until EOF.

use anyhow::Result;
use tokio::io::{AsyncBufReadExt, BufReader};

use super::{LineItem, Source};

pub struct StdinSource {
    reader: BufReader<tokio::io::Stdin>,
    seq: u64,
    label: String,
}

impl StdinSource {
    pub fn new() -> Self {
        Self {
            reader: BufReader::new(tokio::io::stdin()),
            seq: 0,
            label: "stdin".into(),
        }
    }
}

impl Default for StdinSource {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait::async_trait]
impl Source for StdinSource {
    async fn next_line(&mut self) -> Result<Option<LineItem>> {
        let mut line = String::new();
        let read = self.reader.read_line(&mut line).await?;
        if read == 0 {
            return Ok(None);
        }
        while line.ends_with('\n') || line.ends_with('\r') {
            line.pop();
        }
        self.seq += 1;
        Ok(Some(LineItem {
            line,
            origin: self.label.clone(),
            seq: self.seq,
        }))
    }

    fn label(&self) -> &str {
        &self.label
    }
}