1use crate::plugin::Plugin;
8use std::borrow::Cow;
9use std::fmt;
10use std::sync::{Arc, Mutex};
11
12use ek_event::Event;
13
14pub const EVENT_LOG: &str = "eLog";
15pub const EVENT_PLUG_DOWN_PREFIX: &str = "ePlugQDown.";
16
17pub const LOG_LEVEL_INFO: u8 = 20;
19pub const LOG_LEVEL_WARN: u8 = 30;
20pub const LOG_LEVEL_ERROR: u8 = 40;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct LogData {
25 pub level: u8,
26 pub source: String,
27 pub msg: String,
28}
29
30impl fmt::Display for LogData {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 write!(f, "[{}] {}: {}", self.level, self.source, self.msg)
33 }
34}
35
36pub type LogSink = Arc<dyn Fn(&LogData) + Send + Sync>;
38
39fn default_console_sink() -> LogSink {
40 Arc::new(|d: &LogData| println!("{d}"))
41}
42
43pub struct LogPlugin {
45 sink: Mutex<LogSink>,
46}
47
48impl LogPlugin {
49 pub fn console() -> Self {
50 Self { sink: Mutex::new(default_console_sink()) }
51 }
52 pub fn with_sink(sink: impl Fn(&LogData) + Send + Sync + 'static) -> Self {
53 Self { sink: Mutex::new(Arc::new(sink)) }
54 }
55 pub fn set_sink(&self, sink: LogSink) {
56 *self.sink.lock().unwrap() = sink;
57 }
58}
59
60impl Plugin for LogPlugin {
61 fn name(&self) -> &str {
62 "log"
63 }
64
65 fn routes(&self) -> Vec<Cow<'static, str>> {
66 vec![Cow::Borrowed(EVENT_LOG)]
67 }
68
69 fn on_mail(&self, event: &Event) {
70 if let Some(d) = event.data.downcast_ref::<LogData>() {
71 let sink = self.sink.lock().unwrap().clone();
72 sink(d);
73 }
74 }
75}