Plume/src/activity_pub/mod.rs

119 lines
3.3 KiB
Rust
Raw Normal View History

2018-05-18 10:04:40 +02:00
use activitystreams_traits::{Activity, Actor, Object, Link};
2018-05-16 20:20:44 +02:00
use array_tool::vec::Uniq;
use diesel::PgConnection;
use reqwest::Client;
2018-05-19 09:39:59 +02:00
use rocket::{
http::{ContentType, Status},
response::{Response, Responder, Content},
request::Request
};
2018-04-24 14:31:02 +02:00
use rocket_contrib::Json;
use serde_json;
2018-05-16 20:20:44 +02:00
use self::sign::Signable;
2018-04-24 11:21:39 +02:00
pub mod actor;
2018-05-01 16:00:29 +02:00
pub mod inbox;
pub mod object;
2018-05-04 17:18:00 +02:00
pub mod request;
2018-04-29 19:49:56 +02:00
pub mod sign;
2018-04-24 10:35:45 +02:00
pub mod webfinger;
2018-04-24 14:31:02 +02:00
pub type ActivityPub = Content<Json>;
pub const CONTEXT_URL: &'static str = "https://www.w3.org/ns/activitystreams";
2018-04-30 18:50:35 +02:00
pub const PUBLIC_VISIBILTY: &'static str = "https://www.w3.org/ns/activitystreams#Public";
2018-04-24 14:31:02 +02:00
#[cfg(debug_assertions)]
pub fn ap_url(url: String) -> String {
format!("http://{}", url)
}
#[cfg(not(debug_assertions))]
pub fn ap_url(url: String) -> String {
format!("https://{}", url)
}
2018-04-24 14:31:02 +02:00
pub fn context() -> serde_json::Value {
json!([
2018-04-29 19:49:56 +02:00
CONTEXT_URL,
2018-04-24 14:31:02 +02:00
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"sensitive": "as:sensitive",
"movedTo": "as:movedTo",
"Hashtag": "as:Hashtag",
"ostatus":"http://ostatus.org#",
"atomUri":"ostatus:atomUri",
"inReplyToAtomUri":"ostatus:inReplyToAtomUri",
"conversation":"ostatus:conversation",
"toot":"http://joinmastodon.org/ns#",
"Emoji":"toot:Emoji",
"focalPoint": {
"@container":"@list",
"@id":"toot:focalPoint"
},
"featured":"toot:featured"
}
])
}
pub fn activity_pub(json: serde_json::Value) -> ActivityPub {
2018-04-24 14:31:02 +02:00
Content(ContentType::new("application", "activity+json"), Json(json))
}
2018-05-16 20:20:44 +02:00
pub struct ActivityStream<T> (T);
impl<T> ActivityStream<T> {
pub fn new(t: T) -> ActivityStream<T> {
ActivityStream(t)
}
}
impl<'r, O: Object> Responder<'r> for ActivityStream<O> {
fn respond_to(self, request: &Request) -> Result<Response<'r>, Status> {
serde_json::to_string(&self.0).respond_to(request)
}
}
2018-05-18 10:04:40 +02:00
pub fn broadcast<A: Activity + Clone, S: sign::Signer, T: inbox::WithInbox + Actor>(conn: &PgConnection, sender: &S, act: A, to: Vec<T>) {
2018-05-16 20:20:44 +02:00
let boxes = to.into_iter()
.map(|u| u.get_shared_inbox_url().unwrap_or(u.get_inbox_url()))
.collect::<Vec<String>>()
.unique();
for inbox in boxes {
// TODO: run it in Sidekiq or something like that
let mut act = serde_json::to_value(act.clone()).unwrap();
act["@context"] = context();
let signed = act.sign(sender, conn);
let res = Client::new()
.post(&inbox[..])
.headers(request::headers())
.header(request::signature(sender, request::headers(), conn))
.header(request::digest(signed.to_string()))
.body(signed.to_string())
.send();
match res {
Ok(mut r) => println!("Successfully sent activity to inbox ({})\n\n{:?}", inbox, r.text().unwrap()),
Err(e) => println!("Error while sending to inbox ({:?})", e)
}
}
}
2018-05-19 00:04:30 +02:00
#[derive(Clone, Serialize, Deserialize)]
2018-05-19 11:50:56 +02:00
pub struct Id(String);
2018-05-16 20:20:44 +02:00
impl Id {
pub fn new<T: Into<String>>(id: T) -> Id {
2018-05-19 11:50:56 +02:00
Id(id.into())
2018-05-16 20:20:44 +02:00
}
}
2018-05-18 10:04:40 +02:00
pub trait IntoId {
2018-05-19 00:04:30 +02:00
fn into_id(self) -> Id;
2018-05-18 10:04:40 +02:00
}
2018-05-16 20:20:44 +02:00
impl Link for Id {}