use std::collections::HashMap; use flabk_derive::LD; use serde::{Deserialize, Serialize}; use crate::astreams::resolve::Resolvable; use self::{ resolve::ResolveError, serde_ext::{expand_partial, expand_partial_into_vec, into_vec}, }; pub mod context; pub mod resolve; mod serde_ext; #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub enum ObjectKind { Article, Audio, Document, Event, Image, Note, Page, Place, Profile, Relationship, Tombstone, Video, } #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub enum ActivityKind { Accept, Add, Announce, Arrive, Block, Create, Delete, Dislike, Flag, Follow, Invite, Join, Leave, Like, Listen, Move, Offer, Question, Reject, Read, Remove, TentativeReject, TentativeAccept, Travel, Undo, Update, View, } #[derive(Debug, Clone)] pub enum ExpandError { InvalidKind(Option), NoAttribution, ResolveIRI(String), Other(String), } impl From for ExpandError { fn from(err: ResolveError) -> Self { Self::ResolveIRI(err.0) } } /// A Collection is a subtype of Object that /// represents ordered or unordered sets of /// Object or Link instances. #[derive(Debug, Clone, Deserialize)] pub struct Collection { pub summary: Option, #[serde(rename = "type")] pub kind: String, #[serde(rename = "totalItems")] pub total_items: Vec, } #[derive(Debug, Clone, Deserialize)] pub struct Attachment { #[serde(rename = "type")] pub kind: String, pub content: Option, pub url: String, } // TODO: maybe this can work as attachment w/ the ID being more like // the LD IDs? #[derive(Debug, Clone, Deserialize)] pub struct Image { #[serde(flatten)] pub base: ObjectBase, #[serde(rename = "type")] pub kind: Option, pub id: String, #[serde(deserialize_with = "into_vec")] pub url: Vec, } #[derive(Debug, Clone, Deserialize)] pub struct Audience { #[serde(rename = "type")] pub kind: String, pub name: String, } #[derive(Clone, Copy, Debug, Deserialize)] pub enum Unit { #[serde(rename = "m")] Meters, } #[derive(Debug, Clone, Deserialize)] pub struct Location { #[serde(rename = "type")] pub kind: String, pub name: String, pub longitude: Option, pub latitude: Option, pub altitude: Option, pub units: Unit, } #[derive(Debug, Clone, Deserialize)] pub struct Preview { #[serde(rename = "type")] pub kind: String, pub name: String, pub duration: Option, pub url: Link, } #[derive(Debug, Clone, Deserialize)] pub struct APResult { #[serde(rename = "type")] pub kind: String, pub name: String, } /// ObjectBase contains base Activity Streams /// members that all objects should have. Except kind. /// /// This object is intended to be used by inlining it into /// other serializable/deserializable objects. #[derive(Debug, Clone, Deserialize, Default)] #[serde(rename_all = "camelCase")] pub struct ObjectBase { // #[serde(rename = "@context")] // #[serde(deserialize_with = "expand_partial")] // pub ap_context: APContext, pub name: Option, pub name_map: Option>, #[serde(deserialize_with = "into_vec", default = "Vec::new")] pub attachment: Vec, #[serde(deserialize_with = "expand_partial_into_vec")] pub attributed_to: Vec, pub audience: Option, pub media_type: Option, pub content: Option, pub content_map: Option>, pub context: Option, pub start_time: Option, pub end_time: Option, pub generator: Option, #[serde(deserialize_with = "into_vec", default = "Vec::new")] pub icon: Vec, // omit in_reply_to pub location: Option, pub preview: Option, pub published: Option, pub updated: Option, pub replies: Option>, // TODO: type pub summary: Option, pub summary_map: Option>, #[serde(deserialize_with = "expand_partial_into_vec", default = "Vec::new")] pub tag: Vec, // omit url for now: need to merge into_vec & expand_partial #[serde(deserialize_with = "into_vec", default = "Vec::new")] pub to: Vec, #[serde(deserialize_with = "into_vec", default = "Vec::new")] pub bto: Vec, #[serde(deserialize_with = "into_vec", default = "Vec::new")] pub cc: Vec, #[serde(deserialize_with = "into_vec", default = "Vec::new")] pub bcc: Vec, pub duration: Option, } #[derive(Debug, Clone, Deserialize, LD, Default)] pub struct Object { #[serde(flatten)] pub base: ObjectBase, #[serde(rename = "type")] pub kind: Option, pub id: String, } #[derive(Debug, Clone, Deserialize)] pub struct Link { #[serde(rename = "type")] pub kind: Option, pub name: Option, pub href: String, #[serde(rename = "hreflang")] pub href_lang: Option, #[serde(rename = "mediaType")] pub media_type: Option, pub height: u32, pub width: u32, } /// An Activity is a subtype of Object that describes /// some form of action that may happen, /// is currently happening, or has already happened. /// /// The Activity type itself serves as an abstract base type /// for all types of activities. /// It is important to note that the Activity type itself /// does not carry any specific semantics about the kind of action being taken. #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Activity { #[serde(flatten)] pub base: ObjectBase, #[serde(rename = "type")] pub kind: Option, pub id: String, #[serde(deserialize_with = "expand_partial")] pub actor: Option, #[serde(deserialize_with = "expand_partial")] pub object: Option, pub result: Option, pub target: Option, pub origin: Option, pub instrument: Option, } /// Instances of IntransitiveActivity are a subtype of Activity /// representing intransitive actions. #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct IntransitiveActivity { #[serde(flatten)] pub base: ObjectBase, #[serde(rename = "type")] pub kind: Option, pub id: String, #[serde(deserialize_with = "expand_partial")] pub actor: Option, pub result: Option, pub target: Option, pub origin: Option, pub instrument: Option, } pub enum ActorType { Application, Group, Organization, Person, Service, } #[derive(Debug, Clone, Deserialize)] pub struct Basic { #[serde(rename = "type")] pub kind: Option, pub name: Option, } #[derive(Debug, Clone, Deserialize, LD, Default)] pub struct Actor { pub id: String, #[serde(rename = "type")] pub kind: Option, #[serde(rename = "attributedTo")] pub attributed_to: Option, pub published: Option, pub content: Option, pub context: Option, pub conversation: Option, pub url: Option, #[serde(rename = "to")] #[serde(deserialize_with = "into_vec")] pub to_uris: Vec, } pub async fn test() { let obj = r#"{ "@context": "https://www.w3.org/ns/activitystreams", "attributedTo": "http://localhost:3001/u/test", "content": "honk donk", "context": "data:,electrichonkytonk-2jqQ42HyJXctnBKTy1", "conversation": "data:,electrichonkytonk-2jqQ42HyJXctnBKTy1", "id": "htts://localhost:3001/u/test/h/6Q8BFF8W6PZT2ddngZ", "published": "2022-09-30T19:04:45Z", "summary": "", "to": "https://www.w3.org/ns/activitystreams#Public", "type": "Note", "url": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ" }"#; let obj = serde_json::from_str::(obj).unwrap(); println!(); println!("{:#?}", obj); }