mirror of
https://git.asonix.dog/asonix/relay.git
synced 2025-03-12 00:45:38 +00:00
Instrument with tracing
This commit is contained in:
parent
ebba8e3f60
commit
43e5b6d873
725
Cargo.lock
generated
725
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
28
Cargo.toml
28
Cargo.toml
|
@ -15,26 +15,22 @@ build = "src/build.rs"
|
|||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
actix-rt = "2.0.2"
|
||||
actix-web = { version = "4.0.0-beta.7", default-features = false, features = ["compress-brotli", "compress-gzip", "compress-zstd"] }
|
||||
actix-web = { version = "4.0.0-beta.7", default-features = false }
|
||||
actix-webfinger = "0.4.0-beta.3"
|
||||
activitystreams = "0.7.0-alpha.10"
|
||||
activitystreams-ext = "0.1.0-alpha.2"
|
||||
ammonia = "3.1.0"
|
||||
async-mutex = "1.0.1"
|
||||
async-rwlock = "1.3.0"
|
||||
awc = { version = "3.0.0-beta.6", default-features = false, features = ["compress-brotli", "compress-gzip", "compress-zstd", "rustls"] }
|
||||
background-jobs = "0.9.0"
|
||||
awc = { version = "3.0.0-beta.6", default-features = false, features = ["rustls"] }
|
||||
base64 = "0.13"
|
||||
chrono = "0.4.19"
|
||||
config = "0.11.0"
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.9.0"
|
||||
futures = "0.3.12"
|
||||
http-signature-normalization-actix = { version = "0.5.0-beta.6", default-features = false, features = ["sha-2"] }
|
||||
log = "0.4"
|
||||
futures-util = "0.3.17"
|
||||
http-signature-normalization-actix = { version = "0.5.0-beta.7", default-features = false, features = ["sha-2"], git = "https://git.asonix.dog/asonix/http-signature-normalization" }
|
||||
lru = "0.6.0"
|
||||
mime = "0.3.16"
|
||||
pretty_env_logger = "0.4.0"
|
||||
rand = "0.8"
|
||||
rsa = "0.5"
|
||||
rsa-magic-public-key = "0.4.0"
|
||||
|
@ -44,8 +40,24 @@ sha2 = "0.9"
|
|||
sled = "0.34.6"
|
||||
structopt = "0.3.12"
|
||||
thiserror = "1.0"
|
||||
tracing = "0.1"
|
||||
tracing-actix-web = { version = "0.4.0-beta.12", git = "https://github.com/asonix/tracing-actix-web", branch = "asonix/tracing-error-work-around" }
|
||||
tracing-error = "0.1"
|
||||
tracing-futures = "0.2"
|
||||
tracing-log = "0.1"
|
||||
tracing-subscriber = { version = "0.2", features = ["ansi", "fmt"] }
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
|
||||
[dependencies.background-jobs]
|
||||
version = "0.10.0"
|
||||
git = "https://git.asonix.dog/asonix/background-jobs"
|
||||
default-features = false
|
||||
features = [
|
||||
"background-jobs-actix",
|
||||
"error-logging"
|
||||
]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0"
|
||||
dotenv = "0.15.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
data::{ActorCache, State},
|
||||
error::MyError,
|
||||
error::Error,
|
||||
middleware::MyVerify,
|
||||
requests::Requests,
|
||||
};
|
||||
|
@ -20,7 +20,6 @@ pub(crate) struct ParsedConfig {
|
|||
restricted_mode: bool,
|
||||
validate_signatures: bool,
|
||||
https: bool,
|
||||
pretty_log: bool,
|
||||
publish_blocks: bool,
|
||||
sled_path: PathBuf,
|
||||
source_repo: Url,
|
||||
|
@ -34,7 +33,6 @@ pub struct Config {
|
|||
debug: bool,
|
||||
restricted_mode: bool,
|
||||
validate_signatures: bool,
|
||||
pretty_log: bool,
|
||||
publish_blocks: bool,
|
||||
base_uri: Url,
|
||||
sled_path: PathBuf,
|
||||
|
@ -55,7 +53,7 @@ pub enum UrlKind {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
pub(crate) fn build() -> Result<Self, MyError> {
|
||||
pub(crate) fn build() -> Result<Self, Error> {
|
||||
let mut config = config::Config::new();
|
||||
config
|
||||
.set_default("hostname", "localhost:8080")?
|
||||
|
@ -65,7 +63,6 @@ impl Config {
|
|||
.set_default("restricted_mode", false)?
|
||||
.set_default("validate_signatures", false)?
|
||||
.set_default("https", false)?
|
||||
.set_default("pretty_log", true)?
|
||||
.set_default("publish_blocks", false)?
|
||||
.set_default("sled_path", "./sled/db-0-34")?
|
||||
.set_default("source_repo", "https://git.asonix.dog/asonix/relay")?
|
||||
|
@ -83,7 +80,6 @@ impl Config {
|
|||
debug: config.debug,
|
||||
restricted_mode: config.restricted_mode,
|
||||
validate_signatures: config.validate_signatures,
|
||||
pretty_log: config.pretty_log,
|
||||
publish_blocks: config.publish_blocks,
|
||||
base_uri,
|
||||
sled_path: config.sled_path,
|
||||
|
@ -95,10 +91,6 @@ impl Config {
|
|||
&self.sled_path
|
||||
}
|
||||
|
||||
pub(crate) fn pretty_log(&self) -> bool {
|
||||
self.pretty_log
|
||||
}
|
||||
|
||||
pub(crate) fn validate_signatures(&self) -> bool {
|
||||
self.validate_signatures
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
apub::AcceptedActors,
|
||||
db::{Actor, Db},
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
requests::Requests,
|
||||
};
|
||||
use activitystreams::{prelude::*, url::Url};
|
||||
|
@ -30,7 +30,7 @@ impl<T> MaybeCached<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ActorCache {
|
||||
db: Db,
|
||||
}
|
||||
|
@ -40,11 +40,12 @@ impl ActorCache {
|
|||
ActorCache { db }
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Get Actor", skip(requests))]
|
||||
pub(crate) async fn get(
|
||||
&self,
|
||||
id: &Url,
|
||||
requests: &Requests,
|
||||
) -> Result<MaybeCached<Actor>, MyError> {
|
||||
) -> Result<MaybeCached<Actor>, Error> {
|
||||
if let Some(actor) = self.db.actor(id.clone()).await? {
|
||||
if actor.saved_at + REFETCH_DURATION > SystemTime::now() {
|
||||
return Ok(MaybeCached::Cached(actor));
|
||||
|
@ -56,26 +57,25 @@ impl ActorCache {
|
|||
.map(MaybeCached::Fetched)
|
||||
}
|
||||
|
||||
pub(crate) async fn add_connection(&self, actor: Actor) -> Result<(), MyError> {
|
||||
#[tracing::instrument(name = "Add Connection")]
|
||||
pub(crate) async fn add_connection(&self, actor: Actor) -> Result<(), Error> {
|
||||
self.db.add_connection(actor.id.clone()).await?;
|
||||
self.db.save_actor(actor).await
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_connection(&self, actor: &Actor) -> Result<(), MyError> {
|
||||
#[tracing::instrument(name = "Remove Connection")]
|
||||
pub(crate) async fn remove_connection(&self, actor: &Actor) -> Result<(), Error> {
|
||||
self.db.remove_connection(actor.id.clone()).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_no_cache(
|
||||
&self,
|
||||
id: &Url,
|
||||
requests: &Requests,
|
||||
) -> Result<Actor, MyError> {
|
||||
#[tracing::instrument(name = "Fetch remote actor", skip(requests))]
|
||||
pub(crate) async fn get_no_cache(&self, id: &Url, requests: &Requests) -> Result<Actor, Error> {
|
||||
let accepted_actor = requests.fetch::<AcceptedActors>(id.as_str()).await?;
|
||||
|
||||
let input_domain = id.domain().ok_or(MyError::MissingDomain)?;
|
||||
let input_domain = id.domain().ok_or(ErrorKind::MissingDomain)?;
|
||||
let accepted_actor_id = accepted_actor
|
||||
.id(&input_domain)?
|
||||
.ok_or(MyError::MissingId)?;
|
||||
.ok_or(ErrorKind::MissingId)?;
|
||||
|
||||
let inbox = get_inbox(&accepted_actor)?.clone();
|
||||
|
||||
|
@ -93,7 +93,7 @@ impl ActorCache {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_inbox(actor: &AcceptedActors) -> Result<&Url, MyError> {
|
||||
fn get_inbox(actor: &AcceptedActors) -> Result<&Url, Error> {
|
||||
Ok(actor
|
||||
.endpoints()?
|
||||
.and_then(|e| e.shared_inbox)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
db::{Db, MediaMeta},
|
||||
error::MyError,
|
||||
error::Error,
|
||||
};
|
||||
use activitystreams::url::Url;
|
||||
use actix_web::web::Bytes;
|
||||
|
@ -9,7 +9,7 @@ use uuid::Uuid;
|
|||
|
||||
static MEDIA_DURATION: Duration = Duration::from_secs(60 * 60 * 24 * 2);
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MediaCache {
|
||||
db: Db,
|
||||
}
|
||||
|
@ -19,15 +19,18 @@ impl MediaCache {
|
|||
MediaCache { db }
|
||||
}
|
||||
|
||||
pub(crate) async fn get_uuid(&self, url: Url) -> Result<Option<Uuid>, MyError> {
|
||||
#[tracing::instrument(name = "Get media uuid")]
|
||||
pub(crate) async fn get_uuid(&self, url: Url) -> Result<Option<Uuid>, Error> {
|
||||
self.db.media_id(url).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_url(&self, uuid: Uuid) -> Result<Option<Url>, MyError> {
|
||||
#[tracing::instrument(name = "Get media url")]
|
||||
pub(crate) async fn get_url(&self, uuid: Uuid) -> Result<Option<Url>, Error> {
|
||||
self.db.media_url(uuid).await
|
||||
}
|
||||
|
||||
pub(crate) async fn is_outdated(&self, uuid: Uuid) -> Result<bool, MyError> {
|
||||
#[tracing::instrument(name = "Is media outdated")]
|
||||
pub(crate) async fn is_outdated(&self, uuid: Uuid) -> Result<bool, Error> {
|
||||
if let Some(meta) = self.db.media_meta(uuid).await? {
|
||||
if meta.saved_at + MEDIA_DURATION > SystemTime::now() {
|
||||
return Ok(false);
|
||||
|
@ -37,7 +40,8 @@ impl MediaCache {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_bytes(&self, uuid: Uuid) -> Result<Option<(String, Bytes)>, MyError> {
|
||||
#[tracing::instrument(name = "Get media bytes")]
|
||||
pub(crate) async fn get_bytes(&self, uuid: Uuid) -> Result<Option<(String, Bytes)>, Error> {
|
||||
if let Some(meta) = self.db.media_meta(uuid).await? {
|
||||
if meta.saved_at + MEDIA_DURATION > SystemTime::now() {
|
||||
return self
|
||||
|
@ -51,7 +55,8 @@ impl MediaCache {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) async fn store_url(&self, url: Url) -> Result<Uuid, MyError> {
|
||||
#[tracing::instrument(name = "Store media url")]
|
||||
pub(crate) async fn store_url(&self, url: Url) -> Result<Uuid, Error> {
|
||||
let uuid = Uuid::new_v4();
|
||||
|
||||
self.db.save_url(url, uuid).await?;
|
||||
|
@ -59,12 +64,13 @@ impl MediaCache {
|
|||
Ok(uuid)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "store media bytes", skip(bytes))]
|
||||
pub(crate) async fn store_bytes(
|
||||
&self,
|
||||
uuid: Uuid,
|
||||
media_type: String,
|
||||
bytes: Bytes,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
self.db
|
||||
.save_bytes(
|
||||
uuid,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::{
|
||||
db::{Contact, Db, Info, Instance},
|
||||
error::MyError,
|
||||
error::Error,
|
||||
};
|
||||
use activitystreams::url::Url;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NodeCache {
|
||||
db: Db,
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ impl NodeCache {
|
|||
NodeCache { db }
|
||||
}
|
||||
|
||||
pub(crate) async fn nodes(&self) -> Result<Vec<Node>, MyError> {
|
||||
#[tracing::instrument(name = "Get nodes")]
|
||||
pub(crate) async fn nodes(&self) -> Result<Vec<Node>, Error> {
|
||||
let infos = self.db.connected_info().await?;
|
||||
let instances = self.db.connected_instance().await?;
|
||||
let contacts = self.db.connected_contact().await?;
|
||||
|
@ -48,6 +49,7 @@ impl NodeCache {
|
|||
Ok(vec)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Is NodeInfo Outdated")]
|
||||
pub(crate) async fn is_nodeinfo_outdated(&self, actor_id: Url) -> bool {
|
||||
self.db
|
||||
.info(actor_id)
|
||||
|
@ -56,6 +58,7 @@ impl NodeCache {
|
|||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Is Contact Outdated")]
|
||||
pub(crate) async fn is_contact_outdated(&self, actor_id: Url) -> bool {
|
||||
self.db
|
||||
.contact(actor_id)
|
||||
|
@ -64,6 +67,7 @@ impl NodeCache {
|
|||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Is Instance Outdated")]
|
||||
pub(crate) async fn is_instance_outdated(&self, actor_id: Url) -> bool {
|
||||
self.db
|
||||
.instance(actor_id)
|
||||
|
@ -72,13 +76,14 @@ impl NodeCache {
|
|||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Save node info")]
|
||||
pub(crate) async fn set_info(
|
||||
&self,
|
||||
actor_id: Url,
|
||||
software: String,
|
||||
version: String,
|
||||
reg: bool,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
self.db
|
||||
.save_info(
|
||||
actor_id,
|
||||
|
@ -92,6 +97,7 @@ impl NodeCache {
|
|||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Save instance info")]
|
||||
pub(crate) async fn set_instance(
|
||||
&self,
|
||||
actor_id: Url,
|
||||
|
@ -100,7 +106,7 @@ impl NodeCache {
|
|||
version: String,
|
||||
reg: bool,
|
||||
requires_approval: bool,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
self.db
|
||||
.save_instance(
|
||||
actor_id,
|
||||
|
@ -116,6 +122,7 @@ impl NodeCache {
|
|||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Save contact info")]
|
||||
pub(crate) async fn set_contact(
|
||||
&self,
|
||||
actor_id: Url,
|
||||
|
@ -123,7 +130,7 @@ impl NodeCache {
|
|||
display_name: String,
|
||||
url: Url,
|
||||
avatar: Url,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
self.db
|
||||
.save_contact(
|
||||
actor_id,
|
||||
|
|
|
@ -2,17 +2,17 @@ use crate::{
|
|||
config::{Config, UrlKind},
|
||||
data::NodeCache,
|
||||
db::Db,
|
||||
error::MyError,
|
||||
error::Error,
|
||||
requests::{Breakers, Requests},
|
||||
};
|
||||
use activitystreams::url::Url;
|
||||
use actix_web::web;
|
||||
use async_rwlock::RwLock;
|
||||
use log::info;
|
||||
use lru::LruCache;
|
||||
use rand::thread_rng;
|
||||
use rsa::{RsaPrivateKey, RsaPublicKey};
|
||||
use std::sync::Arc;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct State {
|
||||
|
@ -25,6 +25,20 @@ pub struct State {
|
|||
pub(crate) db: Db,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("State")
|
||||
.field("public_key", &"PublicKey")
|
||||
.field("private_key", &"[redacted]")
|
||||
.field("config", &self.config)
|
||||
.field("object_cache", &"Object Cache")
|
||||
.field("node_cache", &self.node_cache)
|
||||
.field("breakers", &self.breakers)
|
||||
.field("db", &self.db)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub(crate) fn node_cache(&self) -> NodeCache {
|
||||
self.node_cache.clone()
|
||||
|
@ -44,11 +58,12 @@ impl State {
|
|||
)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Get inboxes for other domains")]
|
||||
pub(crate) async fn inboxes_without(
|
||||
&self,
|
||||
existing_inbox: &Url,
|
||||
domain: &str,
|
||||
) -> Result<Vec<Url>, MyError> {
|
||||
) -> Result<Vec<Url>, Error> {
|
||||
Ok(self
|
||||
.db
|
||||
.inboxes()
|
||||
|
@ -74,8 +89,10 @@ impl State {
|
|||
self.object_cache.write().await.put(object_id, actor_id);
|
||||
}
|
||||
|
||||
pub(crate) async fn build(config: Config, db: Db) -> Result<Self, MyError> {
|
||||
#[tracing::instrument(name = "Building state")]
|
||||
pub(crate) async fn build(config: Config, db: Db) -> Result<Self, Error> {
|
||||
let private_key = if let Ok(Some(key)) = db.private_key().await {
|
||||
info!("Using existing key");
|
||||
key
|
||||
} else {
|
||||
info!("Generating new keys");
|
||||
|
|
90
src/db.rs
90
src/db.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::{config::Config, error::MyError};
|
||||
use crate::{config::Config, error::Error};
|
||||
use activitystreams::url::Url;
|
||||
use actix_web::web::Bytes;
|
||||
use rsa::{
|
||||
|
@ -9,7 +9,7 @@ use sled::Tree;
|
|||
use std::{collections::HashMap, sync::Arc, time::SystemTime};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Db {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
@ -31,6 +31,14 @@ struct Inner {
|
|||
restricted_mode: bool,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Inner {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Inner")
|
||||
.field("restricted_mode", &self.restricted_mode)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Actor {
|
||||
pub(crate) id: Url,
|
||||
|
@ -194,12 +202,12 @@ impl Inner {
|
|||
}
|
||||
|
||||
impl Db {
|
||||
pub(crate) fn build(config: &Config) -> Result<Self, MyError> {
|
||||
pub(crate) fn build(config: &Config) -> Result<Self, Error> {
|
||||
let db = sled::open(config.sled_path())?;
|
||||
Self::build_inner(config.restricted_mode(), db)
|
||||
}
|
||||
|
||||
fn build_inner(restricted_mode: bool, db: sled::Db) -> Result<Self, MyError> {
|
||||
fn build_inner(restricted_mode: bool, db: sled::Db) -> Result<Self, Error> {
|
||||
Ok(Db {
|
||||
inner: Arc::new(Inner {
|
||||
actor_id_actor: db.open_tree("actor-id-actor")?,
|
||||
|
@ -222,8 +230,8 @@ impl Db {
|
|||
|
||||
async fn unblock<T>(
|
||||
&self,
|
||||
f: impl Fn(&Inner) -> Result<T, MyError> + Send + 'static,
|
||||
) -> Result<T, MyError>
|
||||
f: impl Fn(&Inner) -> Result<T, Error> + Send + 'static,
|
||||
) -> Result<T, Error>
|
||||
where
|
||||
T: Send + 'static,
|
||||
{
|
||||
|
@ -234,11 +242,11 @@ impl Db {
|
|||
Ok(t)
|
||||
}
|
||||
|
||||
pub(crate) async fn connected_ids(&self) -> Result<Vec<Url>, MyError> {
|
||||
pub(crate) async fn connected_ids(&self) -> Result<Vec<Url>, Error> {
|
||||
self.unblock(|inner| Ok(inner.connected().collect())).await
|
||||
}
|
||||
|
||||
pub(crate) async fn save_info(&self, actor_id: Url, info: Info) -> Result<(), MyError> {
|
||||
pub(crate) async fn save_info(&self, actor_id: Url, info: Info) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
let vec = serde_json::to_vec(&info)?;
|
||||
|
||||
|
@ -251,7 +259,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn info(&self, actor_id: Url) -> Result<Option<Info>, MyError> {
|
||||
pub(crate) async fn info(&self, actor_id: Url) -> Result<Option<Info>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.actor_id_info.get(actor_id.as_str().as_bytes())? {
|
||||
let info = serde_json::from_slice(&ivec)?;
|
||||
|
@ -263,7 +271,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn connected_info(&self) -> Result<HashMap<Url, Info>, MyError> {
|
||||
pub(crate) async fn connected_info(&self) -> Result<HashMap<Url, Info>, Error> {
|
||||
self.unblock(|inner| Ok(inner.connected_info().collect()))
|
||||
.await
|
||||
}
|
||||
|
@ -272,7 +280,7 @@ impl Db {
|
|||
&self,
|
||||
actor_id: Url,
|
||||
instance: Instance,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
let vec = serde_json::to_vec(&instance)?;
|
||||
|
||||
|
@ -285,7 +293,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn instance(&self, actor_id: Url) -> Result<Option<Instance>, MyError> {
|
||||
pub(crate) async fn instance(&self, actor_id: Url) -> Result<Option<Instance>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.actor_id_instance.get(actor_id.as_str().as_bytes())? {
|
||||
let instance = serde_json::from_slice(&ivec)?;
|
||||
|
@ -297,16 +305,12 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn connected_instance(&self) -> Result<HashMap<Url, Instance>, MyError> {
|
||||
pub(crate) async fn connected_instance(&self) -> Result<HashMap<Url, Instance>, Error> {
|
||||
self.unblock(|inner| Ok(inner.connected_instance().collect()))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn save_contact(
|
||||
&self,
|
||||
actor_id: Url,
|
||||
contact: Contact,
|
||||
) -> Result<(), MyError> {
|
||||
pub(crate) async fn save_contact(&self, actor_id: Url, contact: Contact) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
let vec = serde_json::to_vec(&contact)?;
|
||||
|
||||
|
@ -319,7 +323,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn contact(&self, actor_id: Url) -> Result<Option<Contact>, MyError> {
|
||||
pub(crate) async fn contact(&self, actor_id: Url) -> Result<Option<Contact>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.actor_id_contact.get(actor_id.as_str().as_bytes())? {
|
||||
let contact = serde_json::from_slice(&ivec)?;
|
||||
|
@ -331,12 +335,12 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn connected_contact(&self) -> Result<HashMap<Url, Contact>, MyError> {
|
||||
pub(crate) async fn connected_contact(&self) -> Result<HashMap<Url, Contact>, Error> {
|
||||
self.unblock(|inner| Ok(inner.connected_contact().collect()))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn save_url(&self, url: Url, id: Uuid) -> Result<(), MyError> {
|
||||
pub(crate) async fn save_url(&self, url: Url, id: Uuid) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
inner
|
||||
.media_id_media_url
|
||||
|
@ -354,7 +358,7 @@ impl Db {
|
|||
id: Uuid,
|
||||
meta: MediaMeta,
|
||||
bytes: Bytes,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
let vec = serde_json::to_vec(&meta)?;
|
||||
|
||||
|
@ -368,7 +372,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn media_id(&self, url: Url) -> Result<Option<Uuid>, MyError> {
|
||||
pub(crate) async fn media_id(&self, url: Url) -> Result<Option<Uuid>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.media_url_media_id.get(url.as_str().as_bytes())? {
|
||||
Ok(uuid_from_ivec(ivec))
|
||||
|
@ -379,7 +383,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn media_url(&self, id: Uuid) -> Result<Option<Url>, MyError> {
|
||||
pub(crate) async fn media_url(&self, id: Uuid) -> Result<Option<Url>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.media_id_media_url.get(id.as_bytes())? {
|
||||
Ok(url_from_ivec(ivec))
|
||||
|
@ -390,7 +394,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn media_bytes(&self, id: Uuid) -> Result<Option<Bytes>, MyError> {
|
||||
pub(crate) async fn media_bytes(&self, id: Uuid) -> Result<Option<Bytes>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.media_id_media_bytes.get(id.as_bytes())? {
|
||||
Ok(Some(Bytes::copy_from_slice(&ivec)))
|
||||
|
@ -401,7 +405,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn media_meta(&self, id: Uuid) -> Result<Option<MediaMeta>, MyError> {
|
||||
pub(crate) async fn media_meta(&self, id: Uuid) -> Result<Option<MediaMeta>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.media_id_media_meta.get(id.as_bytes())? {
|
||||
let meta = serde_json::from_slice(&ivec)?;
|
||||
|
@ -413,16 +417,16 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn blocks(&self) -> Result<Vec<String>, MyError> {
|
||||
pub(crate) async fn blocks(&self) -> Result<Vec<String>, Error> {
|
||||
self.unblock(|inner| Ok(inner.blocks().collect())).await
|
||||
}
|
||||
|
||||
pub(crate) async fn inboxes(&self) -> Result<Vec<Url>, MyError> {
|
||||
pub(crate) async fn inboxes(&self) -> Result<Vec<Url>, Error> {
|
||||
self.unblock(|inner| Ok(inner.connected_actors().map(|actor| actor.inbox).collect()))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn is_connected(&self, mut id: Url) -> Result<bool, MyError> {
|
||||
pub(crate) async fn is_connected(&self, mut id: Url) -> Result<bool, Error> {
|
||||
id.set_path("");
|
||||
id.set_query(None);
|
||||
id.set_fragment(None);
|
||||
|
@ -444,7 +448,7 @@ impl Db {
|
|||
pub(crate) async fn actor_id_from_public_key_id(
|
||||
&self,
|
||||
public_key_id: Url,
|
||||
) -> Result<Option<Url>, MyError> {
|
||||
) -> Result<Option<Url>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner
|
||||
.public_key_id_actor_id
|
||||
|
@ -458,7 +462,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn actor(&self, actor_id: Url) -> Result<Option<Actor>, MyError> {
|
||||
pub(crate) async fn actor(&self, actor_id: Url) -> Result<Option<Actor>, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(ivec) = inner.actor_id_actor.get(actor_id.as_str().as_bytes())? {
|
||||
let actor = serde_json::from_slice(&ivec)?;
|
||||
|
@ -470,7 +474,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn save_actor(&self, actor: Actor) -> Result<(), MyError> {
|
||||
pub(crate) async fn save_actor(&self, actor: Actor) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
let vec = serde_json::to_vec(&actor)?;
|
||||
|
||||
|
@ -486,8 +490,8 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_connection(&self, actor_id: Url) -> Result<(), MyError> {
|
||||
log::debug!("Removing Connection: {}", actor_id);
|
||||
pub(crate) async fn remove_connection(&self, actor_id: Url) -> Result<(), Error> {
|
||||
tracing::debug!("Removing Connection: {}", actor_id);
|
||||
self.unblock(move |inner| {
|
||||
inner
|
||||
.connected_actor_ids
|
||||
|
@ -498,8 +502,8 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn add_connection(&self, actor_id: Url) -> Result<(), MyError> {
|
||||
log::debug!("Adding Connection: {}", actor_id);
|
||||
pub(crate) async fn add_connection(&self, actor_id: Url) -> Result<(), Error> {
|
||||
tracing::debug!("Adding Connection: {}", actor_id);
|
||||
self.unblock(move |inner| {
|
||||
inner
|
||||
.connected_actor_ids
|
||||
|
@ -510,7 +514,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn add_blocks(&self, domains: Vec<String>) -> Result<(), MyError> {
|
||||
pub(crate) async fn add_blocks(&self, domains: Vec<String>) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
for connected in inner.connected_by_domain(&domains) {
|
||||
inner
|
||||
|
@ -530,7 +534,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_blocks(&self, domains: Vec<String>) -> Result<(), MyError> {
|
||||
pub(crate) async fn remove_blocks(&self, domains: Vec<String>) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
for domain in &domains {
|
||||
inner.blocked_domains.remove(domain_key(domain))?;
|
||||
|
@ -541,7 +545,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn add_allows(&self, domains: Vec<String>) -> Result<(), MyError> {
|
||||
pub(crate) async fn add_allows(&self, domains: Vec<String>) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
for domain in &domains {
|
||||
inner
|
||||
|
@ -554,7 +558,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_allows(&self, domains: Vec<String>) -> Result<(), MyError> {
|
||||
pub(crate) async fn remove_allows(&self, domains: Vec<String>) -> Result<(), Error> {
|
||||
self.unblock(move |inner| {
|
||||
if inner.restricted_mode {
|
||||
for connected in inner.connected_by_domain(&domains) {
|
||||
|
@ -573,7 +577,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn is_allowed(&self, url: Url) -> Result<bool, MyError> {
|
||||
pub(crate) async fn is_allowed(&self, url: Url) -> Result<bool, Error> {
|
||||
self.unblock(move |inner| {
|
||||
if let Some(domain) = url.domain() {
|
||||
Ok(inner.is_allowed(domain))
|
||||
|
@ -584,7 +588,7 @@ impl Db {
|
|||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn private_key(&self) -> Result<Option<RsaPrivateKey>, MyError> {
|
||||
pub(crate) async fn private_key(&self) -> Result<Option<RsaPrivateKey>, Error> {
|
||||
self.unblock(|inner| {
|
||||
if let Some(ivec) = inner.settings.get("private-key")? {
|
||||
let key_str = String::from_utf8_lossy(&ivec);
|
||||
|
@ -601,7 +605,7 @@ impl Db {
|
|||
pub(crate) async fn update_private_key(
|
||||
&self,
|
||||
private_key: &RsaPrivateKey,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
let pem_pkcs8 = private_key.to_pkcs8_pem()?;
|
||||
|
||||
self.unblock(move |inner| {
|
||||
|
|
72
src/error.rs
72
src/error.rs
|
@ -5,11 +5,43 @@ use actix_web::{
|
|||
HttpResponse,
|
||||
};
|
||||
use http_signature_normalization_actix::PrepareSignError;
|
||||
use log::error;
|
||||
use std::{convert::Infallible, fmt::Debug, io::Error};
|
||||
use std::{convert::Infallible, fmt::Debug, io};
|
||||
use tracing::error;
|
||||
use tracing_error::SpanTrace;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Error {
|
||||
context: SpanTrace,
|
||||
kind: ErrorKind,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.kind)?;
|
||||
std::fmt::Display::fmt(&self.context, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
self.kind.source()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Error
|
||||
where
|
||||
ErrorKind: From<T>,
|
||||
{
|
||||
fn from(error: T) -> Self {
|
||||
Error {
|
||||
context: SpanTrace::capture(),
|
||||
kind: error.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub(crate) enum MyError {
|
||||
pub(crate) enum ErrorKind {
|
||||
#[error("Error queueing job, {0}")]
|
||||
Queue(anyhow::Error),
|
||||
|
||||
|
@ -23,7 +55,7 @@ pub(crate) enum MyError {
|
|||
Uri(#[from] ParseError),
|
||||
|
||||
#[error("Couldn't perform IO, {0}")]
|
||||
Io(#[from] Error),
|
||||
Io(#[from] io::Error),
|
||||
|
||||
#[error("Couldn't sign string, {0}")]
|
||||
Rsa(rsa::errors::Error),
|
||||
|
@ -111,19 +143,23 @@ pub(crate) enum MyError {
|
|||
|
||||
#[error("Not trying request due to failed breaker")]
|
||||
Breaker,
|
||||
|
||||
#[error("Failed to extract fields from {0}")]
|
||||
Extract(&'static str)
|
||||
}
|
||||
|
||||
impl ResponseError for MyError {
|
||||
impl ResponseError for Error {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
MyError::NotAllowed(_) | MyError::WrongActor(_) | MyError::BadActor(_, _) => {
|
||||
match self.kind {
|
||||
ErrorKind::NotAllowed(_) | ErrorKind::WrongActor(_) | ErrorKind::BadActor(_, _) => {
|
||||
StatusCode::FORBIDDEN
|
||||
}
|
||||
MyError::NotSubscribed(_) => StatusCode::UNAUTHORIZED,
|
||||
MyError::Duplicate => StatusCode::ACCEPTED,
|
||||
MyError::Kind(_) | MyError::MissingKind | MyError::MissingId | MyError::ObjectCount => {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
ErrorKind::NotSubscribed(_) => StatusCode::UNAUTHORIZED,
|
||||
ErrorKind::Duplicate => StatusCode::ACCEPTED,
|
||||
ErrorKind::Kind(_)
|
||||
| ErrorKind::MissingKind
|
||||
| ErrorKind::MissingId
|
||||
| ErrorKind::ObjectCount => StatusCode::BAD_REQUEST,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
@ -133,27 +169,27 @@ impl ResponseError for MyError {
|
|||
.insert_header(("Content-Type", "application/activity+json"))
|
||||
.body(
|
||||
serde_json::to_string(&serde_json::json!({
|
||||
"error": self.to_string(),
|
||||
"error": self.kind.to_string(),
|
||||
}))
|
||||
.unwrap_or("{}".to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockingError> for MyError {
|
||||
impl From<BlockingError> for ErrorKind {
|
||||
fn from(_: BlockingError) -> Self {
|
||||
MyError::Canceled
|
||||
ErrorKind::Canceled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Infallible> for MyError {
|
||||
impl From<Infallible> for ErrorKind {
|
||||
fn from(i: Infallible) -> Self {
|
||||
match i {}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rsa::errors::Error> for MyError {
|
||||
impl From<rsa::errors::Error> for ErrorKind {
|
||||
fn from(e: rsa::errors::Error) -> Self {
|
||||
MyError::Rsa(e)
|
||||
ErrorKind::Rsa(e)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
config::{Config, UrlKind},
|
||||
db::Actor,
|
||||
error::MyError,
|
||||
error::Error,
|
||||
jobs::{
|
||||
apub::{get_inboxes, prepare_activity},
|
||||
DeliverMany, JobState,
|
||||
|
@ -22,7 +22,8 @@ impl Announce {
|
|||
Announce { object_id, actor }
|
||||
}
|
||||
|
||||
async fn perform(self, state: JobState) -> Result<(), anyhow::Error> {
|
||||
#[tracing::instrument(name = "Announce")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
let activity_id = state.config.generate_url(UrlKind::Activity);
|
||||
|
||||
let announce = generate_announce(&state.config, &activity_id, &self.object_id)?;
|
||||
|
@ -41,7 +42,7 @@ fn generate_announce(
|
|||
config: &Config,
|
||||
activity_id: &Url,
|
||||
object_id: &Url,
|
||||
) -> Result<AsAnnounce, MyError> {
|
||||
) -> Result<AsAnnounce, Error> {
|
||||
let announce = AsAnnounce::new(config.generate_url(UrlKind::Actor), object_id.clone());
|
||||
|
||||
prepare_activity(
|
||||
|
@ -58,6 +59,6 @@ impl ActixJob for Announce {
|
|||
const NAME: &'static str = "relay::jobs::apub::Announce";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
apub::AcceptedActivities,
|
||||
config::{Config, UrlKind},
|
||||
db::Actor,
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
jobs::{apub::prepare_activity, Deliver, JobState, QueryInstance, QueryNodeinfo},
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -24,7 +24,8 @@ impl Follow {
|
|||
Follow { input, actor }
|
||||
}
|
||||
|
||||
async fn perform(self, state: JobState) -> Result<(), anyhow::Error> {
|
||||
#[tracing::instrument(name = "Follow")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
let my_id = state.config.generate_url(UrlKind::Actor);
|
||||
|
||||
// if following relay directly, not just following 'public', followback
|
||||
|
@ -42,7 +43,7 @@ impl Follow {
|
|||
let accept = generate_accept_follow(
|
||||
&state.config,
|
||||
&self.actor.id,
|
||||
self.input.id_unchecked().ok_or(MyError::MissingId)?,
|
||||
self.input.id_unchecked().ok_or(ErrorKind::MissingId)?,
|
||||
&my_id,
|
||||
)?;
|
||||
|
||||
|
@ -61,7 +62,7 @@ impl Follow {
|
|||
}
|
||||
|
||||
// Generate a type that says "I want to follow you"
|
||||
fn generate_follow(config: &Config, actor_id: &Url, my_id: &Url) -> Result<AsFollow, MyError> {
|
||||
fn generate_follow(config: &Config, actor_id: &Url, my_id: &Url) -> Result<AsFollow, Error> {
|
||||
let follow = AsFollow::new(my_id.clone(), actor_id.clone());
|
||||
|
||||
prepare_activity(
|
||||
|
@ -77,7 +78,7 @@ fn generate_accept_follow(
|
|||
actor_id: &Url,
|
||||
input_id: &Url,
|
||||
my_id: &Url,
|
||||
) -> Result<AsAccept, MyError> {
|
||||
) -> Result<AsAccept, Error> {
|
||||
let mut follow = AsFollow::new(actor_id.clone(), my_id.clone());
|
||||
|
||||
follow.set_id(input_id.clone());
|
||||
|
@ -98,6 +99,6 @@ impl ActixJob for Follow {
|
|||
const NAME: &'static str = "relay::jobs::apub::Follow";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
apub::AcceptedActivities,
|
||||
db::Actor,
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
jobs::{apub::get_inboxes, DeliverMany, JobState},
|
||||
};
|
||||
use activitystreams::prelude::*;
|
||||
|
@ -19,12 +19,13 @@ impl Forward {
|
|||
Forward { input, actor }
|
||||
}
|
||||
|
||||
async fn perform(self, state: JobState) -> Result<(), anyhow::Error> {
|
||||
#[tracing::instrument(name = "Forward")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
let object_id = self
|
||||
.input
|
||||
.object()
|
||||
.as_single_id()
|
||||
.ok_or(MyError::MissingId)?;
|
||||
.ok_or(ErrorKind::MissingId)?;
|
||||
|
||||
let inboxes = get_inboxes(&state.state, &self.actor, object_id).await?;
|
||||
|
||||
|
@ -43,6 +44,6 @@ impl ActixJob for Forward {
|
|||
const NAME: &'static str = "relay::jobs::apub::Forward";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
config::{Config, UrlKind},
|
||||
data::State,
|
||||
db::Actor,
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
};
|
||||
use activitystreams::{
|
||||
activity::{Follow as AsFollow, Undo as AsUndo},
|
||||
|
@ -23,8 +23,8 @@ pub(crate) use self::{
|
|||
announce::Announce, follow::Follow, forward::Forward, reject::Reject, undo::Undo,
|
||||
};
|
||||
|
||||
async fn get_inboxes(state: &State, actor: &Actor, object_id: &Url) -> Result<Vec<Url>, MyError> {
|
||||
let domain = object_id.host().ok_or(MyError::Domain)?.to_string();
|
||||
async fn get_inboxes(state: &State, actor: &Actor, object_id: &Url) -> Result<Vec<Url>, Error> {
|
||||
let domain = object_id.host().ok_or(ErrorKind::Domain)?.to_string();
|
||||
|
||||
state.inboxes_without(&actor.inbox, &domain).await
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ fn prepare_activity<T, U, V, Kind>(
|
|||
mut t: T,
|
||||
id: impl TryInto<Url, Error = U>,
|
||||
to: impl TryInto<Url, Error = V>,
|
||||
) -> Result<T, MyError>
|
||||
) -> Result<T, Error>
|
||||
where
|
||||
T: ObjectExt<Kind> + BaseExt<Kind>,
|
||||
MyError: From<U> + From<V>,
|
||||
Error: From<U> + From<V>,
|
||||
{
|
||||
t.set_id(id.try_into()?)
|
||||
.set_many_tos(vec![to.try_into()?])
|
||||
|
@ -45,7 +45,7 @@ where
|
|||
}
|
||||
|
||||
// Generate a type that says "I want to stop following you"
|
||||
fn generate_undo_follow(config: &Config, actor_id: &Url, my_id: &Url) -> Result<AsUndo, MyError> {
|
||||
fn generate_undo_follow(config: &Config, actor_id: &Url, my_id: &Url) -> Result<AsUndo, Error> {
|
||||
let mut follow = AsFollow::new(my_id.clone(), actor_id.clone());
|
||||
|
||||
follow.set_id(config.generate_url(UrlKind::Activity));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
config::UrlKind,
|
||||
db::Actor,
|
||||
error::Error,
|
||||
jobs::{apub::generate_undo_follow, Deliver, JobState},
|
||||
};
|
||||
use background_jobs::ActixJob;
|
||||
|
@ -10,7 +11,8 @@ use std::{future::Future, pin::Pin};
|
|||
pub(crate) struct Reject(pub(crate) Actor);
|
||||
|
||||
impl Reject {
|
||||
async fn perform(self, state: JobState) -> Result<(), anyhow::Error> {
|
||||
#[tracing::instrument(name = "Reject")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
state.actors.remove_connection(&self.0).await?;
|
||||
|
||||
let my_id = state.config.generate_url(UrlKind::Actor);
|
||||
|
@ -29,6 +31,6 @@ impl ActixJob for Reject {
|
|||
const NAME: &'static str = "relay::jobs::apub::Reject";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
apub::AcceptedActivities,
|
||||
config::UrlKind,
|
||||
db::Actor,
|
||||
error::Error,
|
||||
jobs::{apub::generate_undo_follow, Deliver, JobState},
|
||||
};
|
||||
use background_jobs::ActixJob;
|
||||
|
@ -18,7 +19,8 @@ impl Undo {
|
|||
Undo { input, actor }
|
||||
}
|
||||
|
||||
async fn perform(self, state: JobState) -> Result<(), anyhow::Error> {
|
||||
#[tracing::instrument(name = "Undo")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
let was_following = state.state.db.is_connected(self.actor.id.clone()).await?;
|
||||
|
||||
state.actors.remove_connection(&self.actor).await?;
|
||||
|
@ -42,6 +44,6 @@ impl ActixJob for Undo {
|
|||
const NAME: &'static str = "relay::jobs::apub::Undo";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::jobs::JobState;
|
||||
use anyhow::Error;
|
||||
use crate::{error::Error, jobs::JobState};
|
||||
use background_jobs::ActixJob;
|
||||
use std::{future::Future, pin::Pin};
|
||||
use uuid::Uuid;
|
||||
|
@ -14,6 +13,7 @@ impl CacheMedia {
|
|||
CacheMedia { uuid }
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Cache media")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
if !state.media.is_outdated(self.uuid).await? {
|
||||
return Ok(());
|
||||
|
@ -34,11 +34,11 @@ impl CacheMedia {
|
|||
|
||||
impl ActixJob for CacheMedia {
|
||||
type State = JobState;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::CacheMedia";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{apub::AcceptedActors, jobs::JobState};
|
||||
use crate::{
|
||||
apub::AcceptedActors,
|
||||
error::{Error, ErrorKind},
|
||||
jobs::JobState,
|
||||
};
|
||||
use activitystreams::{object::Image, prelude::*, url::Url};
|
||||
use anyhow::Error;
|
||||
use background_jobs::ActixJob;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
|
@ -33,8 +36,8 @@ impl QueryContact {
|
|||
.fetch::<AcceptedActors>(self.contact_id.as_str())
|
||||
.await?;
|
||||
|
||||
let (username, display_name, url, avatar) = to_contact(contact)
|
||||
.ok_or_else(|| anyhow::anyhow!("Failed to extract fields from contact"))?;
|
||||
let (username, display_name, url, avatar) =
|
||||
to_contact(contact).ok_or_else(|| ErrorKind::Extract("contact"))?;
|
||||
|
||||
state
|
||||
.node_cache
|
||||
|
@ -63,12 +66,12 @@ fn to_contact(contact: AcceptedActors) -> Option<(String, String, Url, Url)> {
|
|||
|
||||
impl ActixJob for QueryContact {
|
||||
type State = JobState;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::QueryContact";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{error::MyError, jobs::JobState};
|
||||
use crate::{error::Error, jobs::JobState};
|
||||
use activitystreams::url::Url;
|
||||
use anyhow::Error;
|
||||
use background_jobs::{ActixJob, Backoff};
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
|
@ -11,7 +10,7 @@ pub(crate) struct Deliver {
|
|||
}
|
||||
|
||||
impl Deliver {
|
||||
pub(crate) fn new<T>(to: Url, data: T) -> Result<Self, MyError>
|
||||
pub(crate) fn new<T>(to: Url, data: T) -> Result<Self, Error>
|
||||
where
|
||||
T: serde::ser::Serialize,
|
||||
{
|
||||
|
@ -20,20 +19,22 @@ impl Deliver {
|
|||
data: serde_json::to_value(data)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Deliver")]
|
||||
async fn permform(self, state: JobState) -> Result<(), Error> {
|
||||
state.requests.deliver(self.to, &self.data).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActixJob for Deliver {
|
||||
type State = JobState;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::Deliver";
|
||||
const BACKOFF: Backoff = Backoff::Exponential(8);
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
state.requests.deliver(self.to, &self.data).await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Box::pin(async move { self.permform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use crate::{
|
||||
error::MyError,
|
||||
error::Error,
|
||||
jobs::{Deliver, JobState},
|
||||
};
|
||||
use activitystreams::url::Url;
|
||||
use anyhow::Error;
|
||||
use background_jobs::ActixJob;
|
||||
use futures::future::{ready, Ready};
|
||||
use std::future::{ready, Ready};
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub(crate) struct DeliverMany {
|
||||
|
@ -14,7 +13,7 @@ pub(crate) struct DeliverMany {
|
|||
}
|
||||
|
||||
impl DeliverMany {
|
||||
pub(crate) fn new<T>(to: Vec<Url>, data: T) -> Result<Self, MyError>
|
||||
pub(crate) fn new<T>(to: Vec<Url>, data: T) -> Result<Self, Error>
|
||||
where
|
||||
T: serde::ser::Serialize,
|
||||
{
|
||||
|
@ -24,6 +23,7 @@ impl DeliverMany {
|
|||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Deliver many")]
|
||||
fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
for inbox in self.to {
|
||||
state
|
||||
|
@ -37,11 +37,11 @@ impl DeliverMany {
|
|||
|
||||
impl ActixJob for DeliverMany {
|
||||
type State = JobState;
|
||||
type Future = Ready<Result<(), Error>>;
|
||||
type Future = Ready<Result<(), anyhow::Error>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::DeliverMany";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
ready(self.perform(state))
|
||||
ready(self.perform(state).map_err(Into::into))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{
|
||||
config::UrlKind,
|
||||
error::Error,
|
||||
jobs::{cache_media::CacheMedia, JobState},
|
||||
};
|
||||
use activitystreams::url::Url;
|
||||
use anyhow::Error;
|
||||
use background_jobs::ActixJob;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
|
@ -17,6 +17,7 @@ impl QueryInstance {
|
|||
QueryInstance { actor_id }
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Query instance")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
let contact_outdated = state
|
||||
.node_cache
|
||||
|
@ -91,12 +92,12 @@ impl QueryInstance {
|
|||
|
||||
impl ActixJob for QueryInstance {
|
||||
type State = JobState;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::QueryInstance";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
config::Config,
|
||||
data::{ActorCache, MediaCache, NodeCache, State},
|
||||
db::Db,
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
jobs::process_listeners::Listeners,
|
||||
requests::Requests,
|
||||
};
|
||||
|
@ -67,7 +67,7 @@ pub(crate) fn create_workers(
|
|||
.start(remote_handle);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct JobState {
|
||||
db: Db,
|
||||
requests: Requests,
|
||||
|
@ -84,6 +84,14 @@ pub(crate) struct JobServer {
|
|||
remote: QueueHandle,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for JobServer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("JobServer")
|
||||
.field("queue_handle", &"QueueHandle")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl JobState {
|
||||
fn new(
|
||||
db: Db,
|
||||
|
@ -113,10 +121,13 @@ impl JobServer {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn queue<J>(&self, job: J) -> Result<(), MyError>
|
||||
pub(crate) fn queue<J>(&self, job: J) -> Result<(), Error>
|
||||
where
|
||||
J: Job,
|
||||
{
|
||||
self.remote.queue(job).map_err(MyError::Queue)
|
||||
self.remote
|
||||
.queue(job)
|
||||
.map_err(ErrorKind::Queue)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::jobs::{JobState, QueryContact};
|
||||
use crate::{
|
||||
error::Error,
|
||||
jobs::{JobState, QueryContact},
|
||||
};
|
||||
use activitystreams::url::Url;
|
||||
use anyhow::Error;
|
||||
use background_jobs::ActixJob;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
|
@ -14,6 +16,7 @@ impl QueryNodeinfo {
|
|||
QueryNodeinfo { actor_id }
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Query node info")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
if !state
|
||||
.node_cache
|
||||
|
@ -65,12 +68,12 @@ impl QueryNodeinfo {
|
|||
|
||||
impl ActixJob for QueryNodeinfo {
|
||||
type State = JobState;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::QueryNodeinfo";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::jobs::{instance::QueryInstance, nodeinfo::QueryNodeinfo, JobState};
|
||||
use anyhow::Error;
|
||||
use crate::{
|
||||
error::Error,
|
||||
jobs::{instance::QueryInstance, nodeinfo::QueryNodeinfo, JobState},
|
||||
};
|
||||
use background_jobs::ActixJob;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
|
@ -7,6 +9,7 @@ use std::{future::Future, pin::Pin};
|
|||
pub(crate) struct Listeners;
|
||||
|
||||
impl Listeners {
|
||||
#[tracing::instrument(name = "Spawn query instances")]
|
||||
async fn perform(self, state: JobState) -> Result<(), Error> {
|
||||
for actor_id in state.state.db.connected_ids().await? {
|
||||
state
|
||||
|
@ -21,11 +24,11 @@ impl Listeners {
|
|||
|
||||
impl ActixJob for Listeners {
|
||||
type State = JobState;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), anyhow::Error>>>>;
|
||||
|
||||
const NAME: &'static str = "relay::jobs::Listeners";
|
||||
|
||||
fn run(self, state: Self::State) -> Self::Future {
|
||||
Box::pin(self.perform(state))
|
||||
Box::pin(async move { self.perform(state).await.map_err(Into::into) })
|
||||
}
|
||||
}
|
||||
|
|
42
src/main.rs
42
src/main.rs
|
@ -1,7 +1,8 @@
|
|||
use actix_web::{
|
||||
middleware::{Compress, Logger},
|
||||
web, App, HttpServer,
|
||||
};
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use tracing_actix_web::TracingLogger;
|
||||
use tracing_error::ErrorLayer;
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, EnvFilter};
|
||||
|
||||
mod apub;
|
||||
mod args;
|
||||
|
@ -28,23 +29,23 @@ use self::{
|
|||
async fn main() -> Result<(), anyhow::Error> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
LogTracer::init()?;
|
||||
|
||||
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
|
||||
|
||||
let format_layer = tracing_subscriber::fmt::layer()
|
||||
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
||||
.pretty();
|
||||
|
||||
let subscriber = tracing_subscriber::Registry::default()
|
||||
.with(env_filter)
|
||||
.with(ErrorLayer::default())
|
||||
.with(format_layer);
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
|
||||
let config = Config::build()?;
|
||||
|
||||
if config.debug() {
|
||||
std::env::set_var(
|
||||
"RUST_LOG",
|
||||
"debug,h2=info,trust_dns_resolver=info,trust_dns_proto=info,rustls=info,html5ever=info",
|
||||
)
|
||||
} else {
|
||||
std::env::set_var("RUST_LOG", "info")
|
||||
}
|
||||
|
||||
if config.pretty_log() {
|
||||
pretty_env_logger::init();
|
||||
} else {
|
||||
env_logger::init();
|
||||
}
|
||||
|
||||
let db = Db::build(&config)?;
|
||||
|
||||
let args = Args::new();
|
||||
|
@ -77,8 +78,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
let bind_address = config.bind_address();
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(Compress::default())
|
||||
.wrap(Logger::default())
|
||||
.wrap(TracingLogger::default())
|
||||
.app_data(web::Data::new(db.clone()))
|
||||
.app_data(web::Data::new(state.clone()))
|
||||
.app_data(web::Data::new(state.requests()))
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
use actix_web::{
|
||||
dev::{Payload, Service, ServiceRequest, Transform},
|
||||
http::{Method, StatusCode},
|
||||
http::Method,
|
||||
web::BytesMut,
|
||||
HttpMessage, HttpResponse, ResponseError,
|
||||
HttpMessage,
|
||||
};
|
||||
use futures::{
|
||||
future::{ok, LocalBoxFuture, Ready, TryFutureExt},
|
||||
use futures_util::{
|
||||
future::{LocalBoxFuture, TryFutureExt},
|
||||
stream::{once, TryStreamExt},
|
||||
};
|
||||
use log::{error, info};
|
||||
use std::task::{Context, Poll};
|
||||
use std::{
|
||||
future::{ready, Ready},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct DebugPayload(pub bool);
|
||||
|
@ -18,20 +21,6 @@ pub(crate) struct DebugPayload(pub bool);
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct DebugPayloadMiddleware<S>(bool, S);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Failed to read payload")]
|
||||
pub(crate) struct DebugError;
|
||||
|
||||
impl ResponseError for DebugError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(self.status_code())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Transform<S, ServiceRequest> for DebugPayload
|
||||
where
|
||||
S: Service<ServiceRequest, Error = actix_web::Error>,
|
||||
|
@ -45,7 +34,7 @@ where
|
|||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ok(DebugPayloadMiddleware(self.0, service))
|
||||
ready(Ok(DebugPayloadMiddleware(self.0, service)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
use crate::{
|
||||
apub::AcceptedActors,
|
||||
data::{ActorCache, State},
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
requests::Requests,
|
||||
};
|
||||
use activitystreams::{base::BaseExt, uri, url::Url};
|
||||
use actix_web::web;
|
||||
use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm};
|
||||
use log::error;
|
||||
use rsa::{hash::Hash, padding::PaddingScheme, pkcs8::FromPublicKey, PublicKey, RsaPublicKey};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MyVerify(pub Requests, pub ActorCache, pub State);
|
||||
|
||||
impl MyVerify {
|
||||
#[tracing::instrument("Verify signature")]
|
||||
async fn verify(
|
||||
&self,
|
||||
algorithm: Option<Algorithm>,
|
||||
key_id: String,
|
||||
signature: String,
|
||||
signing_string: String,
|
||||
) -> Result<bool, MyError> {
|
||||
) -> Result<bool, Error> {
|
||||
let public_key_id = uri!(key_id);
|
||||
|
||||
let actor_id = if let Some(mut actor_id) = self
|
||||
|
@ -32,7 +32,7 @@ impl MyVerify {
|
|||
.await?
|
||||
{
|
||||
if !self.2.db.is_allowed(actor_id.clone()).await? {
|
||||
return Err(MyError::NotAllowed(key_id));
|
||||
return Err(ErrorKind::NotAllowed(key_id).into());
|
||||
}
|
||||
|
||||
actor_id.set_fragment(None);
|
||||
|
@ -44,7 +44,7 @@ impl MyVerify {
|
|||
Some(Algorithm::Hs2019) => (),
|
||||
Some(Algorithm::Deprecated(DeprecatedAlgorithm::RsaSha256)) => (),
|
||||
Some(other) => {
|
||||
return Err(MyError::Algorithm(other.to_string()));
|
||||
return Err(ErrorKind::Algorithm(other.to_string()).into());
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ impl MyVerify {
|
|||
.fetch::<PublicKeyResponse>(public_key_id.as_str())
|
||||
.await?
|
||||
.actor_id()
|
||||
.ok_or_else(|| MyError::MissingId)?
|
||||
.ok_or_else(|| ErrorKind::MissingId)?
|
||||
};
|
||||
|
||||
// Previously we verified the sig from an actor's local cache
|
||||
|
@ -106,7 +106,7 @@ async fn do_verify(
|
|||
public_key: &str,
|
||||
signature: String,
|
||||
signing_string: String,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
let public_key = RsaPublicKey::from_public_key_pem(public_key)?;
|
||||
|
||||
web::block(move || {
|
||||
|
@ -121,7 +121,7 @@ async fn do_verify(
|
|||
&decoded,
|
||||
)?;
|
||||
|
||||
Ok(()) as Result<(), MyError>
|
||||
Ok(()) as Result<(), Error>
|
||||
})
|
||||
.await??;
|
||||
|
||||
|
@ -129,7 +129,7 @@ async fn do_verify(
|
|||
}
|
||||
|
||||
impl SignatureVerify for MyVerify {
|
||||
type Error = MyError;
|
||||
type Error = Error;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<bool, Self::Error>>>>;
|
||||
|
||||
fn signature_verify(
|
||||
|
@ -144,10 +144,6 @@ impl SignatureVerify for MyVerify {
|
|||
Box::pin(async move {
|
||||
this.verify(algorithm, key_id, signature, signing_string)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Failed to verify, {}", e);
|
||||
e
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ use crate::{
|
|||
};
|
||||
use actix_web::web::Data;
|
||||
use actix_webfinger::{Resolver, Webfinger};
|
||||
use futures_util::future::LocalBoxFuture;
|
||||
use rsa_magic_public_key::AsMagicPublicKey;
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
pub(crate) struct RelayResolver;
|
||||
|
||||
|
@ -13,8 +13,6 @@ pub(crate) struct RelayResolver;
|
|||
#[error("Error resolving webfinger data")]
|
||||
pub(crate) struct RelayError;
|
||||
|
||||
type FutResult<T, E> = dyn Future<Output = Result<T, E>>;
|
||||
|
||||
impl Resolver for RelayResolver {
|
||||
type State = (Data<State>, Data<Config>);
|
||||
type Error = RelayError;
|
||||
|
@ -23,7 +21,7 @@ impl Resolver for RelayResolver {
|
|||
account: &str,
|
||||
domain: &str,
|
||||
(state, config): Self::State,
|
||||
) -> Pin<Box<FutResult<Option<Webfinger>, Self::Error>>> {
|
||||
) -> LocalBoxFuture<'static, Result<Option<Webfinger>, Self::Error>> {
|
||||
let domain = domain.to_owned();
|
||||
let account = account.to_owned();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::error::MyError;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use activitystreams::url::Url;
|
||||
use actix_web::{http::header::Date, web::Bytes};
|
||||
use async_mutex::Mutex;
|
||||
|
@ -6,7 +6,6 @@ use async_rwlock::RwLock;
|
|||
use awc::Client;
|
||||
use chrono::{DateTime, Utc};
|
||||
use http_signature_normalization_actix::prelude::*;
|
||||
use log::{debug, info, warn};
|
||||
use rsa::{hash::Hash, padding::PaddingScheme, RsaPrivateKey};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{
|
||||
|
@ -19,12 +18,19 @@ use std::{
|
|||
},
|
||||
time::SystemTime,
|
||||
};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Breakers {
|
||||
inner: Arc<RwLock<HashMap<String, Arc<Mutex<Breaker>>>>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Breakers {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Breakers").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Breakers {
|
||||
async fn should_try(&self, url: &Url) -> bool {
|
||||
if let Some(domain) = url.domain() {
|
||||
|
@ -97,6 +103,7 @@ impl Default for Breakers {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Breaker {
|
||||
failures: usize,
|
||||
last_attempt: DateTime<Utc>,
|
||||
|
@ -153,6 +160,21 @@ pub(crate) struct Requests {
|
|||
breakers: Breakers,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Requests {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Requests")
|
||||
.field("client", &"Client")
|
||||
.field("consecutive_errors", &"AtomicUsize")
|
||||
.field("error_limit", &self.error_limit)
|
||||
.field("key_id", &self.key_id)
|
||||
.field("user_agent", &self.user_agent)
|
||||
.field("private_key", &"[redacted]")
|
||||
.field("config", &self.config)
|
||||
.field("breakers", &self.breakers)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Requests {
|
||||
pub(crate) fn new(
|
||||
key_id: String,
|
||||
|
@ -191,28 +213,28 @@ impl Requests {
|
|||
self.consecutive_errors.swap(0, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub(crate) async fn fetch_json<T>(&self, url: &str) -> Result<T, MyError>
|
||||
pub(crate) async fn fetch_json<T>(&self, url: &str) -> Result<T, Error>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
self.do_fetch(url, "application/json").await
|
||||
}
|
||||
|
||||
pub(crate) async fn fetch<T>(&self, url: &str) -> Result<T, MyError>
|
||||
pub(crate) async fn fetch<T>(&self, url: &str) -> Result<T, Error>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
self.do_fetch(url, "application/activity+json").await
|
||||
}
|
||||
|
||||
async fn do_fetch<T>(&self, url: &str, accept: &str) -> Result<T, MyError>
|
||||
async fn do_fetch<T>(&self, url: &str, accept: &str) -> Result<T, Error>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
let parsed_url = url.parse::<Url>()?;
|
||||
|
||||
if !self.breakers.should_try(&parsed_url).await {
|
||||
return Err(MyError::Breaker);
|
||||
return Err(ErrorKind::Breaker.into());
|
||||
}
|
||||
|
||||
let signer = self.signer();
|
||||
|
@ -236,7 +258,7 @@ impl Requests {
|
|||
self.breakers.fail(&parsed_url).await;
|
||||
}
|
||||
|
||||
let mut res = res.map_err(|e| MyError::SendRequest(url.to_string(), e.to_string()))?;
|
||||
let mut res = res.map_err(|e| ErrorKind::SendRequest(url.to_string(), e.to_string()))?;
|
||||
|
||||
self.reset_err();
|
||||
|
||||
|
@ -251,7 +273,7 @@ impl Requests {
|
|||
|
||||
self.breakers.fail(&parsed_url).await;
|
||||
|
||||
return Err(MyError::Status(url.to_string(), res.status()));
|
||||
return Err(ErrorKind::Status(url.to_string(), res.status()).into());
|
||||
}
|
||||
|
||||
self.breakers.succeed(&parsed_url).await;
|
||||
|
@ -259,16 +281,16 @@ impl Requests {
|
|||
let body = res
|
||||
.body()
|
||||
.await
|
||||
.map_err(|e| MyError::ReceiveResponse(url.to_string(), e.to_string()))?;
|
||||
.map_err(|e| ErrorKind::ReceiveResponse(url.to_string(), e.to_string()))?;
|
||||
|
||||
Ok(serde_json::from_slice(body.as_ref())?)
|
||||
}
|
||||
|
||||
pub(crate) async fn fetch_bytes(&self, url: &str) -> Result<(String, Bytes), MyError> {
|
||||
pub(crate) async fn fetch_bytes(&self, url: &str) -> Result<(String, Bytes), Error> {
|
||||
let parsed_url = url.parse::<Url>()?;
|
||||
|
||||
if !self.breakers.should_try(&parsed_url).await {
|
||||
return Err(MyError::Breaker);
|
||||
return Err(ErrorKind::Breaker.into());
|
||||
}
|
||||
|
||||
info!("Fetching bytes for {}", url);
|
||||
|
@ -293,7 +315,7 @@ impl Requests {
|
|||
self.count_err();
|
||||
}
|
||||
|
||||
let mut res = res.map_err(|e| MyError::SendRequest(url.to_string(), e.to_string()))?;
|
||||
let mut res = res.map_err(|e| ErrorKind::SendRequest(url.to_string(), e.to_string()))?;
|
||||
|
||||
self.reset_err();
|
||||
|
||||
|
@ -301,10 +323,10 @@ impl Requests {
|
|||
if let Ok(s) = content_type.to_str() {
|
||||
s.to_owned()
|
||||
} else {
|
||||
return Err(MyError::ContentType);
|
||||
return Err(ErrorKind::ContentType.into());
|
||||
}
|
||||
} else {
|
||||
return Err(MyError::ContentType);
|
||||
return Err(ErrorKind::ContentType.into());
|
||||
};
|
||||
|
||||
if !res.status().is_success() {
|
||||
|
@ -318,14 +340,14 @@ impl Requests {
|
|||
|
||||
self.breakers.fail(&parsed_url).await;
|
||||
|
||||
return Err(MyError::Status(url.to_string(), res.status()));
|
||||
return Err(ErrorKind::Status(url.to_string(), res.status()).into());
|
||||
}
|
||||
|
||||
self.breakers.succeed(&parsed_url).await;
|
||||
|
||||
let bytes = match res.body().limit(1024 * 1024 * 4).await {
|
||||
Err(e) => {
|
||||
return Err(MyError::ReceiveResponse(url.to_string(), e.to_string()));
|
||||
return Err(ErrorKind::ReceiveResponse(url.to_string(), e.to_string()).into());
|
||||
}
|
||||
Ok(bytes) => bytes,
|
||||
};
|
||||
|
@ -333,12 +355,12 @@ impl Requests {
|
|||
Ok((content_type, bytes))
|
||||
}
|
||||
|
||||
pub(crate) async fn deliver<T>(&self, inbox: Url, item: &T) -> Result<(), MyError>
|
||||
pub(crate) async fn deliver<T>(&self, inbox: Url, item: &T) -> Result<(), Error>
|
||||
where
|
||||
T: serde::ser::Serialize,
|
||||
{
|
||||
if !self.breakers.should_try(&inbox).await {
|
||||
return Err(MyError::Breaker);
|
||||
return Err(ErrorKind::Breaker.into());
|
||||
}
|
||||
|
||||
let signer = self.signer();
|
||||
|
@ -366,7 +388,7 @@ impl Requests {
|
|||
self.breakers.fail(&inbox).await;
|
||||
}
|
||||
|
||||
let mut res = res.map_err(|e| MyError::SendRequest(inbox.to_string(), e.to_string()))?;
|
||||
let mut res = res.map_err(|e| ErrorKind::SendRequest(inbox.to_string(), e.to_string()))?;
|
||||
|
||||
self.reset_err();
|
||||
|
||||
|
@ -380,7 +402,7 @@ impl Requests {
|
|||
}
|
||||
|
||||
self.breakers.fail(&inbox).await;
|
||||
return Err(MyError::Status(inbox.to_string(), res.status()));
|
||||
return Err(ErrorKind::Status(inbox.to_string(), res.status()).into());
|
||||
}
|
||||
|
||||
self.breakers.succeed(&inbox).await;
|
||||
|
@ -400,7 +422,7 @@ struct Signer {
|
|||
}
|
||||
|
||||
impl Signer {
|
||||
fn sign(&self, signing_string: &str) -> Result<String, MyError> {
|
||||
fn sign(&self, signing_string: &str) -> Result<String, Error> {
|
||||
let hashed = Sha256::digest(signing_string.as_bytes());
|
||||
let bytes = self.private_key.sign(
|
||||
PaddingScheme::PKCS1v15Sign {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
apub::{PublicKey, PublicKeyInner},
|
||||
config::{Config, UrlKind},
|
||||
data::State,
|
||||
error::MyError,
|
||||
error::Error,
|
||||
routes::ok,
|
||||
};
|
||||
use activitystreams::{
|
||||
|
@ -15,10 +15,11 @@ use activitystreams_ext::Ext1;
|
|||
use actix_web::{web, Responder};
|
||||
use rsa::pkcs8::ToPublicKey;
|
||||
|
||||
#[tracing::instrument(name = "Actor")]
|
||||
pub(crate) async fn route(
|
||||
state: web::Data<State>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<impl Responder, MyError> {
|
||||
) -> Result<impl Responder, Error> {
|
||||
let mut application = Ext1::new(
|
||||
ApActor::new(config.generate_url(UrlKind::Inbox), Application::new()),
|
||||
PublicKey {
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
config::{Config, UrlKind},
|
||||
data::{ActorCache, State},
|
||||
db::Actor,
|
||||
error::MyError,
|
||||
error::{Error, ErrorKind},
|
||||
jobs::apub::{Announce, Follow, Forward, Reject, Undo},
|
||||
jobs::JobServer,
|
||||
requests::Requests,
|
||||
|
@ -14,8 +14,9 @@ use activitystreams::{
|
|||
};
|
||||
use actix_web::{web, HttpResponse};
|
||||
use http_signature_normalization_actix::prelude::{DigestVerified, SignatureVerified};
|
||||
use log::error;
|
||||
use tracing::error;
|
||||
|
||||
#[tracing::instrument(name = "Inbox")]
|
||||
pub(crate) async fn route(
|
||||
state: web::Data<State>,
|
||||
actors: web::Data<ActorCache>,
|
||||
|
@ -24,12 +25,12 @@ pub(crate) async fn route(
|
|||
jobs: web::Data<JobServer>,
|
||||
input: web::Json<AcceptedActivities>,
|
||||
verified: Option<(SignatureVerified, DigestVerified)>,
|
||||
) -> Result<HttpResponse, MyError> {
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let input = input.into_inner();
|
||||
|
||||
let actor = actors
|
||||
.get(
|
||||
input.actor()?.as_single_id().ok_or(MyError::MissingId)?,
|
||||
input.actor()?.as_single_id().ok_or(ErrorKind::MissingId)?,
|
||||
&client,
|
||||
)
|
||||
.await?
|
||||
|
@ -39,28 +40,29 @@ pub(crate) async fn route(
|
|||
let is_connected = state.db.is_connected(actor.id.clone()).await?;
|
||||
|
||||
if !is_allowed {
|
||||
return Err(MyError::NotAllowed(actor.id.to_string()));
|
||||
return Err(ErrorKind::NotAllowed(actor.id.to_string()).into());
|
||||
}
|
||||
|
||||
if !is_connected && !valid_without_listener(&input)? {
|
||||
return Err(MyError::NotSubscribed(actor.id.to_string()));
|
||||
return Err(ErrorKind::NotSubscribed(actor.id.to_string()).into());
|
||||
}
|
||||
|
||||
if config.validate_signatures() && verified.is_none() {
|
||||
return Err(MyError::NoSignature(actor.public_key_id.to_string()));
|
||||
return Err(ErrorKind::NoSignature(actor.public_key_id.to_string()).into());
|
||||
} else if config.validate_signatures() {
|
||||
if let Some((verified, _)) = verified {
|
||||
if actor.public_key_id.as_str() != verified.key_id() {
|
||||
error!("Bad actor, more info: {:?}", input);
|
||||
return Err(MyError::BadActor(
|
||||
return Err(ErrorKind::BadActor(
|
||||
actor.public_key_id.to_string(),
|
||||
verified.key_id().to_owned(),
|
||||
));
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match input.kind().ok_or(MyError::MissingKind)? {
|
||||
match input.kind().ok_or(ErrorKind::MissingKind)? {
|
||||
ValidTypes::Accept => handle_accept(&config, input).await?,
|
||||
ValidTypes::Reject => handle_reject(&config, &jobs, input, actor).await?,
|
||||
ValidTypes::Announce | ValidTypes::Create => {
|
||||
|
@ -74,7 +76,7 @@ pub(crate) async fn route(
|
|||
Ok(accepted(serde_json::json!({})))
|
||||
}
|
||||
|
||||
fn valid_without_listener(input: &AcceptedActivities) -> Result<bool, MyError> {
|
||||
fn valid_without_listener(input: &AcceptedActivities) -> Result<bool, Error> {
|
||||
match input.kind() {
|
||||
Some(ValidTypes::Follow) => Ok(true),
|
||||
Some(ValidTypes::Undo) => Ok(single_object(input.object())?.is_kind("Follow")),
|
||||
|
@ -82,32 +84,32 @@ fn valid_without_listener(input: &AcceptedActivities) -> Result<bool, MyError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn kind_str(base: &AnyBase) -> Result<&str, MyError> {
|
||||
base.kind_str().ok_or(MyError::MissingKind)
|
||||
fn kind_str(base: &AnyBase) -> Result<&str, Error> {
|
||||
base.kind_str()
|
||||
.ok_or(ErrorKind::MissingKind)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn id_string(id: Option<&Url>) -> Result<String, MyError> {
|
||||
id.map(|s| s.to_string()).ok_or(MyError::MissingId)
|
||||
fn id_string(id: Option<&Url>) -> Result<String, Error> {
|
||||
id.map(|s| s.to_string())
|
||||
.ok_or(ErrorKind::MissingId)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn single_object(o: &OneOrMany<AnyBase>) -> Result<&AnyBase, MyError> {
|
||||
o.as_one().ok_or(MyError::ObjectCount)
|
||||
fn single_object(o: &OneOrMany<AnyBase>) -> Result<&AnyBase, Error> {
|
||||
o.as_one().ok_or(ErrorKind::ObjectCount).map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn handle_accept(config: &Config, input: AcceptedActivities) -> Result<(), MyError> {
|
||||
async fn handle_accept(config: &Config, input: AcceptedActivities) -> Result<(), Error> {
|
||||
let base = single_object(input.object())?.clone();
|
||||
let follow = if let Some(follow) = activity::Follow::from_any_base(base)? {
|
||||
follow
|
||||
} else {
|
||||
return Err(MyError::Kind(
|
||||
kind_str(single_object(input.object())?)?.to_owned(),
|
||||
));
|
||||
return Err(ErrorKind::Kind(kind_str(single_object(input.object())?)?.to_owned()).into());
|
||||
};
|
||||
|
||||
if !follow.actor_is(&config.generate_url(UrlKind::Actor)) {
|
||||
return Err(MyError::WrongActor(id_string(
|
||||
follow.actor()?.as_single_id(),
|
||||
)?));
|
||||
return Err(ErrorKind::WrongActor(id_string(follow.actor()?.as_single_id())?).into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -118,20 +120,16 @@ async fn handle_reject(
|
|||
jobs: &JobServer,
|
||||
input: AcceptedActivities,
|
||||
actor: Actor,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
let base = single_object(input.object())?.clone();
|
||||
let follow = if let Some(follow) = activity::Follow::from_any_base(base)? {
|
||||
follow
|
||||
} else {
|
||||
return Err(MyError::Kind(
|
||||
kind_str(single_object(input.object())?)?.to_owned(),
|
||||
));
|
||||
return Err(ErrorKind::Kind(kind_str(single_object(input.object())?)?.to_owned()).into());
|
||||
};
|
||||
|
||||
if !follow.actor_is(&config.generate_url(UrlKind::Actor)) {
|
||||
return Err(MyError::WrongActor(id_string(
|
||||
follow.actor()?.as_single_id(),
|
||||
)?));
|
||||
return Err(ErrorKind::WrongActor(id_string(follow.actor()?.as_single_id())?).into());
|
||||
}
|
||||
|
||||
jobs.queue(Reject(actor))?;
|
||||
|
@ -145,26 +143,26 @@ async fn handle_undo(
|
|||
input: AcceptedActivities,
|
||||
actor: Actor,
|
||||
is_listener: bool,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
let any_base = single_object(input.object())?.clone();
|
||||
let undone_object =
|
||||
AcceptedUndoObjects::from_any_base(any_base)?.ok_or(MyError::ObjectFormat)?;
|
||||
AcceptedUndoObjects::from_any_base(any_base)?.ok_or(ErrorKind::ObjectFormat)?;
|
||||
|
||||
if !undone_object.is_kind(&UndoTypes::Follow) {
|
||||
if is_listener {
|
||||
jobs.queue(Forward::new(input, actor))?;
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(MyError::NotSubscribed(actor.id.to_string()));
|
||||
return Err(ErrorKind::NotSubscribed(actor.id.to_string()).into());
|
||||
}
|
||||
}
|
||||
|
||||
let my_id: Url = config.generate_url(UrlKind::Actor);
|
||||
|
||||
if !undone_object.object_is(&my_id) && !undone_object.object_is(&public()) {
|
||||
return Err(MyError::WrongActor(id_string(
|
||||
undone_object.object().as_single_id(),
|
||||
)?));
|
||||
return Err(
|
||||
ErrorKind::WrongActor(id_string(undone_object.object().as_single_id())?).into(),
|
||||
);
|
||||
}
|
||||
|
||||
if !is_listener {
|
||||
|
@ -179,7 +177,7 @@ async fn handle_forward(
|
|||
jobs: &JobServer,
|
||||
input: AcceptedActivities,
|
||||
actor: Actor,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
jobs.queue(Forward::new(input, actor))?;
|
||||
|
||||
Ok(())
|
||||
|
@ -190,11 +188,11 @@ async fn handle_announce(
|
|||
jobs: &JobServer,
|
||||
input: AcceptedActivities,
|
||||
actor: Actor,
|
||||
) -> Result<(), MyError> {
|
||||
let object_id = input.object().as_single_id().ok_or(MyError::MissingId)?;
|
||||
) -> Result<(), Error> {
|
||||
let object_id = input.object().as_single_id().ok_or(ErrorKind::MissingId)?;
|
||||
|
||||
if state.is_cached(object_id).await {
|
||||
return Err(MyError::Duplicate);
|
||||
return Err(ErrorKind::Duplicate.into());
|
||||
}
|
||||
|
||||
jobs.queue(Announce::new(object_id.to_owned(), actor))?;
|
||||
|
@ -207,13 +205,11 @@ async fn handle_follow(
|
|||
jobs: &JobServer,
|
||||
input: AcceptedActivities,
|
||||
actor: Actor,
|
||||
) -> Result<(), MyError> {
|
||||
) -> Result<(), Error> {
|
||||
let my_id: Url = config.generate_url(UrlKind::Actor);
|
||||
|
||||
if !input.object_is(&my_id) && !input.object_is(&public()) {
|
||||
return Err(MyError::WrongActor(id_string(
|
||||
input.object().as_single_id(),
|
||||
)?));
|
||||
return Err(ErrorKind::WrongActor(id_string(input.object().as_single_id())?).into());
|
||||
}
|
||||
|
||||
jobs.queue(Follow::new(input, actor))?;
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
use crate::{config::Config, data::State, error::MyError};
|
||||
use crate::{
|
||||
config::Config,
|
||||
data::State,
|
||||
error::{Error, ErrorKind},
|
||||
};
|
||||
use actix_web::{web, HttpResponse};
|
||||
use log::error;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use std::io::BufWriter;
|
||||
use tracing::error;
|
||||
|
||||
#[tracing::instrument(name = "Index")]
|
||||
pub(crate) async fn route(
|
||||
state: web::Data<State>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, MyError> {
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let mut nodes = state.node_cache().nodes().await?;
|
||||
nodes.shuffle(&mut thread_rng());
|
||||
let mut buf = BufWriter::new(Vec::new());
|
||||
|
@ -15,7 +20,7 @@ pub(crate) async fn route(
|
|||
crate::templates::index(&mut buf, &nodes, &config)?;
|
||||
let buf = buf.into_inner().map_err(|e| {
|
||||
error!("Error rendering template, {}", e.error());
|
||||
MyError::FlushBuffer
|
||||
ErrorKind::FlushBuffer
|
||||
})?;
|
||||
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(buf))
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use crate::{data::MediaCache, error::MyError, requests::Requests};
|
||||
use crate::{data::MediaCache, error::Error, requests::Requests};
|
||||
use actix_web::{
|
||||
http::header::{CacheControl, CacheDirective},
|
||||
web, HttpResponse,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tracing::instrument(name = "Media")]
|
||||
pub(crate) async fn route(
|
||||
media: web::Data<MediaCache>,
|
||||
requests: web::Data<Requests>,
|
||||
uuid: web::Path<Uuid>,
|
||||
) -> Result<HttpResponse, MyError> {
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let uuid = uuid.into_inner();
|
||||
|
||||
if let Some((content_type, bytes)) = media.get_bytes(uuid).await? {
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
use actix_web::{web, Responder};
|
||||
use actix_webfinger::Link;
|
||||
|
||||
#[tracing::instrument(name = "Well Known NodeInfo")]
|
||||
pub(crate) async fn well_known(config: web::Data<Config>) -> impl Responder {
|
||||
web::Json(Links {
|
||||
links: vec![Link {
|
||||
|
@ -22,6 +23,7 @@ struct Links {
|
|||
links: Vec<Link>,
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "NodeInfo")]
|
||||
pub(crate) async fn route(
|
||||
config: web::Data<Config>,
|
||||
state: web::Data<State>,
|
||||
|
|
|
@ -4,6 +4,7 @@ use actix_web::{
|
|||
web, HttpResponse,
|
||||
};
|
||||
|
||||
#[tracing::instrument(name = "Statistics")]
|
||||
pub(crate) async fn route(filename: web::Path<String>) -> HttpResponse {
|
||||
if let Some(data) = StaticFile::get(&filename.into_inner()) {
|
||||
HttpResponse::Ok()
|
||||
|
|
Loading…
Reference in New Issue
Block a user