aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTill Höppner2015-06-11 20:57:39 +0200
committerTill Höppner2015-06-11 20:57:39 +0200
commitbc755a4dedc520b672bc7168ff6ef9d088072d99 (patch)
tree52bed0ed50693bb9f5bbdc52fa81d7e1edfb855c /src
parent86fe3230866082d6207eb5253f2e89623b941f63 (diff)
parentccc9f5e8eaa84579da610ea0d90d18596078bac7 (diff)
downloadilc-bc755a4dedc520b672bc7168ff6ef9d088072d99.tar.gz
ilc-bc755a4dedc520b672bc7168ff6ef9d088072d99.tar.xz
ilc-bc755a4dedc520b672bc7168ff6ef9d088072d99.zip
Merge pull request #1 from tilpner/cows
Update Event API with Option and Cow
Diffstat (limited to 'src')
-rw-r--r--src/context.rs8
-rw-r--r--src/event.rs111
-rw-r--r--src/format/binary.rs23
-rw-r--r--src/format/energymech.rs150
-rw-r--r--src/format/mod.rs24
-rw-r--r--src/format/weechat3.rs181
-rw-r--r--src/freq.rs15
-rw-r--r--src/lib.rs3
-rw-r--r--src/log.rs90
-rw-r--r--src/main.rs16
10 files changed, 437 insertions, 184 deletions
diff --git a/src/context.rs b/src/context.rs
new file mode 100644
index 0000000..6626714
--- /dev/null
+++ b/src/context.rs
@@ -0,0 +1,8 @@
+
+use chrono::naive::date::NaiveDate;
+use chrono::offset::fixed::FixedOffset;
+
+pub struct Context {
+ pub timezone: FixedOffset,
+ pub override_date: NaiveDate
+}
diff --git a/src/event.rs b/src/event.rs
new file mode 100644
index 0000000..0ecb6bc
--- /dev/null
+++ b/src/event.rs
@@ -0,0 +1,111 @@
+// Copyright 2015 Till Höppner
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Common structures to represent the actual log data in memory.
+//! These will be used by all formats for encoding and decoding.
+
+use std::borrow::Cow;
+
+use chrono::offset::fixed::FixedOffset;
+use chrono::offset::TimeZone;
+
+/// A whole log, in memory. This structure does not specify its
+/// use. It may represent a private query, or the log of a channel.
+pub struct Log<'a> {
+ pub entries: Vec<Event<'a>>
+}
+
+/// Different log formats carry different amounts of information. Some might
+/// hold enough information to calculate precise timestamps, others might
+/// only suffice for the time of day.
+#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+pub enum Time {
+ Unknown,
+ Hms(u8, u8, u8),
+ Timestamp(i64)
+}
+
+impl Time {
+ pub fn from_format(tz: &FixedOffset, s: &str, f: &str) -> Time {
+ tz.datetime_from_str(s, f)
+ .map(|d| d.timestamp())
+ .map(Time::Timestamp)
+ .unwrap_or(Time::Unknown)
+ }
+
+ pub fn with_format(&self, tz: &FixedOffset, f: &str) -> String {
+ match self {
+ &Time::Unknown => panic!("Time data for this event is not present"),
+ &Time::Hms(_h, _m, _s) => unimplemented!(),
+ &Time::Timestamp(t) => format!("{}", tz.timestamp(t, 0).format(f))
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+pub struct Event<'a> {
+ pub ty: Type<'a>,
+ pub time: Time,
+ pub channel: Option<Cow<'a, str>>
+}
+
+/// All representable events, such as messages, quits, joins
+/// and topic changes.
+#[derive(Clone, Debug, Hash, PartialEq, RustcEncodable, RustcDecodable)]
+pub enum Type<'a> {
+ Connect,
+ Disconnect,
+ Msg {
+ from: Cow<'a, str>,
+ content: Cow<'a, str>,
+ },
+ Action {
+ from: Cow<'a, str>,
+ content: Cow<'a, str>,
+ },
+ Join {
+ nick: Cow<'a, str>,
+ mask: Option<Cow<'a, str>>,
+ },
+ Part {
+ nick: Cow<'a, str>,
+ mask: Option<Cow<'a, str>>,
+ reason: Option<Cow<'a, str>>,
+ },
+ Quit {
+ nick: Cow<'a, str>,
+ mask: Option<Cow<'a, str>>,
+ reason: Option<Cow<'a, str>>,
+ },
+ Nick {
+ old_nick: Cow<'a, str>,
+ new_nick: Cow<'a, str>,
+ },
+ Notice {
+ from: Cow<'a, str>,
+ content: Cow<'a, str>,
+ },
+ Kick {
+ kicked_nick: Cow<'a, str>,
+ kicking_nick: Option<Cow<'a, str>>,
+ kick_message: Option<Cow<'a, str>>,
+ },
+ Topic {
+ topic: Cow<'a, str>,
+ },
+ TopicChange {
+ new_topic: Cow<'a, str>,
+ },
+ Mode
+}
diff --git a/src/format/binary.rs b/src/format/binary.rs
index e8d880f..4c2e151 100644
--- a/src/format/binary.rs
+++ b/src/format/binary.rs
@@ -14,35 +14,38 @@
use std::io::{ BufRead, Write };
use std::iter::Iterator;
+use std::marker::PhantomData;
-use log::Event;
+use event::Event;
+use context::Context;
use format::{ Encode, Decode };
use bincode::{ self, SizeLimit };
pub struct Binary;
-pub struct Iter<R> where R: BufRead {
+pub struct Iter<'a, R: 'a> where R: BufRead {
+ _phantom: PhantomData<&'a ()>,
input: R
}
-impl<R> Iterator for Iter<R> where R: BufRead {
- type Item = ::Result<Event>;
- fn next(&mut self) -> Option<::Result<Event>> {
+impl<'a, R: 'a> Iterator for Iter<'a, R> where R: BufRead {
+ type Item = ::Result<Event<'a>>;
+ fn next(&mut self) -> Option<::Result<Event<'a>>> {
Some(bincode::decode_from::<R, Event>(&mut self.input, SizeLimit::Infinite)
.map_err(|_| ::IlcError::BincodeDecode))
}
}
-impl<W> Encode<W> for Binary where W: Write {
- fn encode(&self, mut output: W, event: &Event) -> ::Result<()> {
+impl<'a, W> Encode<'a, W> for Binary where W: Write {
+ fn encode(&'a self, _context: &'a Context, mut output: W, event: &'a Event) -> ::Result<()> {
bincode::encode_into(event, &mut output, SizeLimit::Infinite)
.map_err(|_| ::IlcError::BincodeEncode)
}
}
-impl<R> Decode<R, Iter<R>> for Binary where R: BufRead {
- fn decode(&mut self, input: R) -> Iter<R> {
- Iter { input: input }
+impl<'a, R: 'a> Decode<'a, R, Iter<'a, R>> for Binary where R: BufRead {
+ fn decode(&'a mut self, _context: &'a Context, input: R) -> Iter<R> {
+ Iter { _phantom: PhantomData, input: input }
}
}
diff --git a/src/format/energymech.rs b/src/format/energymech.rs
new file mode 100644
index 0000000..e6f7d80
--- /dev/null
+++ b/src/format/energymech.rs
@@ -0,0 +1,150 @@
+// Copyright 2015 Till Höppner
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::io::{ BufRead, Write };
+use std::borrow::{ ToOwned };
+use std::iter::{ Iterator };
+
+use event::{ Event, Type, Time };
+use context::Context;
+use format::{ Encode, Decode, rejoin, strip_one };
+
+use l::LogLevel::Info;
+
+use chrono::*;
+
+pub struct Energymech;
+
+static TIME_FORMAT: &'static str = "%H:%M:%S";
+
+pub struct Iter<'a, R: 'a> where R: BufRead {
+ context: &'a Context,
+ input: R,
+ buffer: String
+}
+
+impl<'a, R: 'a> Iterator for Iter<'a, R> where R: BufRead {
+ type Item = ::Result<Event<'a>>;
+ fn next(&mut self) -> Option<::Result<Event<'a>>> {
+ fn parse_time(context: &Context, time: &str) -> Time {
+ Time::Timestamp(context.timezone.from_local_date(&context.override_date)
+ .and_time(NaiveTime::from_hms(time[1..3].parse::<u32>().unwrap(),
+ time[4..6].parse::<u32>().unwrap(),
+ time[7..9].parse::<u32>().unwrap()))
+ .single()
+ .expect("Transformed log times can't be represented, due to timezone transitions")
+ .timestamp())
+ }
+
+ loop {
+ self.buffer.clear();
+ match self.input.read_line(&mut self.buffer) {
+ Ok(0) | Err(_) => return None,
+ Ok(_) => ()
+ }
+
+ let mut split_tokens: Vec<char> = Vec::new();
+ let tokens = self.buffer.split( |c: char| {
+ if c.is_whitespace() { split_tokens.push(c); true } else { false }
+ }).collect::<Vec<_>>();
+ if log_enabled!(Info) {
+ info!("Original: `{}`", self.buffer);
+ info!("Parsing: {:?}", tokens);
+ }
+ match &tokens[..tokens.len() - 1] {
+ [time, "*", nick, content..] => return Some(Ok(Event {
+ ty: Type::Action {
+ from: nick.to_owned().into(),
+ content: rejoin(content, &split_tokens[3..])
+ },
+ time: parse_time(&self.context, time),
+ channel: None
+ })),
+ [time, "***", old, "is", "now", "known", "as", new] => return Some(Ok(Event {
+ ty: Type::Nick {
+ old_nick: old.to_owned().into(),
+ new_nick: new.to_owned().into()
+ },
+ time: parse_time(&self.context, time),
+ channel: None
+ })),
+ [time, "***", "Joins:", nick, host] => return Some(Ok(Event {
+ ty: Type::Join {
+ nick: nick.to_owned().into(),
+ mask: Some(strip_one(host).into())
+ },
+ time: parse_time(&self.context, time),
+ channel: None
+ })),
+ [time, "***", "Quits:", nick, host, reason..] => return Some(Ok(Event {
+ ty: Type::Quit {
+ nick: nick.to_owned().into(),
+ mask: Some(strip_one(host).into()),
+ reason: Some(strip_one(&rejoin(reason, &split_tokens[5..])).into())
+ },
+ time: parse_time(&self.context, time),
+ channel: None
+ })),
+ [time, nick, content..]
+ if nick.starts_with('<') && nick.ends_with('>')
+ => return Some(Ok(Event {
+ ty: Type::Msg {
+ from: strip_one(nick).into(),
+ content: rejoin(content, &split_tokens[2..])
+ },
+ time: parse_time(&self.context, time),
+ channel: None
+ })),
+ _ => ()
+ }
+ }
+ }
+}
+
+impl<'a, R: 'a> Decode<'a, R, Iter<'a, R>> for Energymech where R: BufRead {
+ fn decode(&'a mut self, context: &'a Context, input: R) -> Iter<R> {
+ Iter {
+ context: context,
+ input: input,
+ buffer: String::new()
+ }
+ }
+}
+
+impl<'a, W> Encode<'a, W> for Energymech where W: Write {
+ fn encode(&'a self, context: &'a Context, mut output: W, event: &'a Event) -> ::Result<()> {
+ match event {
+ &Event { ty: Type::Msg { ref from, ref content }, ref time, .. } => {
+ try!(writeln!(&mut output, "[{}] <{}> {}",
+ time.with_format(&context.timezone, TIME_FORMAT), from, content))
+ },
+ &Event { ty: Type::Action { ref from, ref content }, ref time, .. } => {
+ try!(writeln!(&mut output, "[{}] * {} {}",
+ time.with_format(&context.timezone, TIME_FORMAT), from, content))
+ },
+ &Event { ty: Type::Nick { ref old_nick, ref new_nick }, ref time, .. } => {
+ try!(writeln!(&mut output, "[{}] *** {} is now known as {}",
+ time.with_format(&context.timezone, TIME_FORMAT), old_nick, new_nick))
+ },
+ &Event { ty: Type::Quit { ref nick, ref mask, ref reason }, ref time, .. } => {
+ try!(writeln!(&mut output, "[{}] *** Quits: {} ({}) ({})",
+ time.with_format(&context.timezone, TIME_FORMAT), nick,
+ mask.as_ref().expect("Mask not present, but required."),
+ reason.as_ref().expect("Reason not present, but required.")))
+ },
+ _ => ()
+ }
+ Ok(())
+ }
+}
diff --git a/src/format/mod.rs b/src/format/mod.rs
index f5692a0..db86a1d 100644
--- a/src/format/mod.rs
+++ b/src/format/mod.rs
@@ -17,16 +17,30 @@
//! target format, all formats must allow for omittable information.
use std::io::{ BufRead, Write };
+use std::borrow::Cow;
-use log::Event;
+use event::Event;
+use context::Context;
pub mod weechat3;
+pub mod energymech;
pub mod binary;
-pub trait Encode<W> where W: Write {
- fn encode(&self, output: W, event: &Event) -> ::Result<()>;
+pub trait Encode<'a, W> where W: Write {
+ fn encode(&'a self, context: &'a Context, output: W, event: &'a Event) -> ::Result<()>;
}
-pub trait Decode<R, O> where R: BufRead, O: Iterator<Item = ::Result<Event>> {
- fn decode(&mut self, input: R) -> O;
+pub trait Decode<'a, R, O> where R: BufRead, O: Iterator<Item = ::Result<Event<'a>>> {
+ fn decode(&'a mut self, context: &'a Context, input: R) -> O;
+}
+
+fn rejoin(s: &[&str], splits: &[char]) -> Cow<'static, str> {
+ let len = s.iter().map(|s| s.len()).sum();
+ let mut out = s.iter().zip(splits.iter()).fold(String::with_capacity(len),
+ |mut s, (b, &split)| { s.push_str(b); s.push(split); s });
+ out.pop(); Cow::Owned(out)
+}
+
+fn strip_one(s: &str) -> String {
+ if s.len() >= 2 { s[1..(s.len() - 1)].to_owned() } else { String::new() }
}
diff --git a/src/format/weechat3.rs b/src/format/weechat3.rs
index bc6e968..20ee1dd 100644
--- a/src/format/weechat3.rs
+++ b/src/format/weechat3.rs
@@ -13,39 +13,30 @@
// limitations under the License.
use std::io::{ BufRead, Write };
-use std::borrow::ToOwned;
+use std::borrow::{ ToOwned };
use std::iter::{ Iterator };
-use log::Event;
-use format::{ Encode, Decode };
+use event::{ Event, Type, Time };
+use context::Context;
+use format::{ Encode, Decode, rejoin, strip_one };
use l::LogLevel::Info;
-use chrono::*;
-
pub struct Weechat3;
static TIME_DATE_FORMAT: &'static str = "%Y-%m-%d %H:%M:%S";
-pub struct Iter<R> where R: BufRead {
+pub struct Iter<'a, R: 'a> where R: BufRead {
+ context: &'a Context,
input: R,
buffer: String
}
-impl<R> Iterator for Iter<R> where R: BufRead {
- type Item = ::Result<Event>;
- fn next(&mut self) -> Option<::Result<Event>> {
- fn timestamp(date: &str, time: &str) -> i64 {
- UTC.datetime_from_str(&format!("{} {}", date, time), TIME_DATE_FORMAT).unwrap().timestamp()
- }
- fn join(s: &[&str], splits: &[char]) -> String {
- let len = s.iter().map(|s| s.len()).sum();
- let mut out = s.iter().zip(splits.iter()).fold(String::with_capacity(len),
- |mut s, (b, &split)| { s.push_str(b); s.push(split); s });
- out.pop(); out
- }
- fn mask(s: &str) -> String {
- if s.len() >= 2 { s[1..(s.len() - 1)].to_owned() } else { String::new() }
+impl<'a, R: 'a> Iterator for Iter<'a, R> where R: BufRead {
+ type Item = ::Result<Event<'a>>;
+ fn next(&mut self) -> Option<::Result<Event<'a>>> {
+ fn parse_time(c: &Context, date: &str, time: &str) -> Time {
+ Time::from_format(&c.timezone, &format!("{} {}", date, time), TIME_DATE_FORMAT)
}
loop {
@@ -56,51 +47,89 @@ impl<R> Iterator for Iter<R> where R: BufRead {
}
let mut split_tokens: Vec<char> = Vec::new();
- let tokens = self.buffer.split( |c: char| {
+ let tokens = self.buffer.split(|c: char| {
if c.is_whitespace() { split_tokens.push(c); true } else { false }
}).collect::<Vec<_>>();
+
if log_enabled!(Info) {
info!("Original: `{}`", self.buffer);
info!("Parsing: {:?}", tokens);
}
- match tokens[..tokens.len() - 1].as_ref() {
- [date, time, "-->", nick, host, "has", "joined", channel, _..] => return Some(Ok(Event::Join {
- nick: nick.to_owned(), channel: channel.to_owned(), mask: mask(host),
- time: timestamp(date, time)
+
+ match &tokens[..tokens.len() - 1] {
+ [date, time, "-->", nick, host, "has", "joined", channel, _..]
+ => return Some(Ok(Event {
+ ty: Type::Join {
+ nick: nick.to_owned().into(),
+ mask: Some(strip_one(host).into()),
+ },
+ channel: Some(channel.to_owned().into()),
+ time: parse_time(&self.context, date, time)
})),
- [date, time, "<--", nick, host, "has", "left", channel, reason..] => return Some(Ok(Event::Part {
- nick: nick.to_owned(), channel: channel.to_owned(), mask: mask(host),
- reason: mask(&join(reason, &split_tokens[8..])), time: timestamp(date, time)
+ [date, time, "<--", nick, host, "has", "left", channel, reason..]
+ => return Some(Ok(Event {
+ ty: Type::Part {
+ nick: nick.to_owned().into(),
+ mask: Some(strip_one(host).into()),
+ reason: Some(strip_one(&rejoin(reason, &split_tokens[8..])).into()),
+ },
+ channel: Some(channel.to_owned().into()),
+ time: parse_time(&self.context, date, time)
})),
- [date, time, "<--", nick, host, "has", "quit", reason..] => return Some(Ok(Event::Quit {
- nick: nick.to_owned(), mask: mask(host),
- reason: mask(&join(reason, &split_tokens[7..])), time: timestamp(date, time)
+ [date, time, "<--", nick, host, "has", "quit", reason..]
+ => return Some(Ok(Event {
+ ty: Type::Quit {
+ nick: nick.to_owned().into(),
+ mask: Some(strip_one(host).into()),
+ reason: Some(strip_one(&rejoin(reason, &split_tokens[7..])).into()),
+ },
+ time: parse_time(&self.context, date, time),
+ channel: None
})),
[date, time, "--", notice, content..]
if notice.starts_with("Notice(")
- => return Some(Ok(Event::Notice {
- nick: notice["Notice(".len()..notice.len() - 2].to_owned(),
- content: join(content, &split_tokens[4..]),
- time: timestamp(date, time)
+ => return Some(Ok(Event {
+ ty: Type::Notice {
+ from: notice["Notice(".len()..notice.len() - 2].to_owned().into(),
+ content: rejoin(content, &split_tokens[4..]),
+ },
+ time: parse_time(&self.context, date, time),
+ channel: None
})),
- [date, time, "--", "irc:", "disconnected", "from", "server", _..] => return Some(Ok(Event::Disconnect {
- time: timestamp(date, time)
+ [date, time, "--", "irc:", "disconnected", "from", "server", _..]
+ => return Some(Ok(Event {
+ ty: Type::Disconnect,
+ time: parse_time(&self.context, date, time),
+ channel: None
})),
[date, time, "--", nick, verb, "now", "known", "as", new_nick]
if verb == "is" || verb == "are"
- => return Some(Ok(Event::Nick {
- old: nick.to_owned(), new: new_nick.to_owned(), time: timestamp(date, time)
+ => return Some(Ok(Event {
+ ty: Type::Nick {
+ old_nick: nick.to_owned().into(),
+ new_nick: new_nick.to_owned().into()
+ },
+ time: parse_time(&self.context, date, time),
+ channel: None
})),
[date, time, sp, "*", nick, msg..]
- if sp.is_empty()
- => return Some(Ok(Event::Action {
- from: nick.to_owned(), content: join(msg, &split_tokens[5..]),
- time: timestamp(date, time)
+ if sp.clone().is_empty()
+ => return Some(Ok(Event {
+ ty: Type::Action {
+ from: nick.to_owned().into(),
+ content: rejoin(msg, &split_tokens[5..]),
+ },
+ time: parse_time(&self.context, date, time),
+ channel: None
})),
- [date, time, nick, msg..] => return Some(Ok(Event::Msg {
- from: nick.to_owned(),
- content: join(msg, &split_tokens[3..]),
- time: timestamp(date, time)
+ [date, time, nick, msg..]
+ => return Some(Ok(Event {
+ ty: Type::Msg {
+ from: nick.to_owned().into(),
+ content: rejoin(msg, &split_tokens[3..]),
+ },
+ time: parse_time(&self.context, date, time),
+ channel: None
})),
_ => ()
}
@@ -108,51 +137,59 @@ impl<R> Iterator for Iter<R> where R: BufRead {
}
}
-impl<R> Decode<R, Iter<R>> for Weechat3 where R: BufRead {
- fn decode(&mut self, input: R) -> Iter<R> {
+impl<'a, R: 'a> Decode<'a, R, Iter<'a, R>> for Weechat3 where R: BufRead {
+ fn decode(&'a mut self, context: &'a Context, input: R) -> Iter<R> {
Iter {
+ context: context,
input: input,
buffer: String::new()
}
}
}
-impl<W> Encode<W> for Weechat3 where W: Write {
- fn encode(&self, mut output: W, event: &Event) -> ::Result<()> {
- fn date(t: i64) -> String {
- format!("{}", UTC.timestamp(t, 0).format(TIME_DATE_FORMAT))
- }
+impl<'a, W> Encode<'a, W> for Weechat3 where W: Write {
+ fn encode(&'a self, context: &'a Context, mut output: W, event: &'a Event) -> ::Result<()> {
match event {
- &Event::Msg { ref from, ref content, ref time } => {
- try!(writeln!(&mut output, "{}\t{}\t{}", date(*time), from, content))
+ &Event { ty: Type::Msg { ref from, ref content, .. }, ref time, .. } => {
+ try!(writeln!(&mut output, "{}\t{}\t{}",
+ time.with_format(&context.timezone, TIME_DATE_FORMAT), from, content))
},
- &Event::Action { ref from, ref content, ref time } => {
- try!(writeln!(&mut output, "{}\t *\t{} {}", date(*time), from, content))
+ &Event { ty: Type::Action { ref from, ref content, .. }, ref time, .. } => {
+ try!(writeln!(&mut output, "{}\t *\t{} {}",
+ time.with_format(&context.timezone, TIME_DATE_FORMAT), from, content))
},
- &Event::Join { ref nick, ref mask, ref channel, ref time } => {
+ &Event { ty: Type::Join { ref nick, ref mask, .. }, ref channel, ref time } => {
try!(writeln!(&mut output, "{}\t-->\t{} ({}) has joined {}",
- date(*time), nick, mask, channel))
+ time.with_format(&context.timezone, TIME_DATE_FORMAT), nick,
+ mask.as_ref().expect("Hostmask not present, but required."),
+ channel.as_ref().expect("Channel not present, but required.")))
},
- &Event::Part { ref nick, ref mask, ref channel, ref time, ref reason } => {
+ &Event { ty: Type::Part { ref nick, ref mask, ref reason }, ref channel, ref time } => {
try!(write!(&mut output, "{}\t<--\t{} ({}) has left {}",
- date(*time), nick, mask, channel));
- if reason.len() > 0 {
- try!(write!(&mut output, " ({})", reason));
+ time.with_format(&context.timezone, TIME_DATE_FORMAT), nick,
+ mask.as_ref().expect("Hostmask not present, but required."),
+ channel.as_ref().expect("Channel not present, but required.")));
+ if reason.is_some() && reason.as_ref().unwrap().len() > 0 {
+ try!(write!(&mut output, " ({})", reason.as_ref().unwrap()));
}
try!(write!(&mut output, "\n"))
},
- &Event::Quit { ref nick, ref mask, ref time, ref reason } => {
- try!(write!(&mut output, "{}\t<--\t{} ({}) has quit", date(*time), nick, mask));
- if reason.len() > 0 {
- try!(write!(&mut output, " ({})", reason));
+ &Event { ty: Type::Quit { ref nick, ref mask, ref reason }, ref time, .. } => {
+ try!(write!(&mut output, "{}\t<--\t{} ({}) has quit",
+ time.with_format(&context.timezone, TIME_DATE_FORMAT), nick,
+ mask.as_ref().expect("Hostmask not present, but required.")));
+ if reason.is_some() && reason.as_ref().unwrap().len() > 0 {
+ try!(write!(&mut output, " ({})", reason.as_ref().unwrap()));
}
try!(write!(&mut output, "\n"))
},
- &Event::Disconnect { ref time } => {
- try!(writeln!(&mut output, "{}\t--\tirc: disconnected from server", date(*time)))
+ &Event { ty: Type::Disconnect, ref time, .. } => {
+ try!(writeln!(&mut output, "{}\t--\tirc: disconnected from server",
+ time.with_format(&context.timezone, TIME_DATE_FORMAT)))
},
- &Event::Notice { ref nick, ref content, ref time } => {
- try!(writeln!(&mut output, "{}\t--\tNotice({}): {}", date(*time), nick, content))
+ &Event { ty: Type::Notice { ref from, ref content }, ref time, .. } => {
+ try!(writeln!(&mut output, "{}\t--\tNotice({}): {}",
+ time.with_format(&context.timezone, TIME_DATE_FORMAT), from, content))
},
_ => ()
}
diff --git a/src/freq.rs b/src/freq.rs
index 0ca4875..25810e7 100644
--- a/src/freq.rs
+++ b/src/freq.rs
@@ -13,11 +13,16 @@
// limitations under the License.
extern crate ilc;
+extern crate chrono;
use std::io;
use std::collections::hash_map::*;
-use ilc::log::Event::*;
+use chrono::offset::fixed::FixedOffset;
+use chrono::naive::date::NaiveDate;
+
+use ilc::event::{ Event, Type };
+use ilc::context::Context;
use ilc::format::{ self, Decode };
struct Person {
@@ -41,16 +46,20 @@ fn main() {
let stdin = io::stdin();
let mut stats: HashMap<String, Person> = HashMap::new();
+ let context = Context {
+ timezone: FixedOffset::west(0),
+ override_date: NaiveDate::from_ymd(2015, 6, 10)
+ };
let mut parser = format::weechat3::Weechat3;
- for e in parser.decode(stdin.lock()) {
+ for e in parser.decode(&context, stdin.lock()) {
let m = match e {
Ok(m) => m,
Err(err) => panic!(err)
};
match m {
- Msg { ref from, ref content, .. } => {
+ Event { ty: Type::Msg { ref from, ref content, .. }, .. } => {
let nick = strip_nick(from);
if stats.contains_key(nick) {
let p: &mut Person = stats.get_mut(nick).unwrap();
diff --git a/src/lib.rs b/src/lib.rs
index 27454b7..3df9cfd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,8 +21,9 @@ extern crate log as l;
extern crate rustc_serialize;
extern crate bincode;
-pub mod log;
+pub mod event;
pub mod format;
+pub mod context;
use std::convert::From;
use std::{ io, result };
diff --git a/src/log.rs b/src/log.rs
deleted file mode 100644
index 158233a..0000000
--- a/src/log.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2015 Till Höppner
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Common structures to represent the actual log data in memory.
-//! These will be used by all formats for encoding and decoding.
-
-/// A whole log, in memory. This structure does not specify its
-/// use. It may represent a private query, or the log of a channel.
-pub struct Log {
- pub entries: Vec<Event>
-}
-
-/// All representable events, such as messages, quits, joins
-/// and topic changes.
-#[derive(Debug, RustcEncodable, RustcDecodable)]
-pub enum Event {
- Connect {
- time: i64
- },
- Disconnect {
- time: i64
- },
- Msg {
- from: String,
- content: String,
- time: i64
- },
- Action {
- from: String,
- content: String,
- time: i64
- },
- Join {
- nick: String,
- channel: String,
- mask: String,
- time: i64
- },
- Part {
- nick: String,
- channel: String,
- mask: String,
- reason: String,
- time: i64
- },
- Quit {
- nick: String,
- mask: String,
- reason: String,
- time: i64
- },
- Nick {
- old: String,
- new: String,
- time: i64
- },
- Notice {
- nick: String,
- content: String,
- time: i64
- },
- Kick {
- kicked_nick: String,
- kicking_nick: String,
- kick_message: String,
- time: i64
- },
- Topic {
- topic: String,
- time: i64
- },
- TopicChange {
- new_topic: String,
- time: i64
- },
- Mode {
- time: i64
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 99e2659..de5f85c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,6 +16,7 @@
#![plugin(regex_macros)]
extern crate ilc;
+extern crate chrono;
extern crate docopt;
extern crate rustc_serialize;
extern crate libc;
@@ -29,6 +30,10 @@ use std::io::{ self, BufReader };
use docopt::Docopt;
+use chrono::offset::fixed::FixedOffset;
+use chrono::naive::date::NaiveDate;
+
+use ilc::context::Context;
use ilc::format::{ self, Encode, Decode };
static USAGE: &'static str = r#"
@@ -71,13 +76,18 @@ fn main() {
}
if args.cmd_parse {
- let mut parser = format::weechat3::Weechat3;
+ let context = Context {
+ timezone: FixedOffset::west(0),
+ override_date: NaiveDate::from_ymd(2015, 6, 10)
+ };
+ let mut parser = format::energymech::Energymech;
+ let formatter = format::energymech::Energymech;
for file in args.arg_file {
let f: BufReader<File> = BufReader::new(File::open(file).unwrap());
- let iter = parser.decode(f);
+ let iter = parser.decode(&context, f);
for e in iter {
info!("Parsed: {:?}", e);
- drop(parser.encode(io::stdout(), &e.unwrap()));
+ drop(formatter.encode(&context, io::stdout(), &e.unwrap()));
}
}
}