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
mod fetch;
mod ui;
mod widgets;
mod welcome;
use std::{env, sync::Arc, time::Duration};
use reqwest::Client;
use tokio::time::interval;
use ui::draw_ui;
use fetch::{
fetch_query_log::fetch_adguard_query_log,
fetch_stats::fetch_adguard_stats,
fetch_status::fetch_adguard_status,
fetch_filters::fetch_adguard_filter_list
};
async fn run() -> anyhow::Result<()> {
let client = Client::new();
let ip = env::var("ADGUARD_IP")?;
let port = env::var("ADGUARD_PORT")?;
let protocol = env::var("ADGUARD_PROTOCOL").unwrap_or("http".to_string());
let hostname = format!("{}://{}:{}", protocol, ip, port);
let username = env::var("ADGUARD_USERNAME")?;
let password = env::var("ADGUARD_PASSWORD")?;
let filters = fetch_adguard_filter_list(&client, &hostname, &username, &password).await?;
let (queries_tx, queries_rx) = tokio::sync::mpsc::channel(1);
let (stats_tx, stats_rx) = tokio::sync::mpsc::channel(1);
let (status_tx, status_rx) = tokio::sync::mpsc::channel(1);
let shutdown = Arc::new(tokio::sync::Notify::new());
let draw_ui_task = tokio::spawn(
draw_ui(queries_rx, stats_rx, status_rx, filters, Arc::clone(&shutdown))
);
let interval_secs: u64 = env::var("ADGUARD_UPDATE_INTERVAL")
.unwrap_or_else(|_| "2".into()).parse()?;
let mut interval = interval(Duration::from_secs(interval_secs));
loop {
tokio::select! {
_ = interval.tick() => {
let queries = fetch_adguard_query_log(&client, &hostname, &username, &password).await?;
if queries_tx.send(queries.data).await.is_err() {
return Err(anyhow::anyhow!("Failed to send query data"));
}
let stats = fetch_adguard_stats(&client, &hostname, &username, &password).await?;
if stats_tx.send(stats).await.is_err() {
return Err(anyhow::anyhow!("Failed to send stats data"));
}
let status = fetch_adguard_status(&client, &hostname, &username, &password).await?;
if status_tx.send(status).await.is_err() {
return Err(anyhow::anyhow!("Failed to send status data"));
}
}
_ = shutdown.notified() => {
break;
}
}
}
draw_ui_task.await??;
Ok(())
}
fn main() {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
welcome::welcome().await.map_err(|e| {
eprintln!("Failed to initialize: {}", e);
std::io::Error::new(std::io::ErrorKind::Other, "Failed to initialize")
}).unwrap();
run().await.map_err(|e| {
eprintln!("Failed to run: {}", e);
std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to run: {}", e))
}).unwrap_or_else(|e| {
eprintln!("Error: {}", e);
std::process::exit(1);
});
});
}