cargo fmt

This commit is contained in:
Vincent Stuyck 2025-12-20 01:59:51 +01:00
parent 91be1f0acb
commit ebc349de64
5 changed files with 97 additions and 109 deletions

View File

@ -34,7 +34,6 @@ pub struct FolderAttributes {
/// Additional attributes that can be used to categorize hosts. every tag is part of a tag_group
/// NOTE that checkmk always returns taggroups prefixed with "tag_"
pub tags: HashMap<String, String>,
// TODO: to be implemented
// #[serde(flatten, default)]
// pub networkscan: NetworkScan,
@ -116,16 +115,11 @@ pub struct FolderCreationRequest {
pub name: String,
pub title: String,
pub parent: String,
pub attributes: FolderAttributes
pub attributes: FolderAttributes,
}
impl FolderCreationRequest {
pub fn new(
name: String,
title: String,
parent: String,
attributes: FolderAttributes
) -> Self {
pub fn new(name: String, title: String, parent: String, attributes: FolderAttributes) -> Self {
Self {
name,
title,
@ -154,7 +148,7 @@ impl FolderUpdateRequest {
title,
attributes: Some(attributes),
update_attributes: None,
remove_attributes: None
remove_attributes: None,
}
}
pub fn update(title: String, attributes: FolderAttributes) -> Self {
@ -162,7 +156,7 @@ impl FolderUpdateRequest {
title,
attributes: None,
update_attributes: Some(attributes),
remove_attributes: None
remove_attributes: None,
}
}
pub fn remove(title: String, attributes: FolderAttributes) -> Self {
@ -170,14 +164,14 @@ impl FolderUpdateRequest {
title,
attributes: None,
update_attributes: None,
remove_attributes: Some(attributes)
remove_attributes: Some(attributes),
}
}
}
#[derive(Debug, Serialize)]
pub struct FolderDeleteQuery {
pub delete_mode: FolderDeleteMode
pub delete_mode: FolderDeleteMode,
}
impl FolderDeleteQuery {
@ -190,5 +184,5 @@ impl FolderDeleteQuery {
#[serde(rename_all = "snake_case")]
pub enum FolderDeleteMode {
Recursive,
AbotyOnNonEmpty
AbotyOnNonEmpty,
}

View File

@ -29,7 +29,6 @@ impl fmt::Display for DomainType {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum HttpMethod {

View File

@ -6,5 +6,5 @@ pub struct HostContactGroups {
r#use: bool,
use_for_services: bool,
recuse_use: bool,
recuse_perms: bool
recuse_perms: bool,
}

View File

@ -4,20 +4,22 @@ use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use log::trace;
use reqwest::{Certificate, Request};
use reqwest::header::{HeaderName, HeaderValue};
use reqwest::{Certificate, Request};
use serde::de::DeserializeOwned;
use tokio::sync::Semaphore;
use crate::api::{BulkCreateDomainExtention, BulkDeleteDomainExtention, BulkReadDomainExtention, BulkUpdateDomainExtention, DomainCollection, DomainExtention, DomainObject, DomainType};
use crate::api::{
BulkCreateDomainExtention, BulkDeleteDomainExtention, BulkReadDomainExtention,
BulkUpdateDomainExtention, DomainCollection, DomainExtention, DomainObject, DomainType,
};
use crate::{Error, Result};
pub struct Client(Arc<InnerClient>);
struct InnerClient {
http: reqwest::Client,
url: String,
semaphore: Semaphore
semaphore: Semaphore,
}
#[derive(Default, PartialEq, Eq)]
@ -25,7 +27,8 @@ enum SslStrategy {
NoSll,
IngoreHostname,
IgnoreCertificate,
#[default] Strict
#[default]
Strict,
}
#[derive(Default)]
@ -45,30 +48,40 @@ pub struct ClientBuilder<T> {
resolve: Option<SocketAddr>,
port: u16,
_marker: PhantomData<T>
_marker: PhantomData<T>,
}
impl <T> ClientBuilder<T> {
impl<T> ClientBuilder<T> {
fn new() -> ClientBuilder<RequiresLocation> {
Default::default()
}
}
impl ClientBuilder<RequiresLocation> {
pub fn on_host_and_site(self, hostname: String, sitename: String) -> ClientBuilder<RequiresCredentials> {
pub fn on_host_and_site(
self,
hostname: String,
sitename: String,
) -> ClientBuilder<RequiresCredentials> {
ClientBuilder::<RequiresCredentials> {
hostname, sitename,
hostname,
sitename,
..Default::default()
}
}
}
impl ClientBuilder<RequiresCredentials> {
pub fn with_credentials(self, username: String, password: String) -> ClientBuilder<RequiresNothing> {
pub fn with_credentials(
self,
username: String,
password: String,
) -> ClientBuilder<RequiresNothing> {
ClientBuilder {
hostname: self.hostname,
sitename: self.sitename,
username, password,
username,
password,
..Default::default()
}
}
@ -80,8 +93,10 @@ type ClientBuildResult<T> = std::result::Result<T, ClientBuildError>;
pub enum ClientBuildError {
#[error("failed to build client: {0}")]
BuildClient(#[from] reqwest::Error),
#[error("invalid credentials. thise can only consist of visibly ASCII characters (ie. (32-127))")]
InvalidCredentials(#[from] reqwest::header::InvalidHeaderValue)
#[error(
"invalid credentials. thise can only consist of visibly ASCII characters (ie. (32-127))"
)]
InvalidCredentials(#[from] reqwest::header::InvalidHeaderValue),
}
impl ClientBuilder<RequiresNothing> {
@ -148,7 +163,8 @@ impl ClientBuilder<RequiresNothing> {
builder = builder.add_root_certificate(certificate);
}
builder.build()
builder
.build()
.map_err(ClientBuildError::BuildClient)
.map_err(Error::BuildClient)?
};
@ -157,7 +173,11 @@ impl ClientBuilder<RequiresNothing> {
// not sure if this has been inproved since 2.2
let semaphore = Semaphore::new(10);
Ok(Client(Arc::new(InnerClient { http, url, semaphore })))
Ok(Client(Arc::new(InnerClient {
http,
url,
semaphore,
})))
}
}
@ -166,7 +186,7 @@ impl Client {
Self(Arc::new(InnerClient {
http: client,
semaphore: Semaphore::new(10),
url
url,
}))
}
pub fn builder() -> ClientBuilder<RequiresLocation> {
@ -182,26 +202,27 @@ impl InnerClient {
format!("{}/domain-types/{}/collections/all", self.url, domain_type)
}
pub(crate) fn bulk_action_url(&self, domain_type: DomainType, action: BulkAction) -> String {
format!("{}/domain-types/{}/actions/bulk-{}/invoke",self.url, domain_type, action)
format!(
"{}/domain-types/{}/actions/bulk-{}/invoke",
self.url, domain_type, action
)
}
pub(crate) async fn handle_request(&self, request: Request) -> Result<String> {
trace!("sending {}-request to {}", request.method(), request.url());
let response = self.http
let response = self
.http
.execute(request)
.await
.map_err(Error::SendRequest)?;
let status = response.status();
let body = response.text()
.await
.map_err(Error::ReceiveBody)?;
let body = response.text().await.map_err(Error::ReceiveBody)?;
if status.is_success() {
Ok(body)
} else {
let cmkerror = serde_json::from_str(&body)
.map_err(Error::DeserializeResponse)?;
let cmkerror = serde_json::from_str(&body).map_err(Error::DeserializeResponse)?;
Err(Error::CheckmkError(cmkerror))
}
}
@ -215,22 +236,21 @@ impl InnerClient {
}
pub(crate) async fn get_etag(&self, object_url: &str) -> Result<HeaderValue> {
let mut response = self.http
let mut response = self
.http
.head(object_url)
.send()
.await
.map_err(Error::SendRequest)?;
if response.status().is_success() {
response.headers_mut()
response
.headers_mut()
.remove("ETag")
.ok_or(Error::MissingHeader("ETag"))
} else {
let body = response.text()
.await
.map_err(Error::ReceiveBody)?;
let cmkerror = serde_json::from_str(&body)
.map_err(Error::DeserializeResponse)?;
let body = response.text().await.map_err(Error::ReceiveBody)?;
let cmkerror = serde_json::from_str(&body).map_err(Error::DeserializeResponse)?;
Err(Error::CheckmkError(cmkerror))
}
}
@ -238,9 +258,10 @@ impl InnerClient {
pub(crate) async fn create_domain_object<E: DomainExtention>(
&self,
body: &E::CreationRequest,
query: &E::CreationQuery
query: &E::CreationQuery,
) -> Result<()> {
let request = self.http
let request = self
.http
.post(self.collection_url(E::DOMAIN_TYPE))
.json(body)
.query(query)
@ -252,9 +273,10 @@ impl InnerClient {
pub(crate) async fn read_domain_object<E: DomainExtention>(
&self,
id: impl Display,
query: &E::ReadQuery
query: &E::ReadQuery,
) -> Result<DomainObject<E>> {
let request = self.http
let request = self
.http
.get(self.object_url(E::DOMAIN_TYPE, id))
.query(query)
.build()
@ -269,7 +291,8 @@ impl InnerClient {
) -> Result<()> {
let url = self.object_url(E::DOMAIN_TYPE, id);
let etag = self.get_etag(&url).await?;
let request = self.http
let request = self
.http
.put(url)
.json(&request)
.header(reqwest::header::IF_MATCH, etag)
@ -283,7 +306,8 @@ impl InnerClient {
id: impl Display,
query: &E::DeleteQuery,
) -> Result<()> {
let request = self.http
let request = self
.http
.delete(self.object_url(E::DOMAIN_TYPE, id))
.query(&query)
.build()
@ -295,9 +319,10 @@ impl InnerClient {
pub(crate) async fn bulk_create_domain_objects<E: BulkCreateDomainExtention>(
&self,
request: &[E::CreationRequest],
query: &E::CreationQuery
query: &E::CreationQuery,
) -> Result<()> {
let request = self.http
let request = self
.http
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Create))
.json(request)
.query(query)
@ -310,7 +335,8 @@ impl InnerClient {
&self,
query: &E::ReadQuery,
) -> Result<Vec<DomainObject<E>>> {
let request = self.http
let request = self
.http
.get(self.collection_url(E::DOMAIN_TYPE))
.query(query)
.build()
@ -323,7 +349,8 @@ impl InnerClient {
&self,
body: &[E::BulkUpdateRequest],
) -> Result<()> {
let request = self.http
let request = self
.http
.put(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Update))
.json(body)
.build()
@ -335,7 +362,8 @@ impl InnerClient {
&self,
ids: &[String],
) -> Result<()> {
let request = self.http
let request = self
.http
.post(self.bulk_action_url(E::DOMAIN_TYPE, BulkAction::Delete))
.json(&ids)
.build()
@ -365,48 +393,32 @@ impl Display for BulkAction {
pub struct ApiClient<D: DomainExtention> {
inner: Arc<InnerClient>,
_marker: PhantomData<D>
_marker: PhantomData<D>,
}
impl <D: DomainExtention> ApiClient<D> {
impl<D: DomainExtention> ApiClient<D> {
pub async fn create(
&self,
request: &D::CreationRequest,
query: &D::CreationQuery
query: &D::CreationQuery,
) -> Result<()> {
self.inner.create_domain_object::<D>(request, query).await
}
pub async fn read(
&self,
id: impl Display,
query: &D::ReadQuery
) -> Result<D> {
pub async fn read(&self, id: impl Display, query: &D::ReadQuery) -> Result<D> {
self.inner
.read_domain_object(id, query)
.await
.map(|obj| obj.extensions)
}
pub async fn update(
&self,
id: impl Display,
request: &D::UpdateRequest
) -> Result<()> {
self.inner
.update_domain_object::<D>(id, request)
.await
pub async fn update(&self, id: impl Display, request: &D::UpdateRequest) -> Result<()> {
self.inner.update_domain_object::<D>(id, request).await
}
pub async fn delete(
&self,
id: impl Display,
query: &D::DeleteQuery
) -> Result<()> {
self.inner
.delete_domain_object::<D>(id, query)
.await
pub async fn delete(&self, id: impl Display, query: &D::DeleteQuery) -> Result<()> {
self.inner.delete_domain_object::<D>(id, query).await
}
}
impl <D: BulkCreateDomainExtention> ApiClient<D> {
impl<D: BulkCreateDomainExtention> ApiClient<D> {
pub async fn bulk_create(
&self,
request: &[D::CreationRequest],
@ -418,39 +430,22 @@ impl <D: BulkCreateDomainExtention> ApiClient<D> {
}
}
impl <D: BulkReadDomainExtention> ApiClient<D> {
pub async fn bulk_read(
&self,
query: &D::ReadQuery,
) -> Result<Vec<D>> {
let objs = self.inner
.bulk_read_domain_objects::<D>(query)
.await?;
let exts = objs.into_iter()
.map(|obj| obj.extensions)
.collect();
impl<D: BulkReadDomainExtention> ApiClient<D> {
pub async fn bulk_read(&self, query: &D::ReadQuery) -> Result<Vec<D>> {
let objs = self.inner.bulk_read_domain_objects::<D>(query).await?;
let exts = objs.into_iter().map(|obj| obj.extensions).collect();
Ok(exts)
}
}
impl <D: BulkUpdateDomainExtention> ApiClient<D> {
pub async fn bulk_update(
&self,
request: &[D::BulkUpdateRequest],
) -> Result<()> {
self.inner
.bulk_update_domain_objects::<D>(request)
.await
impl<D: BulkUpdateDomainExtention> ApiClient<D> {
pub async fn bulk_update(&self, request: &[D::BulkUpdateRequest]) -> Result<()> {
self.inner.bulk_update_domain_objects::<D>(request).await
}
}
impl <D: BulkDeleteDomainExtention> ApiClient<D> {
pub async fn bulk_delete(
&self,
ids: &[String],
) -> Result<()> {
self.inner
.bulk_delete_domain_objects::<D>(ids)
.await
impl<D: BulkDeleteDomainExtention> ApiClient<D> {
pub async fn bulk_delete(&self, ids: &[String]) -> Result<()> {
self.inner.bulk_delete_domain_objects::<D>(ids).await
}
}

View File

@ -1,5 +1,5 @@
pub mod api;
mod client;
mod error;
pub mod api;
pub use error::{Error, Result};