mangadex-home-rs/src/ping.rs

141 lines
4.4 KiB
Rust
Raw Normal View History

2021-03-26 02:58:07 +00:00
use std::sync::Arc;
2021-03-26 01:06:54 +00:00
use std::{
num::{NonZeroU16, NonZeroUsize},
2021-03-26 02:58:07 +00:00
sync::atomic::Ordering,
2021-03-26 01:06:54 +00:00
};
2021-03-18 01:45:16 +00:00
2021-03-23 03:19:56 +00:00
use log::{error, info, warn};
2021-03-18 01:45:16 +00:00
use serde::{Deserialize, Serialize};
use sodiumoxide::crypto::box_::PrecomputedKey;
use url::Url;
2021-03-26 02:58:07 +00:00
use crate::config::VALIDATE_TOKENS;
2021-03-22 21:47:56 +00:00
use crate::state::RwLockServerState;
2021-03-26 01:06:54 +00:00
use crate::{client_api_version, config::CliArgs};
2021-03-18 01:45:16 +00:00
2021-03-22 21:47:56 +00:00
pub const CONTROL_CENTER_PING_URL: &str = "https://api.mangadex.network/ping";
#[derive(Serialize, Debug)]
2021-03-18 02:41:48 +00:00
pub struct Request<'a> {
2021-03-18 01:45:16 +00:00
secret: &'a str,
2021-03-26 01:06:54 +00:00
port: NonZeroU16,
2021-03-18 01:45:16 +00:00
disk_space: usize,
2021-03-26 01:06:54 +00:00
network_speed: NonZeroUsize,
2021-03-18 01:45:16 +00:00
build_version: usize,
tls_created_at: Option<String>,
}
2021-03-18 02:41:48 +00:00
impl<'a> Request<'a> {
2021-03-26 01:06:54 +00:00
fn from_config_and_state(
secret: &'a str,
config: &CliArgs,
state: &Arc<RwLockServerState>,
) -> Self {
2021-03-18 01:45:16 +00:00
Self {
2021-03-26 01:06:54 +00:00
secret,
2021-03-18 01:45:16 +00:00
port: config.port,
disk_space: config.disk_quota,
network_speed: config.network_speed,
build_version: client_api_version!().parse().unwrap(),
tls_created_at: Some(state.0.read().tls_config.created_at.clone()),
}
}
}
2021-03-23 00:00:21 +00:00
#[allow(clippy::fallible_impl_from)]
2021-03-26 01:06:54 +00:00
impl<'a> From<(&'a str, &CliArgs)> for Request<'a> {
fn from((secret, config): (&'a str, &CliArgs)) -> Self {
2021-03-18 01:45:16 +00:00
Self {
2021-03-26 01:06:54 +00:00
secret,
2021-03-18 01:45:16 +00:00
port: config.port,
disk_space: config.disk_quota,
network_speed: config.network_speed,
build_version: client_api_version!().parse().unwrap(),
tls_created_at: None,
}
}
}
2021-03-22 21:47:56 +00:00
#[derive(Deserialize, Debug)]
2021-03-18 02:41:48 +00:00
pub struct Response {
pub image_server: Url,
pub latest_build: usize,
pub url: String,
pub token_key: Option<String>,
pub compromised: bool,
pub paused: bool,
2021-03-23 03:04:54 +00:00
#[serde(default)]
2021-03-22 21:47:56 +00:00
pub force_tokens: bool,
2021-03-18 02:41:48 +00:00
pub tls: Option<Tls>,
2021-03-18 01:45:16 +00:00
}
2021-03-22 21:47:56 +00:00
#[derive(Deserialize, Debug)]
2021-03-18 02:41:48 +00:00
pub struct Tls {
2021-03-18 01:45:16 +00:00
pub created_at: String,
2021-03-22 21:47:56 +00:00
pub private_key: String,
pub certificate: String,
2021-03-18 01:45:16 +00:00
}
2021-03-26 01:06:54 +00:00
pub async fn update_server_state(secret: &str, req: &CliArgs, data: &mut Arc<RwLockServerState>) {
let req = Request::from_config_and_state(secret, req, data);
2021-03-22 21:47:56 +00:00
let client = reqwest::Client::new();
let resp = client.post(CONTROL_CENTER_PING_URL).json(&req).send().await;
2021-03-18 01:45:16 +00:00
match resp {
2021-03-22 21:47:56 +00:00
Ok(resp) => match resp.json::<Response>().await {
2021-03-18 01:45:16 +00:00
Ok(resp) => {
let mut write_guard = data.0.write();
write_guard.image_server = resp.image_server;
if let Some(key) = resp.token_key {
2021-03-22 21:47:56 +00:00
if let Some(key) = base64::decode(&key)
.ok()
.and_then(|k| PrecomputedKey::from_slice(&k))
{
write_guard.precomputed_key = key;
} else {
error!("Failed to parse token key: got {}", key);
2021-03-18 01:45:16 +00:00
}
}
2021-03-26 02:58:07 +00:00
if VALIDATE_TOKENS.load(Ordering::Acquire) != resp.force_tokens {
2021-03-23 03:19:56 +00:00
if resp.force_tokens {
info!("Client received command to enforce token validity.");
} else {
info!("Client received command to no longer enforce token validity");
}
2021-03-26 02:58:07 +00:00
VALIDATE_TOKENS.store(resp.force_tokens, Ordering::Release);
2021-03-23 03:19:56 +00:00
}
2021-03-18 01:45:16 +00:00
if let Some(tls) = resp.tls {
write_guard.tls_config = tls;
}
if resp.compromised {
2021-03-23 03:19:56 +00:00
error!("Got compromised response from control center!");
2021-03-18 01:45:16 +00:00
}
2021-03-23 03:19:56 +00:00
if resp.paused != write_guard.log_state.was_paused_before {
write_guard.log_state.was_paused_before = resp.paused;
if resp.paused {
warn!("Control center has paused this node.");
} else {
info!("Control center is no longer pausing this node.");
}
2021-03-18 01:45:16 +00:00
}
if resp.url != write_guard.url {
info!("This client's URL has been updated to {}", resp.url);
}
}
Err(e) => warn!("Got malformed response: {}", e),
},
Err(e) => match e {
2021-03-22 21:47:56 +00:00
e if e.is_timeout() => {
2021-03-18 01:45:16 +00:00
error!("Response timed out to control server. Is MangaDex down?")
}
e => warn!("Failed to send request: {}", e),
},
}
}