#![allow(missing_docs)]
use crate::client::*;
pub use crate::error::*;
pub use crate::state::*;
use serde::de::{self, DeserializeOwned};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
use std::collections::HashMap;
use std::fmt::{self, Debug};
use std::iter::FromIterator;
use std::sync::Arc;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ConfigObjectMap<T: ConfigObject> {
objects: HashMap<String, Arc<T>>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ConfigRefMap<T: ConfigRef> {
pub objects: HashMap<String, Arc<T>>,
}
pub trait CreateFromJson: DeserializeOwned {
fn from_json(json: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(json)
}
}
pub trait Builder {
type ConfigObject;
fn build(self) -> Result<Self::ConfigObject, OpsviewConfigError>
where
Self: Sized;
fn new() -> Self
where
Self: Sized;
fn name(self, name: &str) -> Self
where
Self: Sized;
}
pub trait ConfigObject:
Clone
+ Debug
+ Default
+ for<'a> Deserialize<'a>
+ DeserializeOwned
+ Eq
+ PartialEq
+ Serialize
+ Sized
{
type Builder: Builder<ConfigObject = Self>;
fn config_path() -> Option<String> {
None
}
fn unique_name(&self) -> String;
fn builder() -> Self::Builder;
fn minimal(name: &str) -> Result<Self, OpsviewConfigError> {
Self::builder().name(name).build()
}
}
pub trait ConfigRef:
Clone
+ Debug
+ Default
+ for<'a> Deserialize<'a>
+ DeserializeOwned
+ Eq
+ PartialEq
+ Serialize
+ Sized
{
type FullObject: Persistent;
fn name(&self) -> String;
fn ref_(&self) -> Option<String>;
fn unique_name(&self) -> String;
}
#[allow(async_fn_in_trait)]
pub trait Persistent: ConfigObject {
fn id(&self) -> Option<u64>;
fn ref_(&self) -> Option<String>;
fn name(&self) -> Option<String>;
fn clear_readonly(&mut self);
fn name_regex(&self) -> Option<String>;
fn validated_name(&self, name: &str) -> Result<String, OpsviewConfigError>;
fn set_name(&mut self, new_name: &str) -> Result<String, OpsviewConfigError>;
fn clone_new_name(original: &Self, new_name: &str) -> Result<Self, OpsviewConfigError> {
let mut cloned_obj = original.clone();
cloned_obj.clear_readonly();
cloned_obj.set_name(new_name)?;
Ok(cloned_obj)
}
async fn exists(&self, client: &OpsviewClient) -> Result<bool, OpsviewClientError> {
client.object_exists::<Self>(self).await
}
async fn fetch(
&self,
client: &OpsviewClient,
params: Option<Params>,
) -> Result<Self, OpsviewClientError> {
client.get_object_config::<Self>(self, params).await
}
async fn remove(&self, client: &OpsviewClient) -> Result<Value, OpsviewClientError> {
client.delete_object_config::<Self>(self).await
}
async fn create(&self, client: &OpsviewClient) -> Result<Value, OpsviewClientError> {
client.post_new_object_config::<Self>(self).await
}
async fn update(&self, client: &OpsviewClient) -> Result<Value, OpsviewClientError> {
client.put_object_config::<Self>(self).await
}
}
#[allow(async_fn_in_trait)]
pub trait PersistentMap: Serialize + Sized {
fn config_path() -> Option<String> {
None
}
async fn create_all(&self, client: &OpsviewClient) -> Result<Value, OpsviewClientError> {
client.post_new_object_config_map::<Self>(self).await
}
}
impl<T: ConfigObject + Clone> ConfigObjectMap<T> {
pub fn iter_cloned(&self) -> impl Iterator<Item = T> + '_ {
self.objects.values().map(|arc| (**arc).clone())
}
}
impl<T: ConfigObject> FromIterator<T> for ConfigObjectMap<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut map = ConfigObjectMap::new();
for item in iter {
map.add(item);
}
map
}
}
impl<T: ConfigObject> ConfigObjectMap<T> {
pub fn new() -> Self {
ConfigObjectMap {
objects: HashMap::new(),
}
}
pub fn add(&mut self, object: T) {
self.objects.insert(object.unique_name(), Arc::new(object));
}
pub fn add_ref(&mut self, object: Arc<T>) {
self.objects.insert(object.unique_name(), object);
}
pub fn as_vec(&self) -> Vec<Arc<T>> {
self.objects.values().cloned().collect()
}
pub fn contains(&self, key: &str) -> bool {
self.objects.contains_key(key)
}
pub fn get(&self, key: &str) -> Option<Arc<T>> {
self.objects.get(key).cloned()
}
pub fn insert(&mut self, key: String, object: Arc<T>) {
self.objects.insert(key, object);
}
pub fn is_empty(&self) -> bool {
self.objects.is_empty()
}
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, Arc<T>> {
self.objects.iter()
}
pub fn keys(&self) -> std::collections::hash_map::Keys<'_, String, Arc<T>> {
self.objects.keys()
}
pub fn len(&self) -> usize {
self.objects.len()
}
pub fn remove(&mut self, name: &str) -> Option<Arc<T>> {
self.objects.remove(name)
}
pub fn values(&self) -> impl Iterator<Item = &Arc<T>> {
self.objects.values()
}
pub fn drain(&mut self) -> std::collections::hash_map::Drain<'_, String, Arc<T>> {
self.objects.drain()
}
pub fn extend(&mut self, other: &mut Self) {
self.objects.extend(other.drain());
}
}
impl<T: ConfigObject> Serialize for ConfigObjectMap<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let objects: Vec<&T> = self.objects.values().map(|arc_obj| &**arc_obj).collect();
objects.serialize(serializer)
}
}
impl<'de, T: ConfigObject> Deserialize<'de> for ConfigObjectMap<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<T> = Vec::deserialize(deserializer)?;
let mut objects = HashMap::new();
for obj in vec {
let name = obj.unique_name().clone();
if objects.contains_key(&name) {
return Err(serde::de::Error::custom(format!(
"Duplicate name detected: {}",
name
)));
}
objects.insert(name, Arc::new(obj));
}
Ok(ConfigObjectMap { objects })
}
}
impl<T: ConfigRef + Clone> ConfigRefMap<T> {
pub fn iter_cloned(&self) -> impl Iterator<Item = T> + '_ {
self.objects.values().map(|arc| (**arc).clone())
}
}
impl<T: ConfigRef> FromIterator<T> for ConfigRefMap<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut map = ConfigRefMap::new();
for item in iter {
map.add(item);
}
map
}
}
impl<T: ConfigRef> ConfigRefMap<T> {
pub fn new() -> Self {
ConfigRefMap {
objects: HashMap::new(),
}
}
pub fn add(&mut self, object: T) {
self.objects.insert(object.unique_name(), Arc::new(object));
}
pub fn add_ref(&mut self, object: Arc<T>) {
self.objects.insert(object.unique_name(), object);
}
pub fn as_vec(&self) -> Vec<Arc<T>> {
self.objects.values().cloned().collect()
}
pub fn contains(&self, key: &str) -> bool {
self.objects.contains_key(key)
}
pub fn get(&self, key: &str) -> Option<Arc<T>> {
self.objects.get(key).cloned()
}
pub fn is_empty(&self) -> bool {
self.objects.is_empty()
}
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, Arc<T>> {
self.objects.iter()
}
pub fn keys(&self) -> std::collections::hash_map::Keys<'_, String, Arc<T>> {
self.objects.keys()
}
pub fn len(&self) -> usize {
self.objects.len()
}
pub fn remove(&mut self, name: &str) -> Option<Arc<T>> {
self.objects.remove(name)
}
pub fn values(&self) -> impl Iterator<Item = &Arc<T>> {
self.objects.values()
}
}
impl<T: ConfigRef> Serialize for ConfigRefMap<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let objects: Vec<&T> = self.objects.values().map(|arc_obj| &**arc_obj).collect();
objects.serialize(serializer)
}
}
impl<'de, T: ConfigRef> Deserialize<'de> for ConfigRefMap<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<T> = Vec::deserialize(deserializer)?;
let mut objects = HashMap::new();
for obj in vec {
let name = obj.unique_name().clone();
if objects.contains_key(&name) {
return Err(serde::de::Error::custom(format!(
"Duplicate name detected: {}",
name
)));
}
objects.insert(name, Arc::new(obj));
}
Ok(ConfigRefMap { objects })
}
}
pub fn deserialize_readonly<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: Deserialize<'de>,
{
let value = Deserialize::deserialize(deserializer)?;
Ok(Some(value))
}
pub fn deserialize_string_or_number_to_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(StringOrNumberVisitor)
}
struct StringOrNumberVisitor;
impl<'de> serde::de::Visitor<'de> for StringOrNumberVisitor {
type Value = Option<u64>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string or a number, or null")
}
fn visit_some<D>(self, deserializer: D) -> Result<Option<u64>, D::Error>
where
D: Deserializer<'de>,
{
deserializer
.deserialize_any(StringOrNumberValueVisitor)
.map(Some)
}
fn visit_none<E>(self) -> Result<Option<u64>, E> {
Ok(None)
}
}
struct StringOrNumberValueVisitor;
impl<'de> serde::de::Visitor<'de> for StringOrNumberValueVisitor {
type Value = u64;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string or a number")
}
fn visit_u64<E>(self, value: u64) -> Result<u64, E> {
Ok(value)
}
fn visit_str<E>(self, value: &str) -> Result<u64, E>
where
E: serde::de::Error,
{
value.parse().map_err(serde::de::Error::custom)
}
}
pub fn deserialize_string_or_number_to_option_bool<'de, D>(
deserializer: D,
) -> Result<Option<bool>, D::Error>
where
D: Deserializer<'de>,
{
struct StringOrNumberVisitor;
impl<'de> serde::de::Visitor<'de> for StringOrNumberVisitor {
type Value = Option<bool>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string or a number, either '0' or '1'")
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match value {
0 => Ok(Some(false)),
1 => Ok(Some(true)),
_ => Err(serde::de::Error::custom(format!(
"Invalid int value '{}' for boolean field",
value
))),
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match value {
"" => Ok(None),
"0" => Ok(Some(false)),
"1" => Ok(Some(true)),
"yes" => Ok(Some(true)),
"no" => Ok(Some(false)),
"true" => Ok(Some(true)),
"false" => Ok(Some(false)),
_ => Err(serde::de::Error::custom(format!(
"Invalid str value '{}' for boolean field",
value
))),
}
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(None)
}
fn visit_none<E>(self) -> Result<Self::Value, E> {
Ok(None)
}
}
deserializer.deserialize_any(StringOrNumberVisitor)
}
pub fn serialize_option_bool_as_string<S>(
value: &Option<bool>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let str_value = match value {
Some(true) => "1",
Some(false) => "0",
None => return serializer.serialize_none(),
};
serializer.serialize_str(str_value)
}
pub fn ref_map_from<T, U>(config_obj_map: &ConfigObjectMap<T>) -> ConfigRefMap<U>
where
T: ConfigObject,
U: ConfigRef<FullObject = T> + From<Arc<T>>,
{
let mut ref_map = ConfigRefMap::new();
for arc_object in config_obj_map.values() {
let config_ref = U::from(Arc::clone(arc_object));
ref_map.add(config_ref);
}
ref_map
}