diff options
Diffstat (limited to 'src/feature')
-rw-r--r-- | src/feature/mod.rs | 6 | ||||
-rw-r--r-- | src/feature/topanime.rs | 119 |
2 files changed, 124 insertions, 1 deletions
diff --git a/src/feature/mod.rs b/src/feature/mod.rs index a52bb2c..b57c179 100644 --- a/src/feature/mod.rs +++ b/src/feature/mod.rs | |||
@@ -2,9 +2,11 @@ use std::boxed::Box; | |||
2 | 2 | ||
3 | extern crate telegram_bot; | 3 | extern crate telegram_bot; |
4 | use telegram_bot::{Api, Message}; | 4 | use telegram_bot::{Api, Message}; |
5 | extern crate rustc_serialize; | ||
5 | 6 | ||
6 | pub mod jisoku; | 7 | pub mod jisoku; |
7 | pub mod tasterank; | 8 | pub mod tasterank; |
9 | pub mod topanime; | ||
8 | 10 | ||
9 | pub enum FeatureResult { | 11 | pub enum FeatureResult { |
10 | Handled, | 12 | Handled, |
@@ -18,5 +20,7 @@ pub trait Feature { | |||
18 | } | 20 | } |
19 | 21 | ||
20 | pub fn init() -> Vec<Box<Feature>> { | 22 | pub fn init() -> Vec<Box<Feature>> { |
21 | vec![Box::new(tasterank::Tasterank::new()), Box::new(jisoku::Jisoku::new())] | 23 | vec![Box::new(tasterank::Tasterank::new()), |
24 | Box::new(jisoku::Jisoku::new()), | ||
25 | Box::new(topanime::TopAnime::new())] | ||
22 | } | 26 | } |
diff --git a/src/feature/topanime.rs b/src/feature/topanime.rs new file mode 100644 index 0000000..cccc976 --- /dev/null +++ b/src/feature/topanime.rs | |||
@@ -0,0 +1,119 @@ | |||
1 | use std::io; | ||
2 | use std::io::prelude::*; | ||
3 | use std::fs::File; | ||
4 | use std::usize; | ||
5 | |||
6 | extern crate telegram_bot; | ||
7 | use telegram_bot::{Api, Message, MessageType}; | ||
8 | extern crate time; | ||
9 | extern crate regex; | ||
10 | use self::regex::Regex; | ||
11 | use super::rustc_serialize::json; | ||
12 | |||
13 | use feature::FeatureResult; | ||
14 | use feature::Feature; | ||
15 | |||
16 | #[derive(RustcDecodable)] | ||
17 | pub struct Anime { | ||
18 | name: String, | ||
19 | score: f64, | ||
20 | } | ||
21 | |||
22 | impl Anime { | ||
23 | pub fn new(name: &str, score: f64) -> Anime { | ||
24 | Anime { | ||
25 | name: name.to_owned(), | ||
26 | score: score, | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | |||
31 | pub struct TopAnime { | ||
32 | animes: Vec<Anime>, | ||
33 | last_access: f64, | ||
34 | } | ||
35 | |||
36 | impl Feature for TopAnime { | ||
37 | fn name(&self) -> &'static str { | ||
38 | "Tasterank" | ||
39 | } | ||
40 | fn init(&mut self) {} | ||
41 | fn handle(&mut self, a: Api, m: Message) -> Result<FeatureResult, String> { | ||
42 | if let MessageType::Text(s) = m.msg { | ||
43 | let re = Regex::new(r"(?i)luggas top ([0-9]{1,3}) anime").unwrap(); | ||
44 | let cap = re.captures(&s); | ||
45 | let s_num = match cap { | ||
46 | Some(s) => s.at(1), | ||
47 | None => return Ok(FeatureResult::Skip), | ||
48 | }; | ||
49 | let s_num = match s_num { | ||
50 | Some(s) => s, | ||
51 | None => return Ok(FeatureResult::Skip), | ||
52 | }; | ||
53 | |||
54 | // parse to int | ||
55 | let num = match s_num.parse::<i32>() { | ||
56 | Ok(n) => n, | ||
57 | Err(e) => { | ||
58 | println!("{}", e); | ||
59 | return Ok(FeatureResult::Skip); | ||
60 | } | ||
61 | }; | ||
62 | let start = time::precise_time_ns(); | ||
63 | if let Err(e) = self.update_animes() { | ||
64 | println!("{}", e); | ||
65 | return Ok(FeatureResult::Skip); | ||
66 | } | ||
67 | println!("(benchm) updating animes: {}ms", | ||
68 | (time::precise_time_ns() - start) / 1000000); | ||
69 | |||
70 | let mut msg = String::new(); | ||
71 | for i in 0..num { | ||
72 | let i = i as usize; | ||
73 | if self.animes.len() <= i { | ||
74 | break; | ||
75 | } | ||
76 | msg.push_str(&format!("{}. {} ({}%)\n", | ||
77 | i + 1, | ||
78 | self.animes[i].name, | ||
79 | self.animes[i].score)); | ||
80 | } | ||
81 | println!("(benchm) anime before send: {}ms", | ||
82 | (time::precise_time_ns() - start) / 1000000); | ||
83 | if let Err(e) = a.send_message(m.chat.id(), msg, None, None, Some(m.message_id), None) { | ||
84 | println!("{}", e); | ||
85 | } | ||
86 | println!("(benchm) anime: {}ms", | ||
87 | (time::precise_time_ns() - start) / 1000000); | ||
88 | return Ok(FeatureResult::Handled); | ||
89 | } | ||
90 | Ok(FeatureResult::Skip) | ||
91 | } | ||
92 | } | ||
93 | |||
94 | impl TopAnime { | ||
95 | pub fn new() -> TopAnime { | ||
96 | let mut t = TopAnime { | ||
97 | animes: vec![], | ||
98 | last_access: 0f64, | ||
99 | }; | ||
100 | t.init(); | ||
101 | t | ||
102 | } | ||
103 | fn update_animes(&mut self) -> Result<(), io::Error> { | ||
104 | let now = time::precise_time_s(); | ||
105 | if now - self.last_access < 3600.0f64 { | ||
106 | return Ok(()); | ||
107 | } | ||
108 | let mut f = try!(File::open("data/animescore.json")); | ||
109 | let mut buf = String::new(); | ||
110 | try!(f.read_to_string(&mut buf)); | ||
111 | let v: Vec<Anime> = match json::decode(&buf) { | ||
112 | Ok(v) => v, | ||
113 | Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, format!("{}", e))), | ||
114 | }; | ||
115 | self.animes = v; | ||
116 | self.last_access = now; | ||
117 | Ok(()) | ||
118 | } | ||
119 | } | ||