mirror of
https://git.asonix.dog/asonix/relay.git
synced 2024-12-23 11:40:31 +00:00
Instrument with tracing
This commit is contained in:
parent
ebba8e3f60
commit
43e5b6d873
34 changed files with 748 additions and 707 deletions
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 a new issue