docs: Add comprehensive rustdoc to filter plugin modules
Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) <aider@aider.chat>
This commit is contained in:
@@ -4,6 +4,7 @@ use std::process::{Command, Stdio, Child};
|
|||||||
use which::which;
|
use which::which;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
|
/// A filter that executes an external program and pipes input through it.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ExecFilter {
|
pub struct ExecFilter {
|
||||||
program: String,
|
program: String,
|
||||||
@@ -16,6 +17,13 @@ pub struct ExecFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExecFilter {
|
impl ExecFilter {
|
||||||
|
/// Creates a new `ExecFilter` for the specified program and arguments.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `program` - The name or path of the program to execute.
|
||||||
|
/// * `args` - The arguments to pass to the program.
|
||||||
|
/// * `split_whitespace` - Whether to split arguments on whitespace.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
program: &str,
|
program: &str,
|
||||||
args: Vec<&str>,
|
args: Vec<&str>,
|
||||||
@@ -37,6 +45,12 @@ impl ExecFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for ExecFilter {
|
impl FilterPlugin for ExecFilter {
|
||||||
|
/// Filters the input by piping it through the external program and writing the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
if !self.supported {
|
if !self.supported {
|
||||||
return Err(std::io::Error::new(
|
return Err(std::io::Error::new(
|
||||||
@@ -146,6 +160,7 @@ impl FilterPlugin for ExecFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(ExecFilter {
|
Box::new(ExecFilter {
|
||||||
program: self.program.clone(),
|
program: self.program.clone(),
|
||||||
@@ -158,6 +173,7 @@ impl FilterPlugin for ExecFilter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
|
|||||||
@@ -2,11 +2,21 @@ use super::{FilterPlugin, FilterOption};
|
|||||||
use std::io::{Result, Read, Write, BufRead};
|
use std::io::{Result, Read, Write, BufRead};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
/// A filter that matches lines against a regular expression pattern.
|
||||||
pub struct GrepFilter {
|
pub struct GrepFilter {
|
||||||
regex: Regex,
|
regex: Regex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GrepFilter {
|
impl GrepFilter {
|
||||||
|
/// Creates a new `GrepFilter` with the specified regex pattern.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `pattern` - The regular expression pattern to match.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the pattern is invalid.
|
||||||
pub fn new(pattern: String) -> Result<Self> {
|
pub fn new(pattern: String) -> Result<Self> {
|
||||||
let regex = Regex::new(&pattern)
|
let regex = Regex::new(&pattern)
|
||||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
|
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
|
||||||
@@ -17,6 +27,12 @@ impl GrepFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for GrepFilter {
|
impl FilterPlugin for GrepFilter {
|
||||||
|
/// Filters the input by writing only lines that match the regex pattern.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
let mut buf_reader = std::io::BufReader::new(&mut *reader);
|
let mut buf_reader = std::io::BufReader::new(&mut *reader);
|
||||||
for line in buf_reader.by_ref().lines() {
|
for line in buf_reader.by_ref().lines() {
|
||||||
@@ -28,12 +44,14 @@ impl FilterPlugin for GrepFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
regex: self.regex.clone(),
|
regex: self.regex.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
|
|||||||
@@ -3,11 +3,17 @@ use std::io::{Result, Read, Write, BufRead};
|
|||||||
use crate::common::PIPESIZE;
|
use crate::common::PIPESIZE;
|
||||||
use crate::services::filter_service::register_filter_plugin;
|
use crate::services::filter_service::register_filter_plugin;
|
||||||
|
|
||||||
|
/// A filter that reads the first N bytes from the input stream.
|
||||||
pub struct HeadBytesFilter {
|
pub struct HeadBytesFilter {
|
||||||
remaining: usize,
|
remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeadBytesFilter {
|
impl HeadBytesFilter {
|
||||||
|
/// Creates a new `HeadBytesFilter` that will read up to the specified number of bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `count` - The maximum number of bytes to read.
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: count,
|
remaining: count,
|
||||||
@@ -16,6 +22,12 @@ impl HeadBytesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for HeadBytesFilter {
|
impl FilterPlugin for HeadBytesFilter {
|
||||||
|
/// Filters the input by reading only the first N bytes and writing them to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
if self.remaining == 0 {
|
if self.remaining == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -34,12 +46,14 @@ impl FilterPlugin for HeadBytesFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
remaining: self.remaining,
|
remaining: self.remaining,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
@@ -51,11 +65,17 @@ impl FilterPlugin for HeadBytesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A filter that reads the first N lines from the input stream.
|
||||||
pub struct HeadLinesFilter {
|
pub struct HeadLinesFilter {
|
||||||
remaining: usize,
|
remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeadLinesFilter {
|
impl HeadLinesFilter {
|
||||||
|
/// Creates a new `HeadLinesFilter` that will read up to the specified number of lines.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `count` - The maximum number of lines to read.
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: count,
|
remaining: count,
|
||||||
@@ -64,6 +84,12 @@ impl HeadLinesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for HeadLinesFilter {
|
impl FilterPlugin for HeadLinesFilter {
|
||||||
|
/// Filters the input by reading only the first N lines and writing them to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
if self.remaining == 0 {
|
if self.remaining == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -81,12 +107,14 @@ impl FilterPlugin for HeadLinesFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
remaining: self.remaining,
|
remaining: self.remaining,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub use skip::{SkipBytesFilter, SkipLinesFilter};
|
|||||||
pub use grep::GrepFilter;
|
pub use grep::GrepFilter;
|
||||||
pub use strip_ansi::StripAnsiFilter;
|
pub use strip_ansi::StripAnsiFilter;
|
||||||
|
|
||||||
|
/// Represents an option for a filter plugin.
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
|
||||||
pub struct FilterOption {
|
pub struct FilterOption {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -25,13 +26,26 @@ pub struct FilterOption {
|
|||||||
pub required: bool,
|
pub required: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for filter plugins that process input streams.
|
||||||
pub trait FilterPlugin: Send {
|
pub trait FilterPlugin: Send {
|
||||||
|
/// Processes the input stream and writes the filtered output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` indicating success or failure.
|
||||||
fn filter(&mut self, reader: Box<&mut dyn Read>, writer: Box<&mut dyn Write>) -> Result<()>;
|
fn filter(&mut self, reader: Box<&mut dyn Read>, writer: Box<&mut dyn Write>) -> Result<()>;
|
||||||
|
/// Clones this plugin into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin>;
|
fn clone_box(&self) -> Box<dyn FilterPlugin>;
|
||||||
// Get the filter options definition
|
/// Returns the configuration options for this plugin.
|
||||||
fn options(&self) -> Vec<FilterOption>;
|
fn options(&self) -> Vec<FilterOption>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enum representing the different types of filters.
|
||||||
#[derive(Debug, EnumString, strum::VariantNames, strum::Display)]
|
#[derive(Debug, EnumString, strum::VariantNames, strum::Display)]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
pub enum FilterType {
|
pub enum FilterType {
|
||||||
@@ -45,11 +59,13 @@ pub enum FilterType {
|
|||||||
StripAnsi,
|
StripAnsi,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A chain of filter plugins applied sequentially.
|
||||||
pub struct FilterChain {
|
pub struct FilterChain {
|
||||||
plugins: Vec<Box<dyn FilterPlugin>>,
|
plugins: Vec<Box<dyn FilterPlugin>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for FilterChain {
|
impl Clone for FilterChain {
|
||||||
|
/// Clones this filter chain.
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let mut plugins = Vec::with_capacity(self.plugins.len());
|
let mut plugins = Vec::with_capacity(self.plugins.len());
|
||||||
for plugin in &self.plugins {
|
for plugin in &self.plugins {
|
||||||
@@ -60,22 +76,35 @@ impl Clone for FilterChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Box<dyn FilterPlugin> {
|
impl Clone for Box<dyn FilterPlugin> {
|
||||||
|
/// Clones the boxed filter plugin.
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
self.clone_box()
|
self.clone_box()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterChain {
|
impl FilterChain {
|
||||||
|
/// Creates a new empty filter chain.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
plugins: Vec::new(),
|
plugins: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a plugin to the chain.
|
||||||
pub fn add_plugin(&mut self, plugin: Box<dyn FilterPlugin>) {
|
pub fn add_plugin(&mut self, plugin: Box<dyn FilterPlugin>) {
|
||||||
self.plugins.push(plugin);
|
self.plugins.push(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies the filter chain to the input and writes to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` indicating success or failure.
|
||||||
pub fn filter(&mut self, reader: &mut dyn Read, writer: &mut dyn Write) -> Result<()> {
|
pub fn filter(&mut self, reader: &mut dyn Read, writer: &mut dyn Write) -> Result<()> {
|
||||||
if self.plugins.is_empty() {
|
if self.plugins.is_empty() {
|
||||||
// If no plugins, just copy the input to output
|
// If no plugins, just copy the input to output
|
||||||
@@ -112,7 +141,15 @@ impl FilterChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to parse filter string and create appropriate plugins
|
/// Parses a filter string into a `FilterChain`.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `filter_str` - The filter string (e.g., "head_lines(10)|grep(pattern=error)").
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing the parsed `FilterChain` or an error if invalid.
|
||||||
pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
||||||
let mut chain = FilterChain::new();
|
let mut chain = FilterChain::new();
|
||||||
|
|
||||||
@@ -183,7 +220,17 @@ pub fn parse_filter_string(filter_str: &str) -> Result<FilterChain> {
|
|||||||
Ok(chain)
|
Ok(chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create filter with proper option handling
|
/// Creates a filter plugin with the given options.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `filter_type` - The type of filter to create.
|
||||||
|
/// * `unnamed_params` - Unnamed parameters.
|
||||||
|
/// * `named_options` - Named options.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing the boxed filter plugin.
|
||||||
fn create_filter_with_options(
|
fn create_filter_with_options(
|
||||||
filter_type: FilterType,
|
filter_type: FilterType,
|
||||||
unnamed_params: &[serde_json::Value],
|
unnamed_params: &[serde_json::Value],
|
||||||
@@ -250,7 +297,16 @@ fn create_filter_with_options(
|
|||||||
create_specific_filter(filter_type, &options)
|
create_specific_filter(filter_type, &options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to create specific filter instances based on options
|
/// Creates a specific filter instance based on type and options.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `filter_type` - The type of filter.
|
||||||
|
/// * `options` - The processed options.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing the boxed filter plugin.
|
||||||
fn create_specific_filter(
|
fn create_specific_filter(
|
||||||
filter_type: FilterType,
|
filter_type: FilterType,
|
||||||
options: &HashMap<String, serde_json::Value>,
|
options: &HashMap<String, serde_json::Value>,
|
||||||
@@ -338,7 +394,15 @@ fn create_specific_filter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to parse option values
|
/// Parses an option value from a string into a JSON value.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `input` - The input string.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing the parsed JSON value.
|
||||||
fn parse_option_value(input: &str) -> Result<serde_json::Value> {
|
fn parse_option_value(input: &str) -> Result<serde_json::Value> {
|
||||||
// Remove quotes if present
|
// Remove quotes if present
|
||||||
let input = input.trim_matches(|c| c == '\'' || c == '"');
|
let input = input.trim_matches(|c| c == '\'' || c == '"');
|
||||||
|
|||||||
@@ -3,17 +3,24 @@ use std::io::{Result, Read, Write, BufRead};
|
|||||||
use crate::common::PIPESIZE;
|
use crate::common::PIPESIZE;
|
||||||
use crate::services::filter_service::register_filter_plugin;
|
use crate::services::filter_service::register_filter_plugin;
|
||||||
|
|
||||||
|
/// A filter that skips the first N bytes from the input stream.
|
||||||
pub struct SkipBytesFilter {
|
pub struct SkipBytesFilter {
|
||||||
remaining: usize,
|
remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SkipBytesFilter {
|
impl SkipBytesFilter {
|
||||||
|
/// Creates a new `SkipBytesFilter` that will skip the specified number of bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `count` - The number of bytes to skip.
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: count,
|
remaining: count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new instance from options.
|
||||||
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
||||||
let options = options.ok_or_else(|| {
|
let options = options.ok_or_else(|| {
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
@@ -37,6 +44,12 @@ impl SkipBytesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for SkipBytesFilter {
|
impl FilterPlugin for SkipBytesFilter {
|
||||||
|
/// Filters the input by skipping the first N bytes and writing the rest to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
// Skip bytes in chunks
|
// Skip bytes in chunks
|
||||||
if self.remaining > 0 {
|
if self.remaining > 0 {
|
||||||
@@ -56,12 +69,14 @@ impl FilterPlugin for SkipBytesFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
remaining: self.remaining,
|
remaining: self.remaining,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
@@ -73,17 +88,24 @@ impl FilterPlugin for SkipBytesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A filter that skips the first N lines from the input stream.
|
||||||
pub struct SkipLinesFilter {
|
pub struct SkipLinesFilter {
|
||||||
remaining: usize,
|
remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SkipLinesFilter {
|
impl SkipLinesFilter {
|
||||||
|
/// Creates a new `SkipLinesFilter` that will skip the specified number of lines.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `count` - The number of lines to skip.
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: count,
|
remaining: count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new instance from options.
|
||||||
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
||||||
let options = options.ok_or_else(|| {
|
let options = options.ok_or_else(|| {
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
@@ -107,6 +129,12 @@ impl SkipLinesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for SkipLinesFilter {
|
impl FilterPlugin for SkipLinesFilter {
|
||||||
|
/// Filters the input by skipping the first N lines and writing the rest to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
let mut buf_reader = std::io::BufReader::new(&mut *reader);
|
let mut buf_reader = std::io::BufReader::new(&mut *reader);
|
||||||
for line in buf_reader.by_ref().lines() {
|
for line in buf_reader.by_ref().lines() {
|
||||||
@@ -120,12 +148,14 @@ impl FilterPlugin for SkipLinesFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
remaining: self.remaining,
|
remaining: self.remaining,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
|
|||||||
@@ -2,25 +2,35 @@ use std::io::{Result, Read, Write};
|
|||||||
use strip_ansi_escapes::Writer;
|
use strip_ansi_escapes::Writer;
|
||||||
use super::{FilterPlugin, FilterOption};
|
use super::{FilterPlugin, FilterOption};
|
||||||
|
|
||||||
|
/// A filter that removes ANSI escape sequences from the input.
|
||||||
pub struct StripAnsiFilter;
|
pub struct StripAnsiFilter;
|
||||||
|
|
||||||
impl StripAnsiFilter {
|
impl StripAnsiFilter {
|
||||||
|
/// Creates a new `StripAnsiFilter`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for StripAnsiFilter {
|
impl FilterPlugin for StripAnsiFilter {
|
||||||
|
/// Filters the input by stripping ANSI escape sequences and writing the plain text to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
let mut ansi_writer = Writer::new(&mut *writer);
|
let mut ansi_writer = Writer::new(&mut *writer);
|
||||||
std::io::copy(&mut *reader, &mut ansi_writer)?;
|
std::io::copy(&mut *reader, &mut ansi_writer)?;
|
||||||
ansi_writer.flush()
|
ansi_writer.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self)
|
Box::new(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter (none required).
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
Vec::new() // strip_ansi doesn't take any options
|
Vec::new() // strip_ansi doesn't take any options
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,18 @@ use std::collections::VecDeque;
|
|||||||
use crate::common::PIPESIZE;
|
use crate::common::PIPESIZE;
|
||||||
use crate::services::filter_service::register_filter_plugin;
|
use crate::services::filter_service::register_filter_plugin;
|
||||||
|
|
||||||
|
/// A filter that reads the last N bytes from the input stream.
|
||||||
pub struct TailBytesFilter {
|
pub struct TailBytesFilter {
|
||||||
buffer: VecDeque<u8>,
|
buffer: VecDeque<u8>,
|
||||||
count: usize,
|
count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TailBytesFilter {
|
impl TailBytesFilter {
|
||||||
|
/// Creates a new `TailBytesFilter` that will keep the last specified number of bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `count` - The number of bytes to keep from the end.
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buffer: VecDeque::with_capacity(count),
|
buffer: VecDeque::with_capacity(count),
|
||||||
@@ -17,6 +23,7 @@ impl TailBytesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new instance from options.
|
||||||
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
||||||
let options = options.ok_or_else(|| {
|
let options = options.ok_or_else(|| {
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
@@ -40,6 +47,12 @@ impl TailBytesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for TailBytesFilter {
|
impl FilterPlugin for TailBytesFilter {
|
||||||
|
/// Filters the input by keeping only the last N bytes and writing them to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
let mut temp_buffer = vec![0; PIPESIZE];
|
let mut temp_buffer = vec![0; PIPESIZE];
|
||||||
loop {
|
loop {
|
||||||
@@ -63,6 +76,7 @@ impl FilterPlugin for TailBytesFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
buffer: self.buffer.clone(),
|
buffer: self.buffer.clone(),
|
||||||
@@ -70,6 +84,7 @@ impl FilterPlugin for TailBytesFilter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
@@ -81,12 +96,18 @@ impl FilterPlugin for TailBytesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A filter that reads the last N lines from the input stream.
|
||||||
pub struct TailLinesFilter {
|
pub struct TailLinesFilter {
|
||||||
lines: VecDeque<String>,
|
lines: VecDeque<String>,
|
||||||
count: usize,
|
count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TailLinesFilter {
|
impl TailLinesFilter {
|
||||||
|
/// Creates a new `TailLinesFilter` that will keep the last specified number of lines.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `count` - The number of lines to keep from the end.
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lines: VecDeque::with_capacity(count),
|
lines: VecDeque::with_capacity(count),
|
||||||
@@ -94,6 +115,7 @@ impl TailLinesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new instance from options.
|
||||||
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
pub fn create(options: Option<serde_json::Value>) -> Result<Box<dyn FilterPlugin>> {
|
||||||
let options = options.ok_or_else(|| {
|
let options = options.ok_or_else(|| {
|
||||||
std::io::Error::new(
|
std::io::Error::new(
|
||||||
@@ -117,6 +139,12 @@ impl TailLinesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FilterPlugin for TailLinesFilter {
|
impl FilterPlugin for TailLinesFilter {
|
||||||
|
/// Filters the input by keeping only the last N lines and writing them to the output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - The input reader.
|
||||||
|
/// * `writer` - The output writer.
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
let mut buf_reader = std::io::BufReader::new(&mut *reader);
|
let mut buf_reader = std::io::BufReader::new(&mut *reader);
|
||||||
for line in buf_reader.by_ref().lines() {
|
for line in buf_reader.by_ref().lines() {
|
||||||
@@ -134,6 +162,7 @@ impl FilterPlugin for TailLinesFilter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clones this filter into a new boxed instance.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
lines: self.lines.clone(),
|
lines: self.lines.clone(),
|
||||||
@@ -141,6 +170,7 @@ impl FilterPlugin for TailLinesFilter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the configuration options for this filter.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
|
|
||||||
/// Helper function to create a filter chain from a string
|
/// Creates a filter chain from a filter string specification.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `filter_str` - The string describing the filter chain (e.g., "head_lines(10)|grep(pattern=error)").
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing an optional `FilterChain` if parsing succeeds.
|
||||||
pub fn create_filter_chain(filter_str: &str) -> Result<Option<super::FilterChain>> {
|
pub fn create_filter_chain(filter_str: &str) -> Result<Option<super::FilterChain>> {
|
||||||
super::parse_filter_string(filter_str).map(Some)
|
super::parse_filter_string(filter_str).map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to parse a number from a string with error handling
|
/// Parses a string into a number of type T.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `s` - The string to parse.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result` containing the parsed number or an error if invalid.
|
||||||
pub fn parse_number<T: std::str::FromStr>(s: &str) -> Result<T> {
|
pub fn parse_number<T: std::str::FromStr>(s: &str) -> Result<T> {
|
||||||
s.parse::<T>()
|
s.parse::<T>()
|
||||||
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid number"))
|
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid number"))
|
||||||
|
|||||||
Reference in New Issue
Block a user