use std::{borrow::Cow, ops::BitOrAssign};
use serde::{Deserialize, Serialize};
use zenoh_keyexpr::keyexpr;
use zenoh_result::ZResult;
use crate::StructVersion;
#[derive(Debug, Clone)]
pub enum PluginDiff {
Delete(String),
Start(zenoh_config::PluginLoad),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
pub enum PluginState {
Declared,
Loaded,
Started,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, PartialOrd, Ord)]
pub enum PluginReportLevel {
#[default]
Info,
Warning,
Error,
}
impl BitOrAssign for PluginReportLevel {
fn bitor_assign(&mut self, rhs: Self) {
if *self < rhs {
*self = rhs;
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Default, Deserialize)]
pub struct PluginReport {
level: PluginReportLevel,
#[serde(skip_serializing_if = "Vec::is_empty")]
messages: Vec<Cow<'static, str>>,
}
pub trait PluginStatus {
fn name(&self) -> &str;
fn id(&self) -> &str;
fn version(&self) -> Option<&str>;
fn long_version(&self) -> Option<&str>;
fn path(&self) -> &str;
fn state(&self) -> PluginState;
fn report(&self) -> PluginReport;
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PluginStatusRec<'a> {
pub name: Cow<'a, str>,
pub id: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<Cow<'a, str>>,
pub long_version: Option<Cow<'a, str>>,
pub path: Cow<'a, str>,
pub state: PluginState,
pub report: PluginReport,
}
impl PluginStatus for PluginStatusRec<'_> {
fn name(&self) -> &str {
&self.name
}
fn id(&self) -> &str {
&self.id
}
fn version(&self) -> Option<&str> {
self.version.as_deref()
}
fn long_version(&self) -> Option<&str> {
self.long_version.as_deref()
}
fn path(&self) -> &str {
&self.path
}
fn state(&self) -> PluginState {
self.state
}
fn report(&self) -> PluginReport {
self.report.clone()
}
}
impl<'a> PluginStatusRec<'a> {
pub fn new<T: PluginStatus + ?Sized>(plugin: &'a T) -> Self {
Self {
name: Cow::Borrowed(plugin.name()),
id: Cow::Borrowed(plugin.id()),
version: plugin.version().map(Cow::Borrowed),
long_version: plugin.long_version().map(Cow::Borrowed),
path: Cow::Borrowed(plugin.path()),
state: plugin.state(),
report: plugin.report(),
}
}
pub fn into_owned(self) -> PluginStatusRec<'static> {
PluginStatusRec {
name: Cow::Owned(self.name.into_owned()),
id: Cow::Owned(self.id.into_owned()),
version: self.version.map(|v| Cow::Owned(v.into_owned())),
long_version: self.long_version.map(|v| Cow::Owned(v.into_owned())),
path: Cow::Owned(self.path.into_owned()),
state: self.state,
report: self.report,
}
}
pub(crate) fn prepend_name(self, prefix: &str) -> Self {
Self {
name: Cow::Owned(format!("{}/{}", prefix, self.name)),
..self
}
}
}
pub trait PluginControl {
fn report(&self) -> PluginReport {
PluginReport::default()
}
fn plugins_status(&self, _names: &keyexpr) -> Vec<PluginStatusRec<'_>> {
Vec::new()
}
}
pub trait PluginStartArgs: StructVersion {}
pub trait PluginInstance: PluginControl + Send + Sync {}
pub trait Plugin: Sized + 'static {
type StartArgs: PluginStartArgs;
type Instance: PluginInstance;
const DEFAULT_NAME: &'static str;
const PLUGIN_VERSION: &'static str;
const PLUGIN_LONG_VERSION: &'static str;
fn start(name: &str, args: &Self::StartArgs) -> ZResult<Self::Instance>;
}
#[macro_export]
macro_rules! plugin_version {
() => {
env!("CARGO_PKG_VERSION")
};
}
#[macro_export]
macro_rules! plugin_long_version {
() => {
$crate::export::git_version::git_version!(prefix = "v", cargo_prefix = "v")
};
}
impl PluginReport {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
*self = Self::default();
}
pub fn get_level(&self) -> PluginReportLevel {
self.level
}
pub fn add_error<S: Into<Cow<'static, str>>>(&mut self, error: S) {
self.level |= PluginReportLevel::Error;
self.messages.push(error.into());
}
pub fn add_warning<S: Into<Cow<'static, str>>>(&mut self, warning: S) {
self.level |= PluginReportLevel::Warning;
self.messages.push(warning.into());
}
pub fn add_info<S: Into<Cow<'static, str>>>(&mut self, message: S) {
self.level |= PluginReportLevel::Info;
self.messages.push(message.into());
}
pub fn messages(&self) -> &[Cow<'static, str>] {
&self.messages
}
}
pub trait PluginConditionSetter {
fn add_error(self, report: &mut PluginReport) -> Self;
fn add_warning(self, report: &mut PluginReport) -> Self;
fn add_info(self, report: &mut PluginReport) -> Self;
}
impl<T, E: ToString> PluginConditionSetter for core::result::Result<T, E> {
fn add_error(self, report: &mut PluginReport) -> Self {
if let Err(e) = &self {
report.add_error(e.to_string());
}
self
}
fn add_warning(self, report: &mut PluginReport) -> Self {
if let Err(e) = &self {
report.add_warning(e.to_string());
}
self
}
fn add_info(self, report: &mut PluginReport) -> Self {
if let Err(e) = &self {
report.add_info(e.to_string());
}
self
}
}