Atproto, Router, add atproto api mod with Nsid

Sets up a generic atproto module to store atproto implementation. Mainly
doing this so that I can switch between rsky/atrium as well as add my
own layers on top.

This also switches the old Xrpc/Router use of Nsid to the atproto api
implementation of it. Next up is the DB where I'll need a bunch of
these.
This commit is contained in:
Julia Lange 2025-04-25 13:52:02 -07:00
parent d4a3a71e2f
commit db33099405
Signed by: Julia
SSH key fingerprint: SHA256:50XUMcOFYPUs9/1j7p9SPnwASZ7QnxXm7THF7HkbqzQ
6 changed files with 858 additions and 32 deletions

830
rust/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,9 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
atrium-api = { version = "0.25.2", default-features = false }
axum = { version = "0.8.3", features = ["json"] } axum = { version = "0.8.3", features = ["json"] }
axum-macros = "0.5.0" axum-macros = "0.5.0"
http = "1.3.1"
serde = "1.0.219" serde = "1.0.219"
serde_json = "1.0.140" serde_json = "1.0.140"
sqlx = { version = "0.8.5", features = ["runtime-tokio"] } sqlx = { version = "0.8.5", features = ["postgres", "runtime-tokio"] }
tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] }

1
rust/src/atproto.rs Normal file
View file

@ -0,0 +1 @@
pub use atrium_api::types::string::Nsid;

View file

@ -1,4 +1,6 @@
use crate::router::{ use crate::{
atproto::Nsid,
router::{
Router, Router,
Endpoint, Endpoint,
xrpc::{ xrpc::{
@ -7,18 +9,21 @@ use crate::router::{
Response, Response,
error, error,
}, },
},
}; };
use axum::http::StatusCode; use http::status::StatusCode;
mod atproto;
mod router; mod router;
mod db; mod db;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let mut router = Router::new(); let mut router = Router::new();
router = router.add_endpoint(Endpoint::new_xrpc_query(String::from("me.woach.get"), test)); let get_nsid = Nsid::new(String::from("me.woach.get")).expect("me.woach.get is a valid nsid");
router = router.add_endpoint(Endpoint::new_xrpc_procedure(String::from("me.woach.post"), test2)); 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; router.serve().await;
} }

View file

@ -1,8 +1,11 @@
use crate::router::xrpc::{ use crate::{
atproto::Nsid,
router::xrpc::{
XrpcEndpoint, XrpcEndpoint,
XrpcHandler, XrpcHandler,
QueryInput, QueryInput,
ProcedureInput, ProcedureInput,
}
}; };
use axum::Router as AxumRouter; use axum::Router as AxumRouter;
use core::net::SocketAddr; use core::net::SocketAddr;
@ -19,13 +22,13 @@ pub enum Endpoint {
Xrpc(XrpcEndpoint), Xrpc(XrpcEndpoint),
} }
impl Endpoint { impl Endpoint {
pub fn new_xrpc_query<Q>(nsid: String, query: Q) -> Self pub fn new_xrpc_query<Q>(nsid: Nsid, query: Q) -> Self
where where
Q: XrpcHandler<QueryInput> + Clone Q: XrpcHandler<QueryInput> + Clone
{ {
Endpoint::Xrpc(XrpcEndpoint::new_query(nsid,query)) Endpoint::Xrpc(XrpcEndpoint::new_query(nsid,query))
} }
pub fn new_xrpc_procedure<P>(nsid: String, procedure: P) -> Self pub fn new_xrpc_procedure<P>(nsid: Nsid, procedure: P) -> Self
where where
P: XrpcHandler<ProcedureInput> + Clone P: XrpcHandler<ProcedureInput> + Clone
{ {

View file

@ -1,3 +1,4 @@
use crate::atproto::Nsid;
use std::{ use std::{
collections::HashMap, collections::HashMap,
pin::Pin, pin::Pin,
@ -26,13 +27,13 @@ use axum::{
}; };
use serde_json::{Value, json}; use serde_json::{Value, json};
enum Nsid { enum Path {
Nsid(String), Nsid(Nsid),
NotImplemented, NotImplemented,
} }
pub struct XrpcEndpoint { pub struct XrpcEndpoint {
nsid: Nsid, path: Path,
resolver: MethodRouter, resolver: MethodRouter,
} }
@ -123,12 +124,12 @@ where
} }
impl XrpcEndpoint { impl XrpcEndpoint {
pub fn new_query<Q>(nsid: String, query: Q) -> Self pub fn new_query<Q>(nsid: Nsid, query: Q) -> Self
where where
Q: XrpcHandler<QueryInput> + Clone Q: XrpcHandler<QueryInput> + Clone
{ {
XrpcEndpoint { XrpcEndpoint {
nsid: Nsid::Nsid(nsid), path: Path::Nsid(nsid),
resolver: get(async move | mut parts: Parts | -> Response { resolver: get(async move | mut parts: Parts | -> Response {
match QueryInput::from_request_parts(&mut parts, &()).await { match QueryInput::from_request_parts(&mut parts, &()).await {
Ok(qi) => query.call(qi).await, Ok(qi) => query.call(qi).await,
@ -138,12 +139,12 @@ impl XrpcEndpoint {
} }
} }
pub fn new_procedure<P>(nsid: String, procedure: P) -> Self pub fn new_procedure<P>(nsid: Nsid, procedure: P) -> Self
where where
P: XrpcHandler<ProcedureInput> + Clone P: XrpcHandler<ProcedureInput> + Clone
{ {
XrpcEndpoint { XrpcEndpoint {
nsid: Nsid::Nsid(nsid), path: Path::Nsid(nsid),
resolver: post(async move | req: Request | -> Response { resolver: post(async move | req: Request | -> Response {
match ProcedureInput::from_request(req, &()).await { match ProcedureInput::from_request(req, &()).await {
Ok(pi) => procedure.call(pi).await, Ok(pi) => procedure.call(pi).await,
@ -154,9 +155,9 @@ impl XrpcEndpoint {
} }
pub fn add_to_router(self, router: axumRouter) -> axumRouter { pub fn add_to_router(self, router: axumRouter) -> axumRouter {
let path = match self.nsid { let path = match self.path {
Nsid::Nsid(s) => &("/xrpc/".to_owned() + &s), Path::Nsid(nsid) => &("/xrpc/".to_owned() + nsid.as_str()),
Nsid::NotImplemented => "/xrpc/{*nsid}", Path::NotImplemented => "/xrpc/{*nsid}",
}; };
router.route(path, self.resolver) router.route(path, self.resolver)
@ -172,7 +173,7 @@ impl XrpcEndpoint {
); );
XrpcEndpoint { XrpcEndpoint {
nsid: Nsid::NotImplemented, path: Path::NotImplemented,
resolver: get(resolver.clone()).post(resolver), resolver: get(resolver.clone()).post(resolver),
} }
} }