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
use current_platform::{COMPILED_ON, CURRENT_PLATFORM};
use db::Database;
use dotenv::dotenv;
use handlers::fabric;
use log::{self, error, info};
use simple_logger::SimpleLogger;
use std::collections::HashMap;
use tokio::{self, runtime};
pub mod db;
pub mod handlers;
pub mod prompt;
pub mod telegram_client;
pub mod updater;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

async fn async_main() -> Result<()> {
    println!(
        "TelepAIr v{} running on {} - Compiled on {}.",
        env!("CARGO_PKG_VERSION"),
        CURRENT_PLATFORM,
        COMPILED_ON
    );
    dotenv().ok();

    SimpleLogger::new()
        .with_level(log::LevelFilter::Info)
        .init()
        .unwrap();

    let mut db = Database::new();
    db.save();
    info!("db loaded: ");

    let api_id = db.get_api_id();
    let api_hash = db.get_api_hash();

    info!("Starting telepAIr with {} {}", api_id, api_hash);

    let (client, sign_out) =
        telegram_client::establish_telegram_connection(api_id, api_hash.to_string()).await?;

    // Start Dependency Setup
    fabric::fabric_setup().await?;
    fabric::execute_fabric_command(&["--updatepatterns"]).await?;

    let me = client.get_me().await?;
    let username = me.username().unwrap();

    let mut dialogs = client.iter_dialogs();

    info!(
        "{} ({}) has {} chats",
        username,
        me.id(),
        dialogs.total().await?
    );

    let mut dialogs = client.iter_dialogs();
    let mut chat_map = HashMap::new();

    while let Some(dialog) = dialogs.next().await? {
        let chat = dialog.chat();
        info!("{: >10} - {}", chat.id(), chat.name());
        chat_map.insert(chat.id(), chat.name().to_owned());
        if me.id() == chat.id() {
            info!("Found ME chat - {}", chat.id());
            if !db.chat_id_exists(&chat.id()) {
                db.add_chat_id(chat.id());
            }
            client
                .send_message(
                    chat,
                    format!(
                        "Hello {}, I am here to serve.  `/help` to get started.",
                        username
                    ),
                )
                .await?;
        }
    }

    if sign_out {
        drop(client.sign_out_disconnect().await);
    } else {
        tokio::select!(
            _ = tokio::signal::ctrl_c() => {
                info!("Got SIGINT; quitting early gracefully");
                info!("Saving Session");
                match client.session().save_to_file(telegram_client::SESSION_FILE) {
                    Ok(_) => {
                        info!("Saved our session")
                    }
                    Err(e) => {
                        error!("NOTE: failed to save the sessio {e}");
                    }
                }

                let _ = client.sign_out_disconnect().await;
            }
            r = handlers::update_handler::handle_updates(client.clone(), chat_map, &mut db) => {
                match r {
                    Ok(_) => info!("Got disconnected from Telegram gracefully"),
                    Err(e) =>{
                        match client.session().save_to_file(telegram_client::SESSION_FILE) {
                            Ok(_) => {
                                info!("Saved our session")
                            }
                            Err(e) => {
                                error!("NOTE: failed to save the sessio {e}");
                            }
                        };

                        error!("Error during update handling: {}", e)
                    },
                }
            }
        );
    }

    Ok(())
}

fn main() -> Result<()> {
    match updater::update() {
        Ok(_) => {}
        Err(e) => error!("Auto updater failed {}", e),
    };

    runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async_main())
}