forked from mirrors/relay
Add healthcheck for db, new clippy lints
This commit is contained in:
parent
96547230bc
commit
f9cad61049
13 changed files with 78 additions and 46 deletions
|
@ -5,7 +5,7 @@ fn git_info() {
|
|||
if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
|
||||
if output.status.success() {
|
||||
let git_hash = String::from_utf8_lossy(&output.stdout);
|
||||
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
||||
println!("cargo:rustc-env=GIT_HASH={git_hash}");
|
||||
println!("cargo:rustc-env=GIT_SHORT_HASH={}", &git_hash[..8])
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ fn git_info() {
|
|||
{
|
||||
if output.status.success() {
|
||||
let git_branch = String::from_utf8_lossy(&output.stdout);
|
||||
println!("cargo:rustc-env=GIT_BRANCH={}", git_branch);
|
||||
println!("cargo:rustc-env=GIT_BRANCH={git_branch}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ fn version_info() -> Result<(), anyhow::Error> {
|
|||
let data: toml::Value = toml::from_str(&cargo_data)?;
|
||||
|
||||
if let Some(version) = data["package"]["version"].as_str() {
|
||||
println!("cargo:rustc-env=PKG_VERSION={}", version);
|
||||
println!("cargo:rustc-env=PKG_VERSION={version}");
|
||||
}
|
||||
|
||||
if let Some(name) = data["package"]["name"].as_str() {
|
||||
println!("cargo:rustc-env=PKG_NAME={}", name);
|
||||
println!("cargo:rustc-env=PKG_NAME={name}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -40,11 +40,11 @@ impl std::fmt::Display for Counter {
|
|||
let labels = self
|
||||
.labels
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, v))
|
||||
.map(|(k, v)| format!("{k}: {v}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
write!(f, "{} - {}", labels, self.value)
|
||||
write!(f, "{labels} - {}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,11 +59,11 @@ impl std::fmt::Display for Gauge {
|
|||
let labels = self
|
||||
.labels
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, v))
|
||||
.map(|(k, v)| format!("{k}: {v}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
write!(f, "{} - {}", labels, self.value)
|
||||
write!(f, "{labels} - {}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ impl std::fmt::Display for Histogram {
|
|||
let labels = self
|
||||
.labels
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}: {}", k, v))
|
||||
.map(|(k, v)| format!("{k}: {v}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
|
@ -87,15 +87,15 @@ impl std::fmt::Display for Histogram {
|
|||
.iter()
|
||||
.map(|(k, v)| {
|
||||
if let Some(v) = v {
|
||||
format!("{}: {:.6}", k, v)
|
||||
format!("{k}: {v:.6}")
|
||||
} else {
|
||||
format!("{}: None,", k)
|
||||
format!("{k}: None,")
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
write!(f, "{} - {}", labels, value)
|
||||
write!(f, "{labels} - {value}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,18 +172,18 @@ impl Snapshot {
|
|||
continue;
|
||||
}
|
||||
|
||||
println!("\t{}", key);
|
||||
println!("\t{key}");
|
||||
for counter in counters {
|
||||
println!("\t\t{}", counter);
|
||||
println!("\t\t{counter}");
|
||||
}
|
||||
}
|
||||
|
||||
for (key, counters) in merging {
|
||||
println!("\t{}", key);
|
||||
println!("\t{key}");
|
||||
|
||||
for (_, counter) in counters {
|
||||
if let Some(counter) = counter.merge() {
|
||||
println!("\t\t{}", counter);
|
||||
println!("\t\t{counter}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,10 +192,10 @@ impl Snapshot {
|
|||
if !self.gauges.is_empty() {
|
||||
println!("Gauges");
|
||||
for (key, gauges) in self.gauges {
|
||||
println!("\t{}", key);
|
||||
println!("\t{key}");
|
||||
|
||||
for gauge in gauges {
|
||||
println!("\t\t{}", gauge);
|
||||
println!("\t\t{gauge}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,10 +203,10 @@ impl Snapshot {
|
|||
if !self.histograms.is_empty() {
|
||||
println!("Histograms");
|
||||
for (key, histograms) in self.histograms {
|
||||
println!("\t{}", key);
|
||||
println!("\t{key}");
|
||||
|
||||
for histogram in histograms {
|
||||
println!("\t\t{}", histogram);
|
||||
println!("\t\t{histogram}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ impl Config {
|
|||
let config: ParsedConfig = config.try_deserialize()?;
|
||||
|
||||
let scheme = if config.https { "https" } else { "http" };
|
||||
let base_uri = iri!(format!("{}://{}", scheme, config.hostname)).into_absolute();
|
||||
let base_uri = iri!(format!("{scheme}://{}", config.hostname)).into_absolute();
|
||||
|
||||
let tls = match (config.tls_key, config.tls_cert) {
|
||||
(Some(key), Some(cert)) => Some(TlsConfig { key, cert }),
|
||||
|
@ -207,8 +207,8 @@ impl Config {
|
|||
|
||||
let source_url = match Self::git_hash() {
|
||||
Some(hash) => format!(
|
||||
"{}{}{}",
|
||||
config.source_repo, config.repository_commit_base, hash
|
||||
"{}{}{hash}",
|
||||
config.source_repo, config.repository_commit_base
|
||||
)
|
||||
.parse()
|
||||
.expect("constructed source URL is valid"),
|
||||
|
@ -332,7 +332,7 @@ impl Config {
|
|||
match AdminConfig::build(api_token) {
|
||||
Ok(conf) => Some(actix_web::web::Data::new(conf)),
|
||||
Err(e) => {
|
||||
tracing::error!("Error creating admin config: {}", e);
|
||||
tracing::error!("Error creating admin config: {e}");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ impl Config {
|
|||
|
||||
pub(crate) fn software_version() -> String {
|
||||
if let Some(git) = Self::git_version() {
|
||||
return format!("v{}-{}", Self::version(), git);
|
||||
return format!("v{}-{git}", Self::version());
|
||||
}
|
||||
|
||||
format!("v{}", Self::version())
|
||||
|
@ -381,7 +381,7 @@ impl Config {
|
|||
let branch = Self::git_branch()?;
|
||||
let hash = Self::git_short_hash()?;
|
||||
|
||||
Some(format!("{}-{}", branch, hash))
|
||||
Some(format!("{branch}-{hash}"))
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
|
@ -463,7 +463,7 @@ impl Config {
|
|||
resolved
|
||||
}
|
||||
UrlKind::Media(uuid) => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||
.resolve(IriRelativeStr::new(&format!("media/{}", uuid))?.as_ref())
|
||||
.resolve(IriRelativeStr::new(&format!("media/{uuid}"))?.as_ref())
|
||||
.try_to_dedicated_string()?,
|
||||
UrlKind::NodeInfo => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||
.resolve(IriRelativeStr::new("nodeinfo/2.0.json")?.as_ref())
|
||||
|
|
|
@ -182,7 +182,7 @@ impl Node {
|
|||
let authority = url.authority_str().ok_or(ErrorKind::MissingDomain)?;
|
||||
let scheme = url.scheme_str();
|
||||
|
||||
let base = iri!(format!("{}://{}", scheme, authority));
|
||||
let base = iri!(format!("{scheme}://{authority}"));
|
||||
|
||||
Ok(Node {
|
||||
base,
|
||||
|
|
30
src/db.rs
30
src/db.rs
|
@ -10,7 +10,10 @@ use rsa::{
|
|||
use sled::{Batch, Tree};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
sync::Arc,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::SystemTime,
|
||||
};
|
||||
use time::OffsetDateTime;
|
||||
|
@ -22,6 +25,8 @@ pub(crate) struct Db {
|
|||
}
|
||||
|
||||
struct Inner {
|
||||
healthz: Tree,
|
||||
healthz_counter: Arc<AtomicU64>,
|
||||
actor_id_actor: Tree,
|
||||
public_key_id_actor_id: Tree,
|
||||
connected_actor_ids: Tree,
|
||||
|
@ -242,6 +247,8 @@ impl Db {
|
|||
fn build_inner(restricted_mode: bool, db: sled::Db) -> Result<Self, Error> {
|
||||
Ok(Db {
|
||||
inner: Arc::new(Inner {
|
||||
healthz: db.open_tree("healthz")?,
|
||||
healthz_counter: Arc::new(AtomicU64::new(0)),
|
||||
actor_id_actor: db.open_tree("actor-id-actor")?,
|
||||
public_key_id_actor_id: db.open_tree("public-key-id-actor-id")?,
|
||||
connected_actor_ids: db.open_tree("connected-actor-ids")?,
|
||||
|
@ -273,6 +280,21 @@ impl Db {
|
|||
Ok(t)
|
||||
}
|
||||
|
||||
pub(crate) async fn check_health(&self) -> Result<(), Error> {
|
||||
let next = self.inner.healthz_counter.fetch_add(1, Ordering::Relaxed);
|
||||
self.unblock(move |inner| {
|
||||
inner
|
||||
.healthz
|
||||
.insert("healthz", &next.to_be_bytes()[..])
|
||||
.map_err(Error::from)
|
||||
})
|
||||
.await?;
|
||||
self.inner.healthz.flush_async().await?;
|
||||
self.unblock(move |inner| inner.healthz.get("healthz").map_err(Error::from))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn mark_last_seen(
|
||||
&self,
|
||||
nodes: HashMap<String, OffsetDateTime>,
|
||||
|
@ -468,7 +490,7 @@ impl Db {
|
|||
pub(crate) async fn is_connected(&self, base_id: IriString) -> Result<bool, Error> {
|
||||
let scheme = base_id.scheme_str();
|
||||
let authority = base_id.authority_str().ok_or(ErrorKind::MissingDomain)?;
|
||||
let prefix = format!("{}://{}", scheme, authority);
|
||||
let prefix = format!("{scheme}://{authority}");
|
||||
|
||||
self.unblock(move |inner| {
|
||||
let connected = inner
|
||||
|
@ -528,7 +550,7 @@ impl Db {
|
|||
}
|
||||
|
||||
pub(crate) async fn remove_connection(&self, actor_id: IriString) -> Result<(), Error> {
|
||||
tracing::debug!("Removing Connection: {}", actor_id);
|
||||
tracing::debug!("Removing Connection: {actor_id}");
|
||||
self.unblock(move |inner| {
|
||||
inner
|
||||
.connected_actor_ids
|
||||
|
@ -540,7 +562,7 @@ impl Db {
|
|||
}
|
||||
|
||||
pub(crate) async fn add_connection(&self, actor_id: IriString) -> Result<(), Error> {
|
||||
tracing::debug!("Adding Connection: {}", actor_id);
|
||||
tracing::debug!("Adding Connection: {actor_id}");
|
||||
self.unblock(move |inner| {
|
||||
inner
|
||||
.connected_actor_ids
|
||||
|
|
|
@ -45,7 +45,7 @@ impl QueryInstance {
|
|||
.authority_str()
|
||||
.ok_or(ErrorKind::MissingDomain)?;
|
||||
let scheme = self.actor_id.scheme_str();
|
||||
let instance_uri = iri!(format!("{}://{}/api/v1/instance", scheme, authority));
|
||||
let instance_uri = iri!(format!("{scheme}://{authority}/api/v1/instance"));
|
||||
|
||||
let instance = match state
|
||||
.requests
|
||||
|
|
|
@ -39,7 +39,7 @@ impl QueryNodeinfo {
|
|||
.authority_str()
|
||||
.ok_or(ErrorKind::MissingDomain)?;
|
||||
let scheme = self.actor_id.scheme_str();
|
||||
let well_known_uri = iri!(format!("{}://{}/.well-known/nodeinfo", scheme, authority));
|
||||
let well_known_uri = iri!(format!("{scheme}://{authority}/.well-known/nodeinfo"));
|
||||
|
||||
let well_known = match state
|
||||
.requests
|
||||
|
@ -168,7 +168,7 @@ impl<'de> serde::de::Visitor<'de> for SupportedVersionVisitor {
|
|||
type Value = SupportedVersion;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "a string starting with '{}'", SUPPORTED_VERSIONS)
|
||||
write!(f, "a string starting with '{SUPPORTED_VERSIONS}'")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
|
@ -187,7 +187,7 @@ impl<'de> serde::de::Visitor<'de> for SupportedNodeinfoVisitor {
|
|||
type Value = SupportedNodeinfo;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "a string starting with '{}'", SUPPORTED_NODEINFO)
|
||||
write!(f, "a string starting with '{SUPPORTED_NODEINFO}'")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
|
|
|
@ -39,7 +39,7 @@ use self::{
|
|||
db::Db,
|
||||
jobs::create_workers,
|
||||
middleware::{DebugPayload, MyVerify, RelayResolver, Timings},
|
||||
routes::{actor, inbox, index, nodeinfo, nodeinfo_meta, statics},
|
||||
routes::{actor, healthz, inbox, index, nodeinfo, nodeinfo_meta, statics},
|
||||
};
|
||||
|
||||
fn init_subscriber(
|
||||
|
@ -273,6 +273,7 @@ async fn do_server_main(
|
|||
app.wrap(Compress::default())
|
||||
.wrap(TracingLogger::default())
|
||||
.wrap(Timings)
|
||||
.route("/healthz", web::get().to(healthz))
|
||||
.service(web::resource("/").route(web::get().to(index)))
|
||||
.service(web::resource("/media/{path}").route(web::get().to(routes::media)))
|
||||
.service(
|
||||
|
|
|
@ -75,7 +75,7 @@ impl MyVerify {
|
|||
Ok(res) => res.actor_id().ok_or(ErrorKind::MissingId),
|
||||
Err(e) => {
|
||||
if e.is_gone() {
|
||||
tracing::warn!("Actor gone: {}", public_key_id);
|
||||
tracing::warn!("Actor gone: {public_key_id}");
|
||||
return Ok(false);
|
||||
} else {
|
||||
return Err(e);
|
||||
|
@ -178,13 +178,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn handles_masto_keys() {
|
||||
println!("{}", ASONIX_DOG_KEY);
|
||||
println!("{ASONIX_DOG_KEY}");
|
||||
let _ = RsaPublicKey::from_public_key_pem(ASONIX_DOG_KEY.trim()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handles_pleromo_keys() {
|
||||
println!("{}", KARJALAZET_KEY);
|
||||
println!("{KARJALAZET_KEY}");
|
||||
let _ = RsaPublicKey::from_public_key_pem(KARJALAZET_KEY.trim()).unwrap();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ impl Breakers {
|
|||
if let Some(mut breaker) = self.inner.get_mut(authority) {
|
||||
breaker.fail();
|
||||
if !breaker.should_try() {
|
||||
tracing::warn!("Failed breaker for {}", authority);
|
||||
tracing::warn!("Failed breaker for {authority}");
|
||||
}
|
||||
false
|
||||
} else {
|
||||
|
@ -235,7 +235,7 @@ impl Requests {
|
|||
if let Ok(bytes) = res.body().await {
|
||||
if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) {
|
||||
if !s.is_empty() {
|
||||
tracing::warn!("Response from {}, {}", parsed_url, s);
|
||||
tracing::warn!("Response from {parsed_url}, {s}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod actor;
|
||||
mod healthz;
|
||||
mod inbox;
|
||||
mod index;
|
||||
mod media;
|
||||
|
@ -7,6 +8,7 @@ mod statics;
|
|||
|
||||
pub(crate) use self::{
|
||||
actor::route as actor,
|
||||
healthz::route as healthz,
|
||||
inbox::route as inbox,
|
||||
index::route as index,
|
||||
media::route as media,
|
||||
|
|
7
src/routes/healthz.rs
Normal file
7
src/routes/healthz.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
use crate::{data::State, error::Error};
|
||||
use actix_web::{web, HttpResponse};
|
||||
|
||||
pub(crate) async fn route(state: web::Data<State>) -> Result<HttpResponse, Error> {
|
||||
state.db.check_health().await?;
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
|
@ -89,19 +89,19 @@ async fn answer(bot: Bot, msg: Message, cmd: Command, db: Db) -> ResponseResult<
|
|||
.await?;
|
||||
}
|
||||
Command::Block { domain } if db.add_blocks(vec![domain.clone()]).await.is_ok() => {
|
||||
bot.send_message(msg.chat.id, format!("{} has been blocked", domain))
|
||||
bot.send_message(msg.chat.id, format!("{domain} has been blocked"))
|
||||
.await?;
|
||||
}
|
||||
Command::Unblock { domain } if db.remove_blocks(vec![domain.clone()]).await.is_ok() => {
|
||||
bot.send_message(msg.chat.id, format!("{} has been unblocked", domain))
|
||||
bot.send_message(msg.chat.id, format!("{domain} has been unblocked"))
|
||||
.await?;
|
||||
}
|
||||
Command::Allow { domain } if db.add_allows(vec![domain.clone()]).await.is_ok() => {
|
||||
bot.send_message(msg.chat.id, format!("{} has been allowed", domain))
|
||||
bot.send_message(msg.chat.id, format!("{domain} has been allowed"))
|
||||
.await?;
|
||||
}
|
||||
Command::Disallow { domain } if db.remove_allows(vec![domain.clone()]).await.is_ok() => {
|
||||
bot.send_message(msg.chat.id, format!("{} has been disallowed", domain))
|
||||
bot.send_message(msg.chat.id, format!("{domain} has been disallowed"))
|
||||
.await?;
|
||||
}
|
||||
Command::ListAllowed => {
|
||||
|
|
Loading…
Reference in a new issue