1pub use ferron_common::logging::*;
2
3use std::{cmp::Ordering, collections::HashMap, net::IpAddr, sync::Arc};
4
5use async_channel::{Receiver, Sender};
6
7use crate::util::{is_localhost, match_hostname};
8
9#[derive(Clone, Eq, PartialEq, Hash)]
11pub struct LoggerFilter {
12 pub hostname: Option<String>,
14
15 pub ip: Option<IpAddr>,
17
18 pub port: Option<u16>,
20}
21
22impl Ord for LoggerFilter {
23 fn cmp(&self, other: &Self) -> Ordering {
24 self
25 .port
26 .is_some()
27 .cmp(&other.port.is_some())
28 .then_with(|| self.ip.is_some().cmp(&other.ip.is_some()))
29 .then_with(|| {
30 self
31 .hostname
32 .as_ref()
33 .map(|h| !h.starts_with("*."))
34 .cmp(&other.hostname.as_ref().map(|h| !h.starts_with("*.")))
35 }) .then_with(|| {
37 self
38 .hostname
39 .as_ref()
40 .map(|h| h.trim_end_matches('.').chars().filter(|c| *c == '.').count())
41 .cmp(
42 &other
43 .hostname
44 .as_ref()
45 .map(|h| h.trim_end_matches('.').chars().filter(|c| *c == '.').count()),
46 )
47 }) }
49}
50
51impl PartialOrd for LoggerFilter {
52 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
53 Some(self.cmp(other))
54 }
55}
56
57impl LoggerFilter {
58 pub fn is_global(&self) -> bool {
60 self.hostname.is_none() && self.ip.is_none() && self.port.is_none()
61 }
62}
63
64pub struct LoggersBuilder {
66 pub inner: HashMap<LoggerFilter, (Sender<LogMessage>, Receiver<LogMessage>)>,
67}
68
69impl LoggersBuilder {
70 pub fn new() -> Self {
72 Self { inner: HashMap::new() }
73 }
74
75 pub fn add(
77 &mut self,
78 filter: LoggerFilter,
79 logger: (Sender<LogMessage>, Receiver<LogMessage>),
80 ) -> (Sender<LogMessage>, Receiver<LogMessage>) {
81 if let Some(existing_logger) = self.inner.get(&filter) {
82 existing_logger.clone()
83 } else {
84 let new_logger = logger.clone();
85 self.inner.insert(filter, logger);
86 new_logger
87 }
88 }
89
90 #[allow(dead_code)]
92 pub fn build(self) -> Loggers {
93 let mut inner_vector = self.inner.into_iter().map(|(k, v)| (k, v.0)).collect::<Vec<_>>();
94 inner_vector.sort_by(|a, b| a.0.cmp(&b.0));
95 Loggers {
96 inner: Arc::new(inner_vector),
97 }
98 }
99
100 pub fn build_borrowed(&self) -> Loggers {
102 let mut inner_vector = self
103 .inner
104 .iter()
105 .map(|(k, v)| (k.clone(), v.0.clone()))
106 .collect::<Vec<_>>();
107 inner_vector.reverse();
108 inner_vector.sort_by(|a, b| a.0.cmp(&b.0));
109 Loggers {
110 inner: Arc::new(inner_vector),
111 }
112 }
113}
114
115pub struct Loggers {
116 inner: Arc<Vec<(LoggerFilter, Sender<LogMessage>)>>,
117}
118
119impl Loggers {
120 pub fn find_global_logger(&self) -> Option<Sender<LogMessage>> {
122 self
123 .inner
124 .iter()
125 .find(|logger| logger.0.is_global())
126 .map(|logger| &logger.1)
127 .cloned()
128 }
129
130 pub fn find_logger(&self, hostname: Option<&str>, ip: IpAddr, port: u16) -> Option<Sender<LogMessage>> {
132 self
137 .inner
138 .iter()
139 .rev()
140 .find(|&logger| {
141 match_hostname(logger.0.hostname.as_deref(), hostname)
142 && ((logger.0.ip.is_none() && (!is_localhost(logger.0.ip.as_ref(), logger.0.hostname.as_deref())
143 || ip.to_canonical().is_loopback())) || logger.0.ip == Some(ip))
145 && (logger.0.port.is_none() || logger.0.port == Some(port))
146 })
147 .map(|logger| &logger.1)
148 .cloned()
149 }
150}
151
152impl Clone for Loggers {
153 fn clone(&self) -> Self {
155 Self {
156 inner: self.inner.clone(),
157 }
158 }
159}