counters + singleton pattern implementation
parent
14b62814dc
commit
a844b32e27
|
@ -1,8 +1,7 @@
|
||||||
use crate::domain::{Action, LogMessage, LogPort, ModuleArgs, Record, Value};
|
use crate::domain::{Action, LogMessage, LogPort, ModuleArgs, Record, Singleton, Value};
|
||||||
|
use crate::singleton_borrow;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::ops::{Index, Range};
|
use std::ops::{Index, Range};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
type LogFormat = fn(&str) -> LogMessage;
|
type LogFormat = fn(&str) -> LogMessage;
|
||||||
|
|
||||||
|
@ -16,14 +15,14 @@ const INFO_LOG_FORMAT: LogFormat = |s| LogMessage::INFO(&s);
|
||||||
const DEBUG_LOG_FORMAT: LogFormat = |s| LogMessage::DEBUG(&s);
|
const DEBUG_LOG_FORMAT: LogFormat = |s| LogMessage::DEBUG(&s);
|
||||||
|
|
||||||
pub struct Log {
|
pub struct Log {
|
||||||
logger: Rc<RefCell<dyn LogPort>>,
|
logger: Singleton<dyn LogPort>,
|
||||||
log_format: LogFormat,
|
log_format: LogFormat,
|
||||||
template: String,
|
template: String,
|
||||||
var_locations: Vec<Range<usize>>,
|
var_locations: Vec<Range<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Log {
|
impl Log {
|
||||||
pub fn from_args(mut args: ModuleArgs, logger: Rc<RefCell<dyn LogPort>>) -> Log {
|
pub fn from_args(mut args: ModuleArgs, logger: Singleton<dyn LogPort>) -> Log {
|
||||||
let log_format = match args.remove("level") {
|
let log_format = match args.remove("level") {
|
||||||
Some(Value::Str(l)) => match l.as_ref() {
|
Some(Value::Str(l)) => match l.as_ref() {
|
||||||
"EMERG" => EMERG_LOG_FORMAT,
|
"EMERG" => EMERG_LOG_FORMAT,
|
||||||
|
@ -82,28 +81,25 @@ impl Log {
|
||||||
impl Action for Log {
|
impl Action for Log {
|
||||||
fn act(&mut self, record: &mut Record) -> Result<(), ()> {
|
fn act(&mut self, record: &mut Record) -> Result<(), ()> {
|
||||||
let message = self.message_with_variables_from_record(record);
|
let message = self.message_with_variables_from_record(record);
|
||||||
(self.logger.borrow_mut()).write((self.log_format)(&message))
|
singleton_borrow!(self.logger).write((self.log_format)(&message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Log;
|
use super::Log;
|
||||||
use crate::assert_log_match;
|
use crate::domain::test_util::FakeLog;
|
||||||
use crate::domain::test_util::*;
|
use crate::domain::{Action, ModuleArgs, Record, Singleton, Value};
|
||||||
use crate::domain::{Action, ModuleArgs, Record, Value};
|
use crate::{assert_log_match, singleton_new, singleton_share};
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "The Log action needs a message template in “message”")]
|
#[should_panic(expected = "The Log action needs a message template in “message”")]
|
||||||
fn arg_message_is_mandatory() {
|
fn arg_message_is_mandatory() {
|
||||||
let args: ModuleArgs = HashMap::new();
|
let args: ModuleArgs = HashMap::new();
|
||||||
let logger = Rc::new(RefCell::new(FakeLog::new(Vec::new())));
|
let logger = singleton_new!(FakeLog::new(Vec::new()));
|
||||||
Log::from_args(args, logger.clone());
|
Log::from_args(args, singleton_share!(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -166,14 +162,14 @@ mod tests {
|
||||||
level: Option<&str>,
|
level: Option<&str>,
|
||||||
logs: Vec<Result<Record, ()>>,
|
logs: Vec<Result<Record, ()>>,
|
||||||
vars: Vec<(&str, &str)>,
|
vars: Vec<(&str, &str)>,
|
||||||
) -> (Log, Rc<RefCell<FakeLog>>, Record) {
|
) -> (Log, Singleton<FakeLog>, Record) {
|
||||||
let mut args: ModuleArgs = HashMap::new();
|
let mut args: ModuleArgs = HashMap::new();
|
||||||
args.insert("message".to_string(), Value::Str(template.to_string()));
|
args.insert("message".to_string(), Value::Str(template.to_string()));
|
||||||
if let Some(l) = level {
|
if let Some(l) = level {
|
||||||
args.insert("level".to_string(), Value::Str(l.to_string()));
|
args.insert("level".to_string(), Value::Str(l.to_string()));
|
||||||
}
|
}
|
||||||
let logger = Rc::new(RefCell::new(FakeLog::new(logs)));
|
let logger = singleton_new!(FakeLog::new(logs));
|
||||||
let log = Log::from_args(args, logger.clone());
|
let log = Log::from_args(args, singleton_share!(logger));
|
||||||
let mut record: Record = HashMap::new();
|
let mut record: Record = HashMap::new();
|
||||||
for (name, value) in vars {
|
for (name, value) in vars {
|
||||||
record.insert(name.to_string(), Value::Str(value.to_string()));
|
record.insert(name.to_string(), Value::Str(value.to_string()));
|
||||||
|
|
|
@ -1,4 +1,63 @@
|
||||||
|
mod counter_raise;
|
||||||
|
pub use self::counter_raise::*;
|
||||||
|
mod counter_reset;
|
||||||
|
pub use self::counter_reset::*;
|
||||||
mod log;
|
mod log;
|
||||||
pub use self::log::*;
|
pub use self::log::*;
|
||||||
mod noop;
|
mod noop;
|
||||||
pub use self::noop::*;
|
pub use self::noop::*;
|
||||||
|
|
||||||
|
use crate::domain::{Counters, CountersPort, ModuleArgs, Singleton, Value};
|
||||||
|
use chrono::Duration;
|
||||||
|
|
||||||
|
pub struct CounterAction<C: CountersPort> {
|
||||||
|
counters: Singleton<Counters<C>>,
|
||||||
|
counter_name: String,
|
||||||
|
counter_key: String,
|
||||||
|
save_into: Option<String>,
|
||||||
|
duration: Option<Duration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CountersPort> CounterAction<C> {
|
||||||
|
pub fn from_args<X: CountersPort>(
|
||||||
|
mut args: ModuleArgs,
|
||||||
|
counters: Singleton<Counters<X>>,
|
||||||
|
action_name: &str,
|
||||||
|
duration_name: &str,
|
||||||
|
) -> CounterAction<X> {
|
||||||
|
let counter_name = remove_acceptable_key(&mut args, "counter").expect(&format!(
|
||||||
|
"The {} action needs a counter name in “counter”",
|
||||||
|
action_name
|
||||||
|
));
|
||||||
|
let counter_key = remove_acceptable_key(&mut args, "for").expect(&format!(
|
||||||
|
"The {} action needs a counter key in “for”",
|
||||||
|
action_name
|
||||||
|
));
|
||||||
|
let save_into = remove_acceptable_key(&mut args, "save");
|
||||||
|
let duration = match args.remove(duration_name) {
|
||||||
|
None => None,
|
||||||
|
Some(Value::Int(i)) => Some(Duration::seconds(i as i64)),
|
||||||
|
_ => panic!(format!(
|
||||||
|
"The {} only accepts a number of seconds in “{}”",
|
||||||
|
action_name, duration_name
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
CounterAction {
|
||||||
|
counters,
|
||||||
|
counter_name,
|
||||||
|
counter_key,
|
||||||
|
save_into,
|
||||||
|
duration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_acceptable_key(args: &mut ModuleArgs, key: &str) -> Option<String> {
|
||||||
|
match args.remove(key) {
|
||||||
|
None => None,
|
||||||
|
Some(Value::Str(s)) => Some(s),
|
||||||
|
Some(Value::Int(i)) => Some(format!("{}", i)),
|
||||||
|
Some(Value::Date(d)) => Some(format!("{}", d.timestamp())),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,21 +9,59 @@ mod module;
|
||||||
pub use self::module::*;
|
pub use self::module::*;
|
||||||
mod workflow;
|
mod workflow;
|
||||||
pub use self::workflow::*;
|
pub use self::workflow::*;
|
||||||
|
mod counter;
|
||||||
|
pub use self::counter::*;
|
||||||
|
|
||||||
use chrono::DateTime;
|
use chrono::{DateTime, Utc};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Str(String),
|
Str(String),
|
||||||
Int(isize),
|
Int(isize),
|
||||||
Date(DateTime<chrono::Utc>),
|
Date(DateTime<Utc>),
|
||||||
Map(HashMap<String, Value>),
|
Map(HashMap<String, Value>),
|
||||||
List(Vec<Value>),
|
List(Vec<Value>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Hash for Value {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
match self {
|
||||||
|
Value::Bool(b) => b.hash(state),
|
||||||
|
Value::Str(s) => s.hash(state),
|
||||||
|
Value::Int(i) => i.hash(state),
|
||||||
|
Value::Date(d) => d.hash(state),
|
||||||
|
Value::Map(h) => h.keys().collect::<Vec<&String>>().sort().hash(state),
|
||||||
|
Value::List(v) => v.hash(state),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type Record = HashMap<String, Value>;
|
pub type Record = HashMap<String, Value>;
|
||||||
|
pub type Singleton<T> = std::rc::Rc<std::cell::RefCell<T>>;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! singleton_new {
|
||||||
|
( $s:expr ) => {
|
||||||
|
std::rc::Rc::new(std::cell::RefCell::new($s))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! singleton_share {
|
||||||
|
( $s:expr ) => {
|
||||||
|
$s.clone()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! singleton_borrow {
|
||||||
|
( $s:expr ) => {
|
||||||
|
(*$s).borrow_mut()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_util;
|
mod test_util;
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub type ModuleArgs = HashMap<String, Value>;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Module, Modules, Record, Value};
|
use super::{Module, Modules, Record, Value};
|
||||||
use crate::domain::test_util::*;
|
use crate::domain::test_util::{FakeAction, FakeFilter, ACT_NAME, FLT_NAME};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -80,9 +80,9 @@ mod tests {
|
||||||
let mut module = Module::new(ACT_NAME.to_string(), HashMap::new(), &mods).unwrap();
|
let mut module = Module::new(ACT_NAME.to_string(), HashMap::new(), &mods).unwrap();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assert!(module.run(&mut record) == Ok(true));
|
assert_eq!(module.run(&mut record), Ok(true));
|
||||||
assert!(record.contains_key(ACT_NAME));
|
assert!(record.contains_key(ACT_NAME));
|
||||||
assert!(record[ACT_NAME] == Value::Int(1));
|
assert_eq!(record[ACT_NAME], Value::Int(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -96,8 +96,8 @@ mod tests {
|
||||||
let mut module = Module::new(FLT_NAME.to_string(), HashMap::new(), &mods).unwrap();
|
let mut module = Module::new(FLT_NAME.to_string(), HashMap::new(), &mods).unwrap();
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assert!(module.run(&mut record) == Ok(false));
|
assert_eq!(module.run(&mut record), Ok(false));
|
||||||
assert!(record.contains_key(FLT_NAME));
|
assert!(record.contains_key(FLT_NAME));
|
||||||
assert!(record[FLT_NAME] == Value::Int(1));
|
assert_eq!(record[FLT_NAME], Value::Int(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::domain::{Action, Filter, LogMessage, LogPort, Record, Value};
|
use crate::domain::{Action, CounterData, CounterRef, CountersPort, Filter, LogMessage, LogPort, Record, Singleton, Value};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub const ACT_NAME: &str = "fake_action";
|
pub const ACT_NAME: &str = "fake_action";
|
||||||
pub const FLT_NAME: &str = "fake_filter";
|
pub const FLT_NAME: &str = "fake_filter";
|
||||||
|
@ -66,3 +67,28 @@ impl LogPort for FakeLog {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FakeCountersAdapter {
|
||||||
|
pub counters: Singleton<HashMap<(String, Value), CounterData>>,
|
||||||
|
}
|
||||||
|
impl CountersPort for FakeCountersAdapter {
|
||||||
|
fn modify(
|
||||||
|
&mut self,
|
||||||
|
entry: CounterRef,
|
||||||
|
data: CounterData,
|
||||||
|
mut f: impl FnMut(&mut CounterData, CounterData) -> usize,
|
||||||
|
) -> usize {
|
||||||
|
let k = (entry.0.to_string(), entry.1.clone());
|
||||||
|
if !singleton_borrow!(self.counters).contains_key(&k) {
|
||||||
|
singleton_borrow!(self.counters).insert(k.clone(), (0, None));
|
||||||
|
}
|
||||||
|
f(singleton_borrow!(self.counters).get_mut(&k).unwrap(), data)
|
||||||
|
}
|
||||||
|
fn remove(&mut self, entry: CounterRef) -> Option<CounterData> {
|
||||||
|
let k = (entry.0.to_string(), entry.1.clone());
|
||||||
|
singleton_borrow!(self.counters).remove(&k)
|
||||||
|
}
|
||||||
|
fn remove_if(&mut self, predicate: impl Fn(&CounterData) -> bool) {
|
||||||
|
singleton_borrow!(self.counters).retain(|_, v| !predicate(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ fn node_wants_chain(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::domain::test_util::*;
|
use crate::domain::test_util::{FakeAction, FakeFilter, ACT_NAME, FLT_NAME};
|
||||||
use crate::domain::{Chain, Config, Modules, Record, Step, Value, Workflow};
|
use crate::domain::{Chain, Config, Modules, Record, Step, Value, Workflow};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -208,12 +208,12 @@ mod tests {
|
||||||
wf.run(&mut record);
|
wf.run(&mut record);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assert!(wf.nodes.len() == 1);
|
assert_eq!(wf.nodes.len(), 1);
|
||||||
assert!(wf.nodes[0].name == "chain1[0]:fake_action");
|
assert_eq!(wf.nodes[0].name, "chain1[0]:fake_action");
|
||||||
assert!(wf.nodes[0].then_dest < 0);
|
assert!(wf.nodes[0].then_dest < 0);
|
||||||
assert!(wf.nodes[0].else_dest < 0);
|
assert!(wf.nodes[0].else_dest < 0);
|
||||||
assert!(record[ACT_NAME] == Value::Int(1));
|
assert_eq!(record[ACT_NAME], Value::Int(1));
|
||||||
assert!(record.get(FLT_NAME) == None);
|
assert_eq!(record.get(FLT_NAME), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -252,15 +252,15 @@ mod tests {
|
||||||
wf.run(&mut record);
|
wf.run(&mut record);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assert!(wf.nodes.len() == 2);
|
assert_eq!(wf.nodes.len(), 2);
|
||||||
assert!(wf.nodes[0].name == "chain1[0]:fake_filter");
|
assert_eq!(wf.nodes[0].name, "chain1[0]:fake_filter");
|
||||||
assert!(wf.nodes[1].name == "chain2[0]:fake_action");
|
assert_eq!(wf.nodes[1].name, "chain2[0]:fake_action");
|
||||||
assert!(wf.nodes[0].then_dest < 0);
|
assert!(wf.nodes[0].then_dest < 0);
|
||||||
assert!(wf.nodes[0].else_dest == 1);
|
assert_eq!(wf.nodes[0].else_dest, 1);
|
||||||
assert!(wf.nodes[1].then_dest < 0);
|
assert!(wf.nodes[1].then_dest < 0);
|
||||||
assert!(wf.nodes[1].else_dest < 0);
|
assert!(wf.nodes[1].else_dest < 0);
|
||||||
assert!(record[ACT_NAME] == Value::Int(1));
|
assert_eq!(record[ACT_NAME], Value::Int(1));
|
||||||
assert!(record[FLT_NAME] == Value::Int(1));
|
assert_eq!(record[FLT_NAME], Value::Int(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -299,14 +299,14 @@ mod tests {
|
||||||
wf.run(&mut record);
|
wf.run(&mut record);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assert!(wf.nodes.len() == 2);
|
assert_eq!(wf.nodes.len(), 2);
|
||||||
assert!(wf.nodes[0].name == "chain1[0]:fake_filter");
|
assert_eq!(wf.nodes[0].name, "chain1[0]:fake_filter");
|
||||||
assert!(wf.nodes[1].name == "chain2[0]:fake_action");
|
assert_eq!(wf.nodes[1].name, "chain2[0]:fake_action");
|
||||||
assert!(wf.nodes[0].then_dest < 0);
|
assert!(wf.nodes[0].then_dest < 0);
|
||||||
assert!(wf.nodes[0].else_dest == 1);
|
assert_eq!(wf.nodes[0].else_dest, 1);
|
||||||
assert!(wf.nodes[1].then_dest < 0);
|
assert!(wf.nodes[1].then_dest < 0);
|
||||||
assert!(wf.nodes[1].else_dest < 0);
|
assert!(wf.nodes[1].else_dest < 0);
|
||||||
assert!(record[ACT_NAME] == Value::Int(1));
|
assert_eq!(record[ACT_NAME], Value::Int(1));
|
||||||
assert!(record[FLT_NAME] == Value::Int(1));
|
assert_eq!(record[FLT_NAME], Value::Int(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -324,14 +324,20 @@ mod tests {
|
||||||
let conf = SerdeConfigAdapter::from_json(json).config;
|
let conf = SerdeConfigAdapter::from_json(json).config;
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assert!(conf.actions.len() == 2);
|
assert_eq!(conf.actions.len(), 2);
|
||||||
assert!(conf.actions.get_index(0).unwrap().0 == "Detect request errors with Nextcloud");
|
assert_eq!(
|
||||||
assert!(
|
conf.actions.get_index(0).unwrap().0,
|
||||||
conf.actions.get_index(1).unwrap().0
|
"Detect request errors with Nextcloud"
|
||||||
== "… Report insufficient buffer-size for Nextcloud QUERY_STRING"
|
|
||||||
);
|
);
|
||||||
assert!(conf.actions.get_index(0).unwrap().1.len() == 3);
|
assert_eq!(
|
||||||
assert!(conf.actions.get_index(0).unwrap().1[1].module == String::from("filter_pcre"));
|
conf.actions.get_index(1).unwrap().0,
|
||||||
assert!(conf.options.get("debug") == Some(&Value::Bool(false)));
|
"… Report insufficient buffer-size for Nextcloud QUERY_STRING"
|
||||||
|
);
|
||||||
|
assert_eq!(conf.actions.get_index(0).unwrap().1.len(), 3);
|
||||||
|
assert_eq!(
|
||||||
|
conf.actions.get_index(0).unwrap().1[1].module,
|
||||||
|
String::from("filter_pcre")
|
||||||
|
);
|
||||||
|
assert_eq!(conf.options.get("debug"), Some(&Value::Bool(false)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::domain::{LogMessage, LogPort, Record, Value};
|
use crate::domain::{LogMessage, LogPort, Record, Value};
|
||||||
use chrono::DateTime;
|
use chrono::{DateTime, Utc};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use systemd::journal::{print, Journal, OpenOptions};
|
use systemd::journal::{print, Journal, OpenOptions};
|
||||||
|
@ -13,7 +13,7 @@ const INT_MAPPER: JournalFieldMapper = |s| {
|
||||||
.unwrap_or(Value::Str(s))
|
.unwrap_or(Value::Str(s))
|
||||||
};
|
};
|
||||||
const DATE_MAPPER: JournalFieldMapper = |s| {
|
const DATE_MAPPER: JournalFieldMapper = |s| {
|
||||||
s.parse::<DateTime<chrono::Utc>>()
|
s.parse::<DateTime<Utc>>()
|
||||||
.map(|d| Value::Date(d))
|
.map(|d| Value::Date(d))
|
||||||
.unwrap_or(Value::Str(s))
|
.unwrap_or(Value::Str(s))
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod counter;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -1,29 +1,50 @@
|
||||||
|
#[macro_use]
|
||||||
mod domain;
|
mod domain;
|
||||||
mod infra;
|
mod infra;
|
||||||
mod service;
|
mod service;
|
||||||
|
|
||||||
use crate::domain::action::Log;
|
use crate::domain::action::{CounterRaise, CounterReset, Log, Noop};
|
||||||
use crate::domain::action::Noop;
|
|
||||||
use crate::domain::filter::Equals;
|
use crate::domain::filter::Equals;
|
||||||
use crate::domain::{ConfigPort, Modules, Workflow};
|
use crate::domain::{ConfigPort, Counters, Modules, Workflow};
|
||||||
use crate::infra::config::ConfFile;
|
use crate::infra::config::ConfFile;
|
||||||
|
use crate::infra::counter::InMemoryCounterAdapter;
|
||||||
use crate::infra::log::SystemdLogAdapter;
|
use crate::infra::log::SystemdLogAdapter;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
type CountersImpl = InMemoryCounterAdapter;
|
||||||
|
type LogImpl = SystemdLogAdapter;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut conf = ConfFile::from_filesystem().to_config();
|
let mut conf = ConfFile::from_filesystem().to_config();
|
||||||
let log = Rc::new(RefCell::new(
|
let log = singleton_new!(LogImpl::open().expect("Error initializing systemd"));
|
||||||
SystemdLogAdapter::open().expect("Error initializing systemd"),
|
|
||||||
));
|
|
||||||
let mut modules = Modules::new();
|
let mut modules = Modules::new();
|
||||||
|
let counters = singleton_new!(Counters::<CountersImpl>::new(CountersImpl::new()));
|
||||||
|
let gets_moved_into_closure = singleton_share!(counters);
|
||||||
modules.register_action(
|
modules.register_action(
|
||||||
"action_noop".to_string(),
|
"action_counterRaise".to_string(),
|
||||||
Box::new(move |a| Box::new(Noop::from_args(a))),
|
Box::new(move |a| {
|
||||||
|
Box::new(CounterRaise::<CountersImpl>::from_args(
|
||||||
|
a,
|
||||||
|
singleton_share!(gets_moved_into_closure), // clone for each call of the constructor
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let gets_moved_into_closure = singleton_share!(counters);
|
||||||
|
modules.register_action(
|
||||||
|
"action_counterReset".to_string(),
|
||||||
|
Box::new(move |a| {
|
||||||
|
Box::new(CounterReset::<CountersImpl>::from_args(
|
||||||
|
a,
|
||||||
|
singleton_share!(gets_moved_into_closure), // clone for each call of the constructor
|
||||||
|
))
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
modules.register_action(
|
modules.register_action(
|
||||||
"action_log".to_string(),
|
"action_log".to_string(),
|
||||||
Box::new(move |a| Box::new(Log::from_args(a, log.clone()))),
|
Box::new(move |a| Box::new(Log::from_args(a, singleton_share!(log)))),
|
||||||
|
);
|
||||||
|
modules.register_action(
|
||||||
|
"action_noop".to_string(),
|
||||||
|
Box::new(move |a| Box::new(Noop::from_args(a))),
|
||||||
);
|
);
|
||||||
modules.register_filter(
|
modules.register_filter(
|
||||||
"filter_equals".to_string(),
|
"filter_equals".to_string(),
|
||||||
|
|
Loading…
Reference in New Issue