mirror of
https://github.com/moghtech/komodo.git
synced 2026-04-27 11:50:24 -05:00
initialize monitor client
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -1439,8 +1439,13 @@ dependencies = [
|
||||
name = "monitor_client"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"envy",
|
||||
"monitor_types",
|
||||
"reqwest",
|
||||
"resolver_api",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -10,3 +10,8 @@ license.workspace = true
|
||||
[dependencies]
|
||||
monitor_types.workspace = true
|
||||
reqwest.workspace = true
|
||||
anyhow.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
resolver_api.workspace = true
|
||||
envy.workspace = true
|
||||
@@ -1,7 +1,23 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use monitor_types::requests::auth::{self, LoginLocalUserResponse, LoginWithSecretResponse};
|
||||
use reqwest::StatusCode;
|
||||
use resolver_api::HasResponse;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct MonitorEnv {
|
||||
monitor_url: String,
|
||||
monitor_token: Option<String>,
|
||||
monitor_username: Option<String>,
|
||||
monitor_password: Option<String>,
|
||||
monitor_secret: Option<String>,
|
||||
}
|
||||
|
||||
pub struct MonitorClient {
|
||||
reqwest: reqwest::Client,
|
||||
address: String,
|
||||
token: String,
|
||||
jwt: String,
|
||||
}
|
||||
|
||||
impl MonitorClient {
|
||||
@@ -9,9 +25,126 @@ impl MonitorClient {
|
||||
MonitorClient {
|
||||
reqwest: Default::default(),
|
||||
address: address.into(),
|
||||
token: token.into(),
|
||||
jwt: token.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_credentials() {}
|
||||
pub async fn new_with_password(
|
||||
address: impl Into<String>,
|
||||
username: impl Into<String>,
|
||||
password: impl Into<String>,
|
||||
) -> anyhow::Result<MonitorClient> {
|
||||
let mut client = MonitorClient {
|
||||
reqwest: Default::default(),
|
||||
address: address.into(),
|
||||
jwt: Default::default(),
|
||||
};
|
||||
|
||||
let LoginLocalUserResponse { jwt } = client
|
||||
.auth(auth::LoginLocalUser {
|
||||
username: username.into(),
|
||||
password: password.into(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
client.jwt = jwt;
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
pub async fn new_with_secret(
|
||||
address: impl Into<String>,
|
||||
username: impl Into<String>,
|
||||
secret: impl Into<String>,
|
||||
) -> anyhow::Result<MonitorClient> {
|
||||
let mut client = MonitorClient {
|
||||
reqwest: Default::default(),
|
||||
address: address.into(),
|
||||
jwt: Default::default(),
|
||||
};
|
||||
|
||||
let LoginWithSecretResponse { jwt } = client
|
||||
.auth(auth::LoginWithSecret {
|
||||
username: username.into(),
|
||||
secret: secret.into(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
client.jwt = jwt;
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
pub async fn new_from_env() -> anyhow::Result<MonitorClient> {
|
||||
let env = envy::from_env::<MonitorEnv>()
|
||||
.context("failed to parse environment for monitor client")?;
|
||||
if let Some(token) = env.monitor_token {
|
||||
Ok(MonitorClient::new_with_token(&env.monitor_url, token))
|
||||
} else if let Some(password) = env.monitor_password {
|
||||
let username = env.monitor_username.ok_or(anyhow!(
|
||||
"must provide MONITOR_USERNAME to authenticate with MONITOR_PASSWORD"
|
||||
))?;
|
||||
MonitorClient::new_with_password(&env.monitor_url, username, password).await
|
||||
} else if let Some(secret) = env.monitor_secret {
|
||||
let username = env.monitor_username.ok_or(anyhow!(
|
||||
"must provide MONITOR_USERNAME to authenticate with MONITOR_SECRET"
|
||||
))?;
|
||||
MonitorClient::new_with_secret(&env.monitor_url, username, secret).await
|
||||
} else {
|
||||
Err(anyhow!("failed to initialize monitor client from env | must provide one of: (MONITOR_TOKEN), (MONITOR_USERNAME and MONITOR_PASSWORD), (MONITOR_USERNAME and MONITOR_SECRET)"))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn api<T: HasResponse>(&self, request: T) -> anyhow::Result<T::Response> {
|
||||
let req_type = T::req_type();
|
||||
self.post(
|
||||
"/api",
|
||||
json!({
|
||||
"type": req_type,
|
||||
"params": request
|
||||
}),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn auth<T: HasResponse>(&self, request: T) -> anyhow::Result<T::Response> {
|
||||
let req_type = T::req_type();
|
||||
self.post(
|
||||
"/auth",
|
||||
json!({
|
||||
"type": req_type,
|
||||
"params": request
|
||||
}),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn post<B: Serialize, R: DeserializeOwned>(
|
||||
&self,
|
||||
endpoint: &str,
|
||||
body: impl Into<Option<B>>,
|
||||
) -> anyhow::Result<R> {
|
||||
let req = self
|
||||
.reqwest
|
||||
.post(format!("{}{endpoint}", self.address))
|
||||
.header("Authorization", format!("Bearer {}", self.jwt));
|
||||
let req = if let Some(body) = body.into() {
|
||||
req.header("Content-Type", "application/json").json(&body)
|
||||
} else {
|
||||
req
|
||||
};
|
||||
let res = req.send().await.context("failed to reach monitor api")?;
|
||||
let status = res.status();
|
||||
if status == StatusCode::OK {
|
||||
match res.json().await {
|
||||
Ok(res) => Ok(res),
|
||||
Err(e) => Err(anyhow!("{status}: {e:#?}")),
|
||||
}
|
||||
} else {
|
||||
match res.text().await {
|
||||
Ok(res) => Err(anyhow!("{status}: {res}")),
|
||||
Err(e) => Err(anyhow!("{status}: {e:#?}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user