More macros
This commit is contained in:
parent
edc21b4403
commit
21b47409f1
3 changed files with 63 additions and 32 deletions
|
@ -29,6 +29,46 @@ macro_rules! fuck {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes a response.
|
||||||
|
macro_rules! respond {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
crate::api::Resp {
|
||||||
|
$($arg)*,
|
||||||
|
.. crate::api::Resp::default()
|
||||||
|
}.into()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters for a response
|
||||||
|
struct Resp<'s> {
|
||||||
|
body: Option<&'s Value>,
|
||||||
|
kind: &'s str,
|
||||||
|
code: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> Default for Resp<'s> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Resp {
|
||||||
|
body: None,
|
||||||
|
kind: "application/json",
|
||||||
|
code: 200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Resp<'a>> for Response {
|
||||||
|
fn from(Resp { body, kind, code }: Resp<'_>) -> Response {
|
||||||
|
let resp = Response::<()>::builder()
|
||||||
|
.status(code)
|
||||||
|
.header("content-type", kind);
|
||||||
|
resp.body(match body {
|
||||||
|
Some(data) => Full::new(serde_json::to_vec(&data).unwrap().into()),
|
||||||
|
None => Full::new(Bytes::default()),
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod ap;
|
pub mod ap;
|
||||||
pub mod wf;
|
pub mod wf;
|
||||||
|
|
||||||
|
@ -205,23 +245,6 @@ fn with_json(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A quick, simple way to construct a response.
|
|
||||||
fn respond<const N: usize>(
|
|
||||||
status: u16,
|
|
||||||
body: Option<impl Into<Bytes>>,
|
|
||||||
headers: [(&str, &str); N],
|
|
||||||
) -> Response {
|
|
||||||
let mut resp = Response::<()>::builder().status(status);
|
|
||||||
for (name, data) in headers {
|
|
||||||
resp = resp.header(name, data);
|
|
||||||
}
|
|
||||||
resp.body(match body {
|
|
||||||
Some(bytes) => Full::new(bytes.into()),
|
|
||||||
None => Full::new(Bytes::default()),
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
mod error {
|
mod error {
|
||||||
//! Pre-baked error responses.
|
//! Pre-baked error responses.
|
||||||
|
|
||||||
|
@ -261,10 +284,13 @@ mod error {
|
||||||
}
|
}
|
||||||
/// Check whether the requester wants json from us.
|
/// Check whether the requester wants json from us.
|
||||||
pub fn accepts_json(&self) -> bool {
|
pub fn accepts_json(&self) -> bool {
|
||||||
|
fn is_json((k, v): (&str, &str)) -> bool {
|
||||||
|
k == "application" && v.split('+').any(|p| p == "json")
|
||||||
|
}
|
||||||
self.accept
|
self.accept
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s| s.split_once('/'))
|
.filter_map(|s| s.split_once('/'))
|
||||||
.any(|(k, v)| k == "application" && v.split('+').any(|p| p == "json"))
|
.any(is_json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,19 @@ use puppy::{
|
||||||
actor::{get_signing_key, Actor},
|
actor::{get_signing_key, Actor},
|
||||||
get_local_ap_object, Context, Error, Key,
|
get_local_ap_object, Context, Error, Key,
|
||||||
};
|
};
|
||||||
use serde_json::{to_string, Value};
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::sig::{Signer, Verifier};
|
use crate::sig::{Signer, Verifier};
|
||||||
use super::{error::Message, respond, Response};
|
use super::{error::Message, Response};
|
||||||
|
|
||||||
/// Proxy a request through the instance.
|
/// Proxy a request through the instance.
|
||||||
pub async fn proxy(cx: &Context, params: &[(&str, &str)]) -> Result<Response, Message> {
|
pub async fn proxy(cx: &Context, params: &[(&str, &str)]) -> Result<Response, Message> {
|
||||||
// Extract our query parameters.
|
// Extract our query parameters.
|
||||||
let Some(user) = params.iter().find_map(|(k, v)| (*k == "user").then_some(v)) else {
|
let Some(user) = params.iter().find_map(|(k, v)| (*k == "user").then_some(v)) else {
|
||||||
fuck!(400: "Expected `user` query param");
|
fuck!(400: "expected `user` query param");
|
||||||
};
|
};
|
||||||
let Some(url) = params.iter().find_map(|(k, v)| (*k == "url").then_some(v)) else {
|
let Some(url) = params.iter().find_map(|(k, v)| (*k == "url").then_some(v)) else {
|
||||||
fuck!(400: "Expected `url` query param");
|
fuck!(400: "expected `url` query param");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Look up the actor's key in the store (which is accessible through the puppy context).
|
// Look up the actor's key in the store (which is accessible through the puppy context).
|
||||||
|
@ -48,19 +48,22 @@ pub fn serve_object(cx: &Context, object_ulid: &str) -> Result<Response, Message
|
||||||
let Ok(parsed) = object_ulid.parse::<Key>() else {
|
let Ok(parsed) = object_ulid.parse::<Key>() else {
|
||||||
fuck!(400: "improperly formatted ulid");
|
fuck!(400: "improperly formatted ulid");
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = cx.run(|tx| get_local_ap_object(&tx, parsed));
|
let result = cx.run(|tx| get_local_ap_object(&tx, parsed));
|
||||||
let Ok(object) = result else {
|
let Ok(object) = result else {
|
||||||
fuck!(404: "object does not exist");
|
fuck!(404: "object does not exist");
|
||||||
};
|
};
|
||||||
let json = to_string(&object.to_json_ld()).unwrap();
|
|
||||||
Ok(respond(200, Some(json), [AP_CONTENT_TYPE]))
|
|
||||||
}
|
|
||||||
|
|
||||||
const AP_CONTENT_TYPE: (&str, &str) = ("content-type", "application/activity+json");
|
Ok(respond! {
|
||||||
|
kind: "application/activity+json",
|
||||||
|
body: Some(&object.to_json_ld())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Serve the special actor used for signing requests.
|
/// Serve the special actor used for signing requests.
|
||||||
pub fn serve_verifier_actor(verifier: &Verifier) -> Response {
|
pub fn serve_verifier_actor(verifier: &Verifier) -> Response {
|
||||||
let body = verifier.to_json_ld();
|
respond! {
|
||||||
let encoded = serde_json::to_vec(&body).unwrap();
|
kind: "application/activity+json",
|
||||||
respond(200, Some(encoded), [AP_CONTENT_TYPE])
|
body: Some(&verifier.to_json_ld())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use puppy::{
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use derive_more::Display;
|
use derive_more::Display;
|
||||||
|
|
||||||
use super::{error::Message, respond, Response};
|
use super::{error::Message, Response};
|
||||||
|
|
||||||
const WF_CONTENT_TYPE: (&str, &str) = ("content-type", "application/jrd+json");
|
const WF_CONTENT_TYPE: (&str, &str) = ("content-type", "application/jrd+json");
|
||||||
|
|
||||||
|
@ -23,8 +23,10 @@ pub fn resolve(cx: &Context, params: &[(&str, &str)]) -> Result<Response, Messag
|
||||||
fuck!(500: "internal error");
|
fuck!(500: "internal error");
|
||||||
};
|
};
|
||||||
let jrd = make_jrd(handle, &id);
|
let jrd = make_jrd(handle, &id);
|
||||||
let encoded = serde_json::to_vec(&jrd).unwrap();
|
Ok(respond! {
|
||||||
Ok(respond(200, Some(encoded), [WF_CONTENT_TYPE]))
|
body: Some(&jrd),
|
||||||
|
kind: "application/jrd+json"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Some(_) | None => fuck!(400: "missing/invalid resource param"),
|
Some(_) | None => fuck!(400: "missing/invalid resource param"),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue