diff --git a/src/config.rs b/src/config.rs index 18b7395..5420e63 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use crate::{error::MyError, requests::Requests, verifier::MyVerify}; +use crate::{error::MyError, middleware::MyVerify, requests::Requests}; use config::Environment; use http_signature_normalization_actix::prelude::{VerifyDigest, VerifySignature}; use sha2::{Digest, Sha256}; diff --git a/src/main.rs b/src/main.rs index 521e5eb..3b4892a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,77 +1,29 @@ use actix::Arbiter; -use actix_web::{ - http::header::{ContentType, Expires}, - middleware::Logger, - web, App, HttpResponse, HttpServer, -}; -use log::error; -use std::{ - io::BufWriter, - time::{Duration, SystemTime}, -}; +use actix_web::{middleware::Logger, web, App, HttpServer}; -mod actor; mod apub; mod args; mod config; mod db; mod error; -mod inbox; mod jobs; +mod middleware; mod node; -mod nodeinfo; mod notify; -mod rehydrate; mod requests; -mod responses; +mod routes; mod state; -mod verifier; -mod webfinger; use self::{ args::Args, config::Config, db::Db, - error::MyError, jobs::{create_server, create_workers}, + middleware::RelayResolver, + routes::{actor, inbox, index, nodeinfo, nodeinfo_meta, statics}, state::State, - templates::statics::StaticFile, - webfinger::RelayResolver, }; -async fn index( - state: web::Data, - config: web::Data, -) -> Result { - let nodes = state.node_cache().nodes().await; - - let mut buf = BufWriter::new(Vec::new()); - - templates::index(&mut buf, &nodes, &config)?; - let buf = buf.into_inner().map_err(|e| { - error!("Error rendering template, {}", e.error()); - MyError::FlushBuffer - })?; - - Ok(HttpResponse::Ok().content_type("text/html").body(buf)) -} - -static FAR: Duration = Duration::from_secs(60 * 60 * 24); - -async fn static_file(filename: web::Path) -> HttpResponse { - if let Some(data) = StaticFile::get(&filename.into_inner()) { - let far_expires = SystemTime::now() + FAR; - HttpResponse::Ok() - .set(Expires(far_expires.into())) - .set(ContentType(data.mime.clone())) - .body(data.content) - } else { - HttpResponse::NotFound() - .reason("No such static file.") - .finish() - } -} - #[actix_rt::main] async fn main() -> Result<(), anyhow::Error> { dotenv::dotenv().ok(); @@ -114,7 +66,6 @@ async fn main() -> Result<(), anyhow::Error> { let state = State::hydrate(config.clone(), &db).await?; let job_server = create_server(db.clone()); - rehydrate::spawn(db.clone(), state.clone()); notify::spawn(state.clone(), job_server.clone(), &config)?; if args.jobs_only() { @@ -150,16 +101,16 @@ async fn main() -> Result<(), anyhow::Error> { web::resource("/inbox") .wrap(config.digest_middleware()) .wrap(config.signature_middleware(state.requests())) - .route(web::post().to(inbox::inbox)), + .route(web::post().to(inbox)), ) - .service(web::resource("/actor").route(web::get().to(actor::route))) - .service(web::resource("/nodeinfo/2.0.json").route(web::get().to(nodeinfo::route))) + .service(web::resource("/actor").route(web::get().to(actor))) + .service(web::resource("/nodeinfo/2.0.json").route(web::get().to(nodeinfo))) .service( web::scope("/.well-known") .service(actix_webfinger::scoped::<_, RelayResolver>()) - .service(web::resource("/nodeinfo").route(web::get().to(nodeinfo::well_known))), + .service(web::resource("/nodeinfo").route(web::get().to(nodeinfo_meta))), ) - .service(web::resource("/static/{filename}").route(web::get().to(static_file))) + .service(web::resource("/static/{filename}").route(web::get().to(statics))) }) .bind(bind_address)? .run() diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs new file mode 100644 index 0000000..6e5b1f9 --- /dev/null +++ b/src/middleware/mod.rs @@ -0,0 +1,5 @@ +mod verifier; +mod webfinger; + +pub use verifier::MyVerify; +pub use webfinger::RelayResolver; diff --git a/src/verifier.rs b/src/middleware/verifier.rs similarity index 100% rename from src/verifier.rs rename to src/middleware/verifier.rs diff --git a/src/webfinger.rs b/src/middleware/webfinger.rs similarity index 100% rename from src/webfinger.rs rename to src/middleware/webfinger.rs diff --git a/src/rehydrate.rs b/src/rehydrate.rs deleted file mode 100644 index 28dd2a6..0000000 --- a/src/rehydrate.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::{db::Db, state::State}; -use actix::{ - clock::{interval_at, Duration, Instant}, - Arbiter, -}; -use log::error; - -pub fn spawn(db: Db, state: State) { - Arbiter::spawn(async move { - let start = Instant::now(); - let duration = Duration::from_secs(60 * 10); - - let mut interval = interval_at(start, duration); - - loop { - interval.tick().await; - - match state.rehydrate(&db).await { - Err(e) => error!("Error rehydrating, {}", e), - _ => (), - } - } - }); -} diff --git a/src/responses.rs b/src/responses.rs deleted file mode 100644 index fdf0537..0000000 --- a/src/responses.rs +++ /dev/null @@ -1,20 +0,0 @@ -use actix_web::HttpResponse; -use serde::ser::Serialize; - -static CONTENT_TYPE: &str = "application/activity+json"; - -pub fn ok(item: T) -> HttpResponse -where - T: Serialize, -{ - HttpResponse::Ok().content_type(CONTENT_TYPE).json(item) -} - -pub fn accepted(item: T) -> HttpResponse -where - T: Serialize, -{ - HttpResponse::Accepted() - .content_type(CONTENT_TYPE) - .json(item) -} diff --git a/src/actor.rs b/src/routes/actor.rs similarity index 98% rename from src/actor.rs rename to src/routes/actor.rs index d352e4c..67f9d80 100644 --- a/src/actor.rs +++ b/src/routes/actor.rs @@ -2,7 +2,7 @@ use crate::{ apub::PublicKey, config::{Config, UrlKind}, error::MyError, - responses::ok, + routes::ok, state::State, }; use activitystreams::{ diff --git a/src/inbox.rs b/src/routes/inbox.rs similarity index 99% rename from src/inbox.rs rename to src/routes/inbox.rs index 75648e4..3dacc39 100644 --- a/src/inbox.rs +++ b/src/routes/inbox.rs @@ -6,7 +6,7 @@ use crate::{ jobs::JobServer, jobs::{Deliver, DeliverMany}, requests::Requests, - responses::accepted, + routes::accepted, state::State, }; use activitystreams::{ @@ -22,7 +22,7 @@ use http_signature_normalization_actix::prelude::{DigestVerified, SignatureVerif use log::error; use std::convert::TryInto; -pub async fn inbox( +pub async fn route( db: web::Data, state: web::Data, config: web::Data, diff --git a/src/routes/index.rs b/src/routes/index.rs new file mode 100644 index 0000000..8d6ad43 --- /dev/null +++ b/src/routes/index.rs @@ -0,0 +1,21 @@ +use crate::{config::Config, error::MyError, state::State}; +use actix_web::{web, HttpResponse}; +use log::error; +use std::io::BufWriter; + +pub async fn route( + state: web::Data, + config: web::Data, +) -> Result { + let nodes = state.node_cache().nodes().await; + + let mut buf = BufWriter::new(Vec::new()); + + crate::templates::index(&mut buf, &nodes, &config)?; + let buf = buf.into_inner().map_err(|e| { + error!("Error rendering template, {}", e.error()); + MyError::FlushBuffer + })?; + + Ok(HttpResponse::Ok().content_type("text/html").body(buf)) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 0000000..75b95bf --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,34 @@ +mod actor; +mod inbox; +mod index; +mod nodeinfo; +mod statics; + +pub use self::{ + actor::route as actor, + inbox::route as inbox, + index::route as index, + nodeinfo::{route as nodeinfo, well_known as nodeinfo_meta}, + statics::route as statics, +}; + +use actix_web::HttpResponse; +use serde::ser::Serialize; + +static CONTENT_TYPE: &str = "application/activity+json"; + +fn ok(item: T) -> HttpResponse +where + T: Serialize, +{ + HttpResponse::Ok().content_type(CONTENT_TYPE).json(item) +} + +fn accepted(item: T) -> HttpResponse +where + T: Serialize, +{ + HttpResponse::Accepted() + .content_type(CONTENT_TYPE) + .json(item) +} diff --git a/src/nodeinfo.rs b/src/routes/nodeinfo.rs similarity index 100% rename from src/nodeinfo.rs rename to src/routes/nodeinfo.rs diff --git a/src/routes/statics.rs b/src/routes/statics.rs new file mode 100644 index 0000000..ebfefeb --- /dev/null +++ b/src/routes/statics.rs @@ -0,0 +1,22 @@ +use crate::templates::statics::StaticFile; +use actix_web::{ + http::header::{ContentType, Expires}, + web, HttpResponse, +}; +use std::time::{Duration, SystemTime}; + +static FAR: Duration = Duration::from_secs(60 * 60 * 24); + +pub async fn route(filename: web::Path) -> HttpResponse { + if let Some(data) = StaticFile::get(&filename.into_inner()) { + let far_expires = SystemTime::now() + FAR; + HttpResponse::Ok() + .set(Expires(far_expires.into())) + .set(ContentType(data.mime.clone())) + .body(data.content) + } else { + HttpResponse::NotFound() + .reason("No such static file.") + .finish() + } +} diff --git a/src/state.rs b/src/state.rs index 3e2e7ae..2d26478 100644 --- a/src/state.rs +++ b/src/state.rs @@ -7,9 +7,10 @@ use crate::{ requests::Requests, }; use activitystreams::primitives::XsdAnyUri; +use actix::clock::{interval_at, Duration, Instant}; use actix_web::web; use futures::{join, try_join}; -use log::info; +use log::{error, info}; use lru::LruCache; use rand::thread_rng; use rsa::{RSAPrivateKey, RSAPublicKey}; @@ -199,7 +200,7 @@ impl State { let public_key = private_key.to_public_key(); let listeners = Arc::new(RwLock::new(listeners)); - Ok(State { + let state = State { public_key, private_key, config, @@ -209,6 +210,29 @@ impl State { whitelists: Arc::new(RwLock::new(whitelists)), listeners: listeners.clone(), node_cache: NodeCache::new(listeners), - }) + }; + + state.spawn_rehydrate(db.clone()); + + Ok(state) + } + + fn spawn_rehydrate(&self, db: Db) { + let state = self.clone(); + actix::spawn(async move { + let start = Instant::now(); + let duration = Duration::from_secs(60 * 10); + + let mut interval = interval_at(start, duration); + + loop { + interval.tick().await; + + match state.rehydrate(&db).await { + Err(e) => error!("Error rehydrating, {}", e), + _ => (), + } + } + }); } }