use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct PluginAdminSection {
pub method_prefix: String,
pub broker_topic_prefix: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeout_seconds: Option<u64>,
}
impl PluginAdminSection {
pub fn validate(&self) -> Result<(), String> {
if !self.method_prefix.starts_with("nexo/admin/") {
return Err(format!(
"method_prefix must start with `nexo/admin/`; got `{}`",
self.method_prefix
));
}
if !self.method_prefix.ends_with('/') {
return Err(format!(
"method_prefix must end with `/`; got `{}`",
self.method_prefix
));
}
if self.method_prefix == "nexo/admin/" {
return Err(
"method_prefix `nexo/admin/` is the root namespace; declare a sub-prefix".into(),
);
}
if self.broker_topic_prefix.is_empty() {
return Err("broker_topic_prefix cannot be empty".into());
}
if self.broker_topic_prefix.contains(' ') {
return Err("broker_topic_prefix cannot contain spaces".into());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validate_accepts_typical_prefix() {
let s = PluginAdminSection {
method_prefix: "nexo/admin/whatsapp/".into(),
broker_topic_prefix: "plugin.whatsapp.admin".into(),
timeout_seconds: None,
};
assert!(s.validate().is_ok());
}
#[test]
fn validate_rejects_missing_admin_anchor() {
let s = PluginAdminSection {
method_prefix: "/whatsapp/".into(),
broker_topic_prefix: "plugin.whatsapp".into(),
timeout_seconds: None,
};
assert!(s.validate().is_err());
}
#[test]
fn validate_rejects_missing_trailing_slash() {
let s = PluginAdminSection {
method_prefix: "nexo/admin/whatsapp".into(),
broker_topic_prefix: "plugin.whatsapp".into(),
timeout_seconds: None,
};
assert!(s.validate().is_err());
}
#[test]
fn validate_rejects_root_namespace() {
let s = PluginAdminSection {
method_prefix: "nexo/admin/".into(),
broker_topic_prefix: "plugin.foo".into(),
timeout_seconds: None,
};
assert!(s.validate().is_err());
}
#[test]
fn validate_rejects_empty_broker_topic() {
let s = PluginAdminSection {
method_prefix: "nexo/admin/whatsapp/".into(),
broker_topic_prefix: String::new(),
timeout_seconds: None,
};
assert!(s.validate().is_err());
}
#[test]
fn deserializes_minimal_toml() {
let toml = r#"
method_prefix = "nexo/admin/whatsapp/"
broker_topic_prefix = "plugin.whatsapp.admin"
"#;
let s: PluginAdminSection = toml::from_str(toml).expect("parse");
assert_eq!(s.method_prefix, "nexo/admin/whatsapp/");
assert_eq!(s.broker_topic_prefix, "plugin.whatsapp.admin");
}
}