|
| 1 | +//! Log format conversion |
| 2 | +use regex::Regex; |
| 3 | + |
| 4 | +use ilc_base::{self, Context, Decode, Encode, Event}; |
| 5 | +use std::io::{BufRead, Write}; |
| 6 | + |
| 7 | +#[derive(Copy, Clone)] |
| 8 | +pub enum Subject { |
| 9 | + Nick, |
| 10 | + Time, |
| 11 | + Type, |
| 12 | + Text, |
| 13 | +} |
| 14 | + |
| 15 | +pub enum Operator { |
| 16 | + Exactly(String), |
| 17 | + Contains(String), |
| 18 | + Matches(Regex), |
| 19 | + Equal(i64), |
| 20 | + Greater(i64), |
| 21 | + Less(i64), |
| 22 | +} |
| 23 | + |
| 24 | +pub struct Filter(pub Subject, pub Operator); |
| 25 | + |
| 26 | +impl Filter { |
| 27 | + pub fn satisfied_by(&self, e: &Event) -> bool { |
| 28 | + use self::Subject::*; |
| 29 | + use self::Operator::*; |
| 30 | + |
| 31 | + match (self.0, &self.1) { |
| 32 | + (Nick, &Exactly(ref s)) => e.ty.actor().map_or(false, |e| e == s), |
| 33 | + (Nick, &Contains(ref s)) => e.ty.actor().map_or(false, |e| e.contains(s)), |
| 34 | + (Nick, &Matches(ref r)) => e.ty.actor().map_or(false, |e| r.is_match(e)), |
| 35 | + (Nick, _op) => false, |
| 36 | + (Time, &Equal(t)) => e.time.as_timestamp() == t, |
| 37 | + (Time, &Greater(t)) => e.time.as_timestamp() > t, |
| 38 | + (Time, &Less(t)) => e.time.as_timestamp() < t, |
| 39 | + (Time, _op) => false, |
| 40 | + (Type, &Exactly(ref s)) => e.ty.type_desc() == s, |
| 41 | + (Type, &Contains(ref s)) => e.ty.type_desc().contains(s), |
| 42 | + (Type, &Matches(ref r)) => r.is_match(e.ty.type_desc()), |
| 43 | + (Type, _op) => false, |
| 44 | + (Text, &Exactly(ref s)) => e.ty.text().map_or(false, |t| t == s), |
| 45 | + (Text, &Contains(ref s)) => e.ty.text().map_or(false, |t| t.contains(s)), |
| 46 | + (Text, &Matches(ref r)) => e.ty.text().map_or(false, |t| r.is_match(t)), |
| 47 | + (Text, _op) => false, |
| 48 | + } |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +/// Convert from one format to another, not necessarily different, format. In combination with a |
| 53 | +/// timezone offset, this can be used to correct the timestamps. |
| 54 | +/// Will return `Err` and abort conversion if the decoder yields `Err` or re-encoding fails. |
| 55 | +pub fn convert(ctx: &Context, |
| 56 | + input: &mut BufRead, |
| 57 | + decoder: &mut Decode, |
| 58 | + output: &mut Write, |
| 59 | + encoder: &Encode, |
| 60 | + filter: Option<Filter>, |
| 61 | + not: bool) |
| 62 | + -> ilc_base::Result<()> { |
| 63 | + if let Some(f) = filter { |
| 64 | + for e in decoder.decode(&ctx, input) { |
| 65 | + let e = try!(e); |
| 66 | + if not ^ f.satisfied_by(&e) { |
| 67 | + try!(encoder.encode(&ctx, output, &e)) |
| 68 | + } |
| 69 | + } |
| 70 | + } else { |
| 71 | + // fast path for filter-less conversion, probably premature |
| 72 | + for e in decoder.decode(&ctx, input) { |
| 73 | + try!(encoder.encode(&ctx, output, &try!(e))); |
| 74 | + } |
| 75 | + } |
| 76 | + Ok(()) |
| 77 | +} |
0 commit comments