1use std::collections::HashSet;
2use std::sync::Arc;
3
4use crate::{DnsRule, RuleStore};
5use serde::{Deserialize, Serialize};
6use tokio::sync::broadcast;
7use tokio_util::sync::CancellationToken;
8
9use crate::ipc::DnsEvent;
10
11#[derive(Debug)]
13pub struct AppState {
14 pub store: RuleStore,
15 pub events: broadcast::Sender<DnsEvent>,
16 pub token: CancellationToken,
17}
18
19pub type SharedState = Arc<AppState>;
20
21#[derive(Serialize, Deserialize, Default)]
22pub struct DnsConfig {
23 pub rules: Vec<DnsRule>,
24}
25
26impl AppState {
27 pub(crate) fn new(token: CancellationToken) -> Self {
28 let (events, _) = broadcast::channel(64);
29 Self {
30 store: RuleStore::new(),
31 events,
32 token,
33 }
34 }
35}
36
37impl AppState {
38 pub fn dispatch(&self, event: DnsEvent) -> bool {
39 self.events.send(event).is_ok()
40 }
41
42 pub fn snapshot_permanent(&self) -> Vec<DnsRule> {
43 self.store.snapshot_persistent()
44 }
45
46 pub fn snapshot_all_domains(&self) -> Vec<String> {
47 self.store
48 .snapshot_all()
49 .into_iter()
50 .map(|r| r.domain)
51 .collect::<HashSet<_>>()
52 .into_iter()
53 .collect()
54 }
55
56 pub fn save(&self) {
57 let config = DnsConfig {
58 rules: self.snapshot_permanent(),
59 };
60 if let Err(e) = confy::store("sidedns", "rules", &config) {
61 tracing::warn!("Failed to save rules: {e}");
62 } else {
63 tracing::info!("Rules saved");
64 }
65 }
66
67 pub fn load_rules(&self) -> Vec<DnsRule> {
68 let rules = match confy::load::<DnsConfig>("sidedns", "rules") {
69 Ok(c) => c.rules,
70 Err(e) => {
71 tracing::warn!("Failed to load saved rules: {e}");
72 vec![]
73 },
74 };
75 let size = self.store.add_all(rules.clone());
76 tracing::info!("Loaded {} saved rule(s)", size);
77 rules
78 }
79}