diff --git a/Cargo.lock b/Cargo.lock index c25d997..3179aaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,6 +464,7 @@ dependencies = [ "enum_delegate", "env_logger", "rand", + "reqwest", "serde", "serde_json", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 0fce749..ab40239 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,6 @@ serde_json = "1.0.108" tokio = { version = "1.34.0", features = ["full"] } tracing = "0.1.40" url = "2.4.1" + +[dev-dependencies] +reqwest = "0.11.22" diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..07e7b66 --- /dev/null +++ b/src/api.rs @@ -0,0 +1,13 @@ +use crate::error::MyResult; +use crate::federation::objects::article::DbArticle; +use crate::federation::objects::instance::DbInstance; +use axum::extract::Path; +use axum::Json; +use axum_macros::debug_handler; + +#[debug_handler] +pub async fn api_get_article(Path(title): Path) -> MyResult> { + let instance = DbInstance::new("localhost")?; + let article = DbArticle::new(title, "dummy".to_string(), instance.ap_id)?; + Ok(Json(article)) +} diff --git a/src/federation/objects/article.rs b/src/federation/objects/article.rs index 83fb7b8..c6651b1 100644 --- a/src/federation/objects/article.rs +++ b/src/federation/objects/article.rs @@ -11,8 +11,9 @@ use activitypub_federation::{ use serde::{Deserialize, Serialize}; use url::Url; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct DbArticle { + pub title: String, pub text: String, pub ap_id: ObjectId, pub instance: ObjectId, @@ -20,9 +21,14 @@ pub struct DbArticle { } impl DbArticle { - pub fn new(text: String, attributed_to: ObjectId) -> Result { + pub fn new( + title: String, + text: String, + attributed_to: ObjectId, + ) -> Result { let ap_id = generate_object_id(attributed_to.inner())?.into(); Ok(DbArticle { + title, text, ap_id, instance: attributed_to, @@ -41,6 +47,7 @@ pub struct Article { #[serde(deserialize_with = "deserialize_one_or_many")] pub(crate) to: Vec, content: String, + name: String, } #[async_trait::async_trait] @@ -69,6 +76,7 @@ impl Object for DbArticle { attributed_to: self.instance, to: vec![public(), instance.followers_url()?], content: self.text, + name: self.title, }) } @@ -83,6 +91,7 @@ impl Object for DbArticle { async fn from_json(json: Self::Kind, data: &Data) -> Result { let post = DbArticle { + title: json.name, text: json.content, ap_id: json.id, instance: json.attributed_to, diff --git a/src/federation/routes.rs b/src/federation/routes.rs index c95a18c..0c8bcee 100644 --- a/src/federation/routes.rs +++ b/src/federation/routes.rs @@ -1,5 +1,5 @@ use crate::database::DatabaseHandle; -use crate::error::Error; +use crate::error::MyResult; use crate::federation::objects::person::{DbUser, Person, PersonAcceptedActivities}; use activitypub_federation::axum::inbox::{receive_activity, ActivityData}; use activitypub_federation::axum::json::FederationJson; @@ -14,7 +14,7 @@ use axum_macros::debug_handler; pub async fn http_get_user( Path(name): Path, data: Data, -) -> Result>, Error> { +) -> MyResult>> { let db_user = data.read_user(&name)?; let json_user = db_user.into_json(&data).await?; Ok(FederationJson(WithContext::new_default(json_user))) diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..43981aa --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,52 @@ +use crate::utils::generate_object_id; +use tracing::log::LevelFilter; + +use activitypub_federation::config::FederationMiddleware; +use axum::{ + routing::{get, post}, + Router, Server, +}; + +use crate::api::api_get_article; +use crate::error::MyResult; +use crate::federation::routes::http_get_user; +use crate::federation::routes::http_post_user_inbox; +use federation::federation_config; +use std::net::ToSocketAddrs; +use tracing::info; + +mod api; +mod database; +pub mod error; +pub mod federation; +mod utils; + +pub async fn start(hostname: &str) -> MyResult<()> { + env_logger::builder() + .filter_level(LevelFilter::Warn) + .filter_module("activitypub_federation", LevelFilter::Info) + .filter_module("fediwiki", LevelFilter::Info) + .init(); + + let config = federation_config(hostname).await?; + + info!("Listening with axum on {hostname}"); + let config = config.clone(); + let app = Router::new() + // federation routes + .route("/:user/inbox", post(http_post_user_inbox)) + .route("/:user", get(http_get_user)) + // api routes + .route("/api/v1/article/:title", get(api_get_article)) + .layer(FederationMiddleware::new(config)); + + let addr = hostname + .to_socket_addrs()? + .next() + .expect("Failed to lookup domain name"); + let server = Server::bind(&addr).serve(app.into_make_service()); + + tokio::spawn(server); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index ba65eb2..782e3b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,48 +1,8 @@ -use crate::utils::generate_object_id; -use error::Error; -use tracing::log::LevelFilter; - -use activitypub_federation::config::FederationMiddleware; -use axum::{ - routing::{get, post}, - Router, Server, -}; - -use crate::federation::routes::http_get_user; -use crate::federation::routes::http_post_user_inbox; -use federation::federation_config; -use std::net::ToSocketAddrs; -use tracing::info; - -mod database; -mod error; -mod federation; -mod utils; +use fediwiki::error::MyResult; +use fediwiki::start; #[tokio::main] -async fn main() -> Result<(), Error> { - env_logger::builder() - .filter_level(LevelFilter::Warn) - .filter_module("activitypub_federation", LevelFilter::Info) - .filter_module("fediwiki", LevelFilter::Info) - .init(); - - let config = federation_config("localhost:8001").await?; - - let hostname = config.domain(); - info!("Listening with axum on {hostname}"); - let config = config.clone(); - let app = Router::new() - .route("/:user/inbox", post(http_post_user_inbox)) - .route("/:user", get(http_get_user)) - .layer(FederationMiddleware::new(config)); - - let addr = hostname - .to_socket_addrs()? - .next() - .expect("Failed to lookup domain name"); - let server = Server::bind(&addr).serve(app.into_make_service()); - - tokio::spawn(server); +pub async fn main() -> MyResult<()> { + start("localhost:8131").await?; Ok(()) } diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..16e0675 --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,22 @@ +extern crate fediwiki; +use fediwiki::federation::objects::article::DbArticle; +use fediwiki::start; + +#[tokio::test] +async fn test_get_article() { + let hostname = "localhost:8131"; + let join = tokio::task::spawn(async { + start(hostname).await.unwrap(); + }); + + let title = "Manu_Chao"; + let res: DbArticle = reqwest::get(format!("http://{hostname}/api/v1/article/{title}")) + .await + .unwrap() + .json() + .await + .unwrap(); + assert_eq!(title, res.title); + assert!(res.local); + join.abort(); +}