1mod fetch;
2mod ui;
3mod widgets;
4mod welcome;
5
6use std::{env, sync::Arc, time::Duration};
7use reqwest::Client;
8use tokio::time::interval;
9
10use ui::draw_ui;
11
12use fetch::{
13 fetch_query_log::fetch_adguard_query_log,
14 fetch_stats::fetch_adguard_stats,
15 fetch_status::fetch_adguard_status,
16 fetch_filters::fetch_adguard_filter_list
17};
18
19async fn run() -> anyhow::Result<()> {
20
21 let client = Client::new();
23
24 let ip = env::var("ADGUARD_IP")?;
26 let port = env::var("ADGUARD_PORT")?;
27 let protocol = env::var("ADGUARD_PROTOCOL").unwrap_or("http".to_string());
28 let hostname = format!("{}://{}:{}", protocol, ip, port);
29 let username = env::var("ADGUARD_USERNAME")?;
30 let password = env::var("ADGUARD_PASSWORD")?;
31
32
33 let filters = fetch_adguard_filter_list(&client, &hostname, &username, &password).await?;
35
36 let (queries_tx, queries_rx) = tokio::sync::mpsc::channel(1);
38 let (stats_tx, stats_rx) = tokio::sync::mpsc::channel(1);
39 let (status_tx, status_rx) = tokio::sync::mpsc::channel(1);
40
41 let shutdown = Arc::new(tokio::sync::Notify::new());
43
44 let draw_ui_task = tokio::spawn(
46 draw_ui(queries_rx, stats_rx, status_rx, filters, Arc::clone(&shutdown))
47 );
48
49 let interval_secs: u64 = env::var("ADGUARD_UPDATE_INTERVAL")
51 .unwrap_or_else(|_| "2".into()).parse()?;
52 let mut interval = interval(Duration::from_secs(interval_secs));
53
54 loop {
56 tokio::select! {
57 _ = interval.tick() => {
58 let queries = fetch_adguard_query_log(&client, &hostname, &username, &password).await?;
59 if queries_tx.send(queries.data).await.is_err() {
60 return Err(anyhow::anyhow!("Failed to send query data"));
61 }
62
63 let stats = fetch_adguard_stats(&client, &hostname, &username, &password).await?;
64 if stats_tx.send(stats).await.is_err() {
65 return Err(anyhow::anyhow!("Failed to send stats data"));
66 }
67
68 let status = fetch_adguard_status(&client, &hostname, &username, &password).await?;
69 if status_tx.send(status).await.is_err() {
70 return Err(anyhow::anyhow!("Failed to send status data"));
71 }
72 }
73 _ = shutdown.notified() => {
74 break;
75 }
76 }
77 }
78
79 draw_ui_task.await??;
80
81 Ok(())
82}
83
84fn main() {
85 let rt = tokio::runtime::Runtime::new().unwrap();
86 rt.block_on(async {
87 welcome::welcome().await.map_err(|e| {
88 eprintln!("Failed to initialize: {}", e);
89 std::io::Error::new(std::io::ErrorKind::Other, "Failed to initialize")
90 }).unwrap();
91
92 run().await.map_err(|e| {
93 eprintln!("Failed to run: {}", e);
94 std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to run: {}", e))
95 }).unwrap_or_else(|e| {
96 eprintln!("Error: {}", e);
97 std::process::exit(1);
98 });
99 });
100}
101