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
/*
rss2tg
Copyright (C) 2017  ejiek

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

extern crate curl;
extern crate rss;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::cmp::Ordering;
use std::fs::File;
use std::io::prelude::*;
use std::error;
use std::thread;
use std::time::Duration;
use std::sync::mpsc::{self, TryRecvError};
use rss::Channel;
use curl::easy::Easy;

pub use notification::Notification;
mod notification;

pub use subscription::Subscription;
mod subscription;

pub use config::Config;
mod config;

/// Main logic of this crate.
pub fn run(config: Config) -> Result<(), Box<error::Error>> {
    let subscriptions = config.subscriptions();
    let mut threads = vec![];

    for subscription in subscriptions.iter() {
        let sub_clone = subscription.clone();
        threads.push(thread::spawn(move || {
            if let Err(e) = main_loop(sub_clone) {
                println!("Thread error{}", e);
            }
        }));
    }

    for thread in threads {
        let _ = thread.join();
    }
    Ok(())
}

fn main_loop(subscription: Subscription) -> Result<(), Box<error::Error>> {
    loop {
        let channel = Channel::from_url(subscription.rss_url()).unwrap();
        let items = channel.items();
        let items_iter = items.iter();

        let mut f = File::open(subscription.last_guid_file().as_ref().unwrap())?;

        let mut contents = String::new();
        f.read_to_string(&mut contents)?;

        let mut last_guid: u64 = 0;

        for line in contents.lines() {
            last_guid = line.parse::<u64>().unwrap();
        }


        let mut notifications: Vec<Notification> = Vec::new();

        for val in items_iter {
            if val.guid().unwrap().value().parse::<u64>().unwrap() > last_guid {
                notifications.push(Notification::new(
                    String::from(val.title().unwrap()),
                    val.guid().unwrap().value().parse::<u64>().unwrap(),
                ));
            }
        }

        notifications.sort();

        for val in notifications.iter() {
            send_update(val.text(), subscription.bot_token(), subscription.chat_id());
            let mut f = File::create(subscription.last_guid_file().as_ref().unwrap())?;
            f.write(val.guid().to_string().as_bytes())?;
            println!("{:?}", val.text());
        }
        thread::sleep(Duration::from_secs(10));
    }
}

/// Sends text using given bot to a given channel.
fn send_update(data: &String, bot_token: &String, chat_id: &String) {
    let address = format!(
        "{}{}{}",
        "https://api.telegram.org/bot",
        bot_token,
        "/sendMessage"
    );
    let data = format!("{}{}{}{}", "chat_id=", chat_id, "&text=", data);
    let mut data = data.as_bytes();

    let mut easy = Easy::new();
    easy.url(&address).unwrap();
    easy.post(true).unwrap();
    easy.post_field_size(data.len() as u64).unwrap();

    let mut transfer = easy.transfer();
    transfer
        .read_function(|buf| Ok(data.read(buf).unwrap_or(0)))
        .unwrap();
    transfer.perform().unwrap();
}