Skip to main content

sidedns_core/ipc/
handler.rs

1use async_trait::async_trait;
2use tokio::sync::broadcast;
3
4use crate::DnsRule;
5use crate::ipc::message::{DnsEvent, IpcRequest, IpcResponse};
6use crate::ipc::server::IpcHandler;
7use crate::state::AppState;
8
9macro_rules! validate_domain {
10    ($domain:ident) => {
11        if !crate::validate_domain(&$domain) {
12            tracing::warn!("Invalid domain name: {}", $domain);
13            return IpcResponse::Error(format!("Invalid domain name: {}", $domain));
14        }
15        let $domain = $domain.to_lowercase();
16    };
17}
18
19#[async_trait]
20impl IpcHandler for AppState {
21    async fn handle(&self, request: IpcRequest) -> IpcResponse {
22        match request {
23            IpcRequest::Add {
24                domain,
25                target,
26                https,
27            } => {
28                validate_domain!(domain);
29                let rule = self.store.add(DnsRule::new(domain.clone(), target, https));
30                tracing::info!("Rule {rule} added");
31                self.events.send(DnsEvent::RuleAdded(rule)).ok();
32                IpcResponse::Ok
33            },
34
35            IpcRequest::AddEphemeral {
36                domain,
37                target,
38                https,
39            } => {
40                validate_domain!(domain);
41                let rule = self
42                    .store
43                    .add_ephemeral(DnsRule::new(domain.clone(), target, https));
44                tracing::info!("Ephemeral rule {rule} added");
45                self.events.send(DnsEvent::EphemeralAdded(rule)).ok();
46                IpcResponse::Ok
47            },
48
49            IpcRequest::Remove { domain } => {
50                validate_domain!(domain);
51                let removed = self.store.remove(&domain);
52                if let Some(rule) = removed {
53                    tracing::info!("Rule {rule} removed");
54                    self.events.send(DnsEvent::RuleRemoved(rule)).ok();
55                    IpcResponse::Ok
56                } else {
57                    IpcResponse::Error(format!("No rule found for '{domain}'"))
58                }
59            },
60
61            IpcRequest::RemoveEphemeral { domain } => {
62                validate_domain!(domain);
63                let removed = self.store.remove_ephemeral(&domain);
64                if let Some(rule) = removed {
65                    tracing::info!("Ephemeral rule {rule} removed");
66                    self.events.send(DnsEvent::EphemeralRemoved(rule)).ok();
67                    IpcResponse::Ok
68                } else {
69                    IpcResponse::Error(format!("No ephemeral rule found for '{domain}'"))
70                }
71            },
72
73            IpcRequest::List => {
74                let rules = self.store.snapshot_persistent();
75                IpcResponse::Rules(rules)
76            },
77
78            IpcRequest::Resolve { domain } => {
79                validate_domain!(domain);
80                IpcResponse::Resolved(self.store.resolve(&domain))
81            },
82
83            IpcRequest::Status => IpcResponse::Status {
84                running: true,
85                rule_count: self.store.len(),
86            },
87
88            IpcRequest::Stop => {
89                tracing::info!("Stop requested via IPC");
90                self.events.send(DnsEvent::DaemonStopped).ok();
91                self.token.cancel();
92                IpcResponse::Ok
93            },
94            IpcRequest::Subscribe => IpcResponse::Ok,
95        }
96    }
97
98    fn subscribe_events(&self) -> broadcast::Receiver<DnsEvent> {
99        self.events.subscribe()
100    }
101}