From 53679522fa7693ea16d47c2f3e62988407f44e49 Mon Sep 17 00:00:00 2001 From: Julia Lange Date: Fri, 20 Jun 2025 09:16:27 -0700 Subject: [PATCH 1/2] Atproto, readd collection imp from atrium --- atproto/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atproto/src/lib.rs b/atproto/src/lib.rs index 53c8d32..30a53e7 100644 --- a/atproto/src/lib.rs +++ b/atproto/src/lib.rs @@ -3,3 +3,5 @@ pub mod types; pub mod error; #[cfg(feature = "sqlx-support")] pub mod sqlx; + +pub use atrium_api::types::Collection; From cd2e03811eb6dbaf56102be201864778f1eb8c5c Mon Sep 17 00:00:00 2001 From: Julia Lange Date: Wed, 2 Jul 2025 10:36:30 -0700 Subject: [PATCH 2/2] Api, split into Api, Entryway, and Router For a lil side project I need to make an Entryway, and I already have enough infrastructure here that I don't want to redo anything. --- Cargo.toml | 4 +- api/Cargo.toml | 2 +- api/src/main.rs | 2 +- entryway/Cargo.toml | 14 ++++++ entryway/src/main.rs | 33 +++++++++++++ router/Cargo.toml | 14 ++++++ api/src/router.rs => router/src/lib.rs | 42 ++++------------ router/src/wellknown.rs | 67 ++++++++++++++++++++++++++ {api/src/router => router/src}/xrpc.rs | 22 +++++---- 9 files changed, 155 insertions(+), 45 deletions(-) create mode 100644 entryway/Cargo.toml create mode 100644 entryway/src/main.rs create mode 100644 router/Cargo.toml rename api/src/router.rs => router/src/lib.rs (50%) create mode 100644 router/src/wellknown.rs rename {api/src/router => router/src}/xrpc.rs (96%) diff --git a/Cargo.toml b/Cargo.toml index c029fb0..abb5327 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,12 @@ [workspace] resolver = "3" -members = [ "api", "atproto","db", "ingestor"] +members = [ "api", "atproto", "entryway", "db", "router", "ingestor" ] [workspace.dependencies] async-trait = "0.1.88" atproto = { path = "./atproto" } +db = { path = "./db" } +router = { path = "./router" } serde = "1.0.219" serde_json = "1.0.140" sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio"] } diff --git a/api/Cargo.toml b/api/Cargo.toml index 1fc049c..5dcc6e0 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] atproto.workspace = true -axum = { version = "0.8.3", features = ["json"] } +router.workspace = true http = "1.3.1" serde.workspace = true serde_json.workspace = true diff --git a/api/src/main.rs b/api/src/main.rs index 46e17ae..13040a6 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -1,4 +1,4 @@ -use crate::router::{ +use router::{ Router, Endpoint, xrpc::{ diff --git a/entryway/Cargo.toml b/entryway/Cargo.toml new file mode 100644 index 0000000..47e68d8 --- /dev/null +++ b/entryway/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "entryway" +version = "0.1.0" +edition = "2024" + +[dependencies] +atproto.workspace = true +router.workspace = true +http = "1.3.1" +serde.workspace = true +serde_json.workspace = true +tokio.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/entryway/src/main.rs b/entryway/src/main.rs new file mode 100644 index 0000000..d8d89a0 --- /dev/null +++ b/entryway/src/main.rs @@ -0,0 +1,33 @@ +use router::{ + Router, + Endpoint, + xrpc::{ + QueryInput, + ProcedureInput, + Response, + error, + }, +}; +use atproto::types::Nsid; +use http::status::StatusCode; + +#[tokio::main] +async fn main() { + let subscriber = tracing_subscriber::FmtSubscriber::new(); + let _ = tracing::subscriber::set_global_default(subscriber); + + let mut router = Router::new(); + // let get_nsid = Nsid::new(String::from("me.woach.get")).expect("me.woach.get is a valid nsid"); + // let post_nsid = Nsid::new(String::from("me.woach.post")).expect("me.woach.post is a valid nsid"); + // router = router.add_endpoint(Endpoint::new_xrpc_query(get_nsid, test)); + // router = router.add_endpoint(Endpoint::new_xrpc_procedure(post_nsid, test2)); + router.serve().await; +} + +// async fn test(_data: QueryInput) -> Response { +// error(StatusCode::OK, "error", "message") +// } +// +// async fn test2(_data: ProcedureInput) -> Response { +// error(StatusCode::OK, "error", "message") +// } diff --git a/router/Cargo.toml b/router/Cargo.toml new file mode 100644 index 0000000..1a09bd8 --- /dev/null +++ b/router/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "router" +version = "0.1.0" +edition = "2024" + +[dependencies] +atproto.workspace = true +axum = { version = "0.8.3", features = ["json"] } +http = "1.3.1" +serde.workspace = true +serde_json.workspace = true +tokio.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/api/src/router.rs b/router/src/lib.rs similarity index 50% rename from api/src/router.rs rename to router/src/lib.rs index bfa3b17..1d97da9 100644 --- a/api/src/router.rs +++ b/router/src/lib.rs @@ -1,53 +1,27 @@ -use crate::router::xrpc::{ - XrpcEndpoint, - XrpcHandler, - QueryInput, - ProcedureInput, -}; -use atproto::Nsid; +use crate::xrpc::XrpcEndpoint; use axum::Router as AxumRouter; use core::net::SocketAddr; use std::net::{IpAddr, Ipv4Addr}; use tokio::net::TcpListener; +pub mod xrpc; +pub mod wellknown; + pub struct Router { addr: SocketAddr, router: AxumRouter, } - -// In case server ever needs to support more than just XRPC -pub enum Endpoint { - Xrpc(XrpcEndpoint), -} -impl Endpoint { - pub fn new_xrpc_query(nsid: Nsid, query: Q) -> Self - where - Q: XrpcHandler + Clone - { - Endpoint::Xrpc(XrpcEndpoint::new_query(nsid,query)) - } - pub fn new_xrpc_procedure

(nsid: Nsid, procedure: P) -> Self - where - P: XrpcHandler + Clone - { - Endpoint::Xrpc(XrpcEndpoint::new_procedure(nsid,procedure)) - } -} - -pub mod xrpc; - impl Router { pub fn new() -> Self { let mut router = AxumRouter::new(); + // TODO: Only add if there is at least on XRPC endpoint router = XrpcEndpoint::not_implemented().add_to_router(router); let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), 6702); Router { router, addr } } pub fn add_endpoint(mut self, endpoint: Endpoint) -> Self { - match endpoint { - Endpoint::Xrpc(ep) => self.router = ep.add_to_router(self.router), - }; + self.router = endpoint.add_to_router(self.router); self } @@ -57,3 +31,7 @@ impl Router { axum::serve(listener, self.router).await.unwrap(); } } + +pub trait Endpoint { + fn add_to_router(self, router: AxumRouter) -> AxumRouter; +} diff --git a/router/src/wellknown.rs b/router/src/wellknown.rs new file mode 100644 index 0000000..fce8f78 --- /dev/null +++ b/router/src/wellknown.rs @@ -0,0 +1,67 @@ +use crate::Endpoint; +use axum::{ + routing::method_routing::MethodRouter, + Router as axumRouter, +}; + +trait WellKnownEndpoint { + fn get_known_route(&self) -> String; + fn get_resolver(self) -> MethodRouter; +} + +impl Endpoint for WellKnownEndpoint { + fn add_to_router(self, router: axumRouter) -> axumRouter { + router.route(".well-known/" + self.get_known_route(), self.get_resolver()) + } +} + +pub mod atproto { + pub mod handle_resolution { + use crate::wellknown::WellKnownEndpoint; + use axum::{ + routing::method_routing::MethodRouter, + response::Response, + http::{StatusCode, HeaderMap}, + }; + + pub struct HandleResolutionEndpoint { + resolver: MethodRouter, + } + + impl HandleResolutionEndpoint { + pub fn new(handle_resolver: F) -> self where + F: Fn(atproto::types::Handle) -> Result> + { + HandleResolutionEndpoint { + resolver: get(async move | headers: HeaderMap | -> Response { + match headers + .get("host") + .map(|s| s.parse::()) + .map(handle_resolver) { + Ok(maybe_did) => match maybe_did { + Some(did) => (StatusCode::OK, did), + None => (StatusCode::NOT_FOUND, "User not found") + }, + Err(_) => + (StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error"), + } + }) + } + } + } + + impl WellKnownEndpoint for HandleResolutionEndpoint { + fn get_known_route(&self) -> String { String::from("atproto-did") } + + fn get_resolver(self) -> MethodRouter { + return self.resolver; + } + } + } +} + +pub mod oauth { + mod protected_resource {} + pub mod authorization_server { + } +} diff --git a/api/src/router/xrpc.rs b/router/src/xrpc.rs similarity index 96% rename from api/src/router/xrpc.rs rename to router/src/xrpc.rs index 500f331..739fd79 100644 --- a/api/src/router/xrpc.rs +++ b/router/src/xrpc.rs @@ -1,9 +1,10 @@ +use crate::Endpoint; use std::{ collections::HashMap, pin::Pin, future::Future, }; -use atproto::Nsid; +use atproto::types::Nsid; use axum::{ extract::{ Json, @@ -154,15 +155,6 @@ impl XrpcEndpoint { } } - pub fn add_to_router(self, router: axumRouter) -> axumRouter { - let path = match self.path { - Path::Nsid(nsid) => &("/xrpc/".to_owned() + nsid.as_str()), - Path::NotImplemented => "/xrpc/{*nsid}", - }; - - router.route(path, self.resolver) - } - pub fn not_implemented() -> Self { let resolver = ( StatusCode::NOT_IMPLEMENTED, @@ -179,3 +171,13 @@ impl XrpcEndpoint { } } +impl Endpoint for XrpcEndpoint { + fn add_to_router(self, router: axumRouter) -> axumRouter { + let path = match self.path { + Path::Nsid(nsid) => &("/xrpc/".to_owned() + nsid.as_str()), + Path::NotImplemented => "/xrpc/{*nsid}", + }; + + router.route(path, self.resolver) + } +}