Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
cd2e03811e
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.
2025-07-02 10:36:30 -07:00
53679522fa
Atproto, readd collection imp from atrium 2025-06-20 09:16:27 -07:00
10 changed files with 157 additions and 45 deletions

View file

@ -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"] }

View file

@ -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

View file

@ -1,4 +1,4 @@
use crate::router::{
use router::{
Router,
Endpoint,
xrpc::{

View file

@ -3,3 +3,5 @@ pub mod types;
pub mod error;
#[cfg(feature = "sqlx-support")]
pub mod sqlx;
pub use atrium_api::types::Collection;

14
entryway/Cargo.toml Normal file
View file

@ -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

33
entryway/src/main.rs Normal file
View file

@ -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")
// }

14
router/Cargo.toml Normal file
View file

@ -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

View file

@ -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<Q>(nsid: Nsid, query: Q) -> Self
where
Q: XrpcHandler<QueryInput> + Clone
{
Endpoint::Xrpc(XrpcEndpoint::new_query(nsid,query))
}
pub fn new_xrpc_procedure<P>(nsid: Nsid, procedure: P) -> Self
where
P: XrpcHandler<ProcedureInput> + 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;
}

67
router/src/wellknown.rs Normal file
View file

@ -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<F>(handle_resolver: F) -> self where
F: Fn(atproto::types::Handle) -> Result<Option<atproto::types::Did>>
{
HandleResolutionEndpoint {
resolver: get(async move | headers: HeaderMap | -> Response {
match headers
.get("host")
.map(|s| s.parse::<atproto::types::Handle>())
.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 {
}
}

View file

@ -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)
}
}