adguardian/
main.rs

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    // Create a reqwest client
22    let client = Client::new();
23
24    // AdGuard instance details, from env vars (verified in welcome.rs)
25    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    // Fetch data that doesn't require updates
34    let filters = fetch_adguard_filter_list(&client, &hostname, &username, &password).await?;
35
36    // Open channels for data fetching where updates are required
37    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    // Create a channel for the UI to notify the fetcher to shutdown
42    let shutdown = Arc::new(tokio::sync::Notify::new());
43
44    // Spawn the UI task, pass data and update channels
45    let draw_ui_task = tokio::spawn(
46        draw_ui(queries_rx, stats_rx, status_rx, filters, Arc::clone(&shutdown))
47    );
48
49    // Get update interval (in seconds)
50    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    // Open loop for fetching data at the specified interval
55    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