#[macro_use]
extern crate wascc_codec as codec;
use codec::capabilities::{
CapabilityDescriptor, CapabilityProvider, Dispatcher, NullDispatcher, OperationDirection,
OP_GET_CAPABILITY_DESCRIPTOR,
};
use codec::core::{OP_BIND_ACTOR, OP_REMOVE_ACTOR};
use codec::{
deserialize,
logging::{WriteLogRequest, OP_LOG},
serialize,
};
#[macro_use]
extern crate log;
use std::error::Error;
use std::sync::RwLock;
#[cfg(not(feature = "static_plugin"))]
capability_provider!(LoggingProvider, LoggingProvider::new);
const CAPABILITY_ID: &str = "wascc:logging";
const SYSTEM_ACTOR: &str = "system";
const VERSION: &str = env!("CARGO_PKG_VERSION");
const REVISION: u32 = 2;
const ERROR: u32 = 1;
const WARN: u32 = 2;
const INFO: u32 = 3;
const DEBUG: u32 = 4;
const TRACE: u32 = 5;
pub struct LoggingProvider {
dispatcher: RwLock<Box<dyn Dispatcher>>,
}
impl Default for LoggingProvider {
fn default() -> Self {
match env_logger::try_init() {
Ok(_) => {}
Err(_) => {}
}
LoggingProvider {
dispatcher: RwLock::new(Box::new(NullDispatcher::new())),
}
}
}
impl LoggingProvider {
pub fn new() -> Self {
Self::default()
}
fn get_descriptor(&self) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
Ok(serialize(
CapabilityDescriptor::builder()
.id(CAPABILITY_ID)
.name("waSCC Default Logging Provider (STDOUT)")
.long_description(
"A simple logging capability provider that supports levels from error to trace",
)
.version(VERSION)
.revision(REVISION)
.with_operation(
OP_LOG,
OperationDirection::ToProvider,
"Sends a log message to stdout",
)
.build(),
)?)
}
fn write_log(
&self,
actor: &str,
log_msg: WriteLogRequest,
) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
match log_msg.level {
ERROR => error!("[{}] {}", actor, log_msg.body),
WARN => warn!("[{}] {}", actor, log_msg.body),
INFO => info!("[{}] {}", actor, log_msg.body),
DEBUG => debug!("[{}] {}", actor, log_msg.body),
TRACE => trace!("[{}] {}", actor, log_msg.body),
_ => error!("Unknown log level: {}", log_msg.level),
}
Ok(vec![])
}
}
impl CapabilityProvider for LoggingProvider {
fn configure_dispatch(
&self,
dispatcher: Box<dyn Dispatcher>,
) -> Result<(), Box<dyn Error + Sync + Send>> {
let mut lock = self.dispatcher.write().unwrap();
*lock = dispatcher;
Ok(())
}
fn handle_call(
&self,
actor: &str,
op: &str,
msg: &[u8],
) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
match op {
OP_BIND_ACTOR if actor == SYSTEM_ACTOR => Ok(vec![]),
OP_REMOVE_ACTOR if actor == SYSTEM_ACTOR => Ok(vec![]),
OP_GET_CAPABILITY_DESCRIPTOR if actor == SYSTEM_ACTOR => self.get_descriptor(),
OP_LOG => self.write_log(actor, deserialize(msg)?),
_ => Err(format!("Unknown operation: {}", op).into()),
}
}
}