1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use self::super::{AppTokens, Event, read_toml_file, github};
use chrono::{FixedOffset, Duration, DateTime, Local};
use self::super::super::Error;
use toml::encode_str;
use std::path::Path;
use std::io::Write;
use std::fs::File;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Feed {
pub subject: String,
pub server: u64,
pub channel: u64,
pub e_tag: Option<String>,
pub latest: Option<DateTime<FixedOffset>>,
pub next_min: Option<DateTime<FixedOffset>>,
pub latest_event: Option<u64>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct FeedForSerialisation {
pub subject: String,
pub server: u64,
pub channel: u64,
pub e_tag: Option<String>,
pub latest: Option<String>,
pub next_min: Option<String>,
pub latest_event: Option<u64>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
struct Feeds {
feed: Vec<FeedForSerialisation>,
}
impl Feed {
pub fn new(subject: String, server_id: u64, channel_id: u64) -> Feed {
Feed {
subject: subject,
server: server_id,
channel: channel_id,
e_tag: None,
latest: None,
next_min: None,
latest_event: None,
}
}
pub fn read(p: &Path) -> Result<Vec<Feed>, Error> {
let feeds: Feeds = try!(read_toml_file(p, "Followed feeds"));
Ok(feeds.feed.into_iter().map(FeedForSerialisation::into).collect())
}
pub fn write(feeds: Vec<Feed>, p: &Path) {
File::create(p).unwrap().write_all(encode_str(&Feeds { feed: feeds.into_iter().map(FeedForSerialisation::from).collect() }).as_bytes()).unwrap();
}
pub fn poll(&mut self, tkn: &AppTokens) -> Result<Vec<Event>, Error> {
let (mut events, next) = if self.e_tag.is_none() {
let (ctnt, etag, next) = try!(if !self.subject.contains('/') {
github::poll_user_events_new(&self.subject, tkn)
} else {
github::poll_repo_events_new(&self.subject, tkn)
});
self.e_tag = Some(etag);
(Event::parse(&ctnt), next)
} else {
let (ctnt_etag, next) = try!(if !self.subject.contains('/') {
github::poll_user_events_update(&self.subject, self.e_tag.as_ref().unwrap(), tkn)
} else {
github::poll_repo_events_update(&self.subject, self.e_tag.as_ref().unwrap(), tkn)
});
match ctnt_etag {
Some((ctnt, etag)) => {
self.e_tag = Some(etag);
(Event::parse(&ctnt), next)
}
None => (vec![], next),
}
};
let now = Local::now();
let now = now.with_timezone(now.offset());
self.latest = Some(now);
self.next_min = Some(now + Duration::seconds(next as i64));
events.reverse();
if let Some(latest_event_id) = self.latest_event {
events = events.into_iter().skip_while(|ev| ev.id != latest_event_id).skip(1).collect();
}
if !events.is_empty() {
self.latest_event = Some(events[events.len() - 1].id);
}
Ok(events)
}
}
impl From<Feed> for FeedForSerialisation {
fn from(f: Feed) -> FeedForSerialisation {
FeedForSerialisation {
subject: f.subject,
server: f.server,
channel: f.channel,
e_tag: f.e_tag,
latest: f.latest.map(|dt| dt.to_rfc3339()),
next_min: f.next_min.map(|dt| dt.to_rfc3339()),
latest_event: f.latest_event,
}
}
}
impl Into<Feed> for FeedForSerialisation {
fn into(self) -> Feed {
Feed {
subject: self.subject,
server: self.server,
channel: self.channel,
e_tag: self.e_tag,
latest: self.latest.map(|dts| DateTime::parse_from_rfc3339(&dts).unwrap()),
next_min: self.next_min.map(|dts| DateTime::parse_from_rfc3339(&dts).unwrap()),
latest_event: self.latest_event,
}
}
}