merge in old new type defs
This commit is contained in:
parent
de12258368
commit
5473512787
|
@ -1,24 +1,63 @@
|
||||||
use async_trait::async_trait;
|
use std::collections::HashMap;
|
||||||
use flabk_derive::IRI;
|
|
||||||
|
use flabk_derive::{Resolvable, IRI};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
context::Context,
|
context::APContext,
|
||||||
note::Note,
|
|
||||||
resolve::ResolveError,
|
resolve::ResolveError,
|
||||||
serde_ext::{expand_partial, pull_single_into_vec},
|
serde_ext::{expand_partial, into_vec},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod note;
|
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
mod serde_ext;
|
mod serde_ext;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||||
pub enum ActivityKind {
|
pub enum ObjectKind {
|
||||||
Create,
|
Article,
|
||||||
Like,
|
Audio,
|
||||||
|
Document,
|
||||||
|
Event,
|
||||||
|
Image,
|
||||||
Note,
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -35,45 +74,211 @@ impl From<ResolveError> for ExpandError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
/// A Collection is a subtype of Object that
|
||||||
pub trait ExpandLD<T> {
|
/// represents ordered or unordered sets of
|
||||||
async fn expand(obj: &ObjectLD) -> Result<T, ExpandError>;
|
/// Object or Link instances.
|
||||||
}
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct Collection<T> {
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
pub summary: Option<String>,
|
||||||
pub struct ActivityLD {
|
#[serde(rename = "type")]
|
||||||
#[serde(rename = "@context")]
|
pub kind: String,
|
||||||
pub context_uri: String,
|
#[serde(rename = "totalItems")]
|
||||||
pub kind: ActivityKind,
|
pub total_items: Vec<T>,
|
||||||
#[serde(rename = "actor")]
|
|
||||||
pub actor_uri: String,
|
|
||||||
#[serde(rename = "to")]
|
|
||||||
pub to_uris: Vec<String>,
|
|
||||||
pub object: Option<ObjectLD>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
pub struct Attachment {
|
||||||
pub struct Activity {
|
|
||||||
// #[serde(rename = "@context")]
|
|
||||||
// #[serde(deserialize_with = "expand_partial")]
|
|
||||||
// pub ap_context: Context,
|
|
||||||
pub id: String,
|
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub kind: ActivityKind,
|
pub kind: String,
|
||||||
#[serde(deserialize_with = "expand_partial")]
|
|
||||||
pub attributed_to: Actor,
|
|
||||||
pub content: Option<String>,
|
pub content: Option<String>,
|
||||||
pub context: Option<String>,
|
pub url: String,
|
||||||
#[serde(deserialize_with = "pull_single_into_vec")]
|
|
||||||
pub to: Vec<String>,
|
|
||||||
pub url: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
// TODO: maybe this can work as attachment w/ the ID being more like
|
||||||
pub struct ObjectLD {
|
// the LD IDs?
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct Image {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub base: ObjectBase,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: Option<ObjectKind>,
|
||||||
|
pub id: String,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub url: Vec<Link>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<f64>,
|
||||||
|
pub latitude: Option<f64>,
|
||||||
|
pub altitude: Option<f64>,
|
||||||
|
pub units: Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct Preview {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: String,
|
||||||
|
pub name: String,
|
||||||
|
pub duration: Option<String>,
|
||||||
|
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(rename = "@context")]
|
||||||
pub context_uri: Option<String>,
|
#[serde(deserialize_with = "expand_partial")]
|
||||||
|
pub ap_context: APContext,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub name_map: Option<HashMap<String, String>>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub attachment: Vec<Attachment>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub attributed_to: Vec<Actor>,
|
||||||
|
pub audience: Option<Audience>,
|
||||||
|
pub media_type: Option<String>,
|
||||||
|
pub content: Option<String>,
|
||||||
|
pub content_map: Option<HashMap<String, String>>,
|
||||||
|
pub context: Option<String>,
|
||||||
|
pub start_time: Option<String>,
|
||||||
|
pub end_time: Option<String>,
|
||||||
|
pub generator: Option<Actor>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub icon: Vec<Link>,
|
||||||
|
// omit in_reply_to
|
||||||
|
pub location: Option<Location>,
|
||||||
|
pub preview: Option<Preview>,
|
||||||
|
pub published: Option<String>,
|
||||||
|
pub updated: Option<String>,
|
||||||
|
pub replies: Option<Collection<()>>, // TODO: type
|
||||||
|
pub summary: Option<String>,
|
||||||
|
pub summary_map: Option<HashMap<String, String>>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub tag: Vec<Actor>,
|
||||||
|
// omit url for now: need to merge into_vec & expand_partial
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub to: Vec<String>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub bto: Vec<String>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub cc: Vec<String>,
|
||||||
|
#[serde(deserialize_with = "into_vec")]
|
||||||
|
pub bcc: Vec<String>,
|
||||||
|
pub duration: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Resolvable, IRI, Default)]
|
||||||
|
pub struct Object {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub base: ObjectBase,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: Option<ObjectKind>,
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct Link {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: Option<ActivityKind>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub href: String,
|
||||||
|
#[serde(rename = "hreflang")]
|
||||||
|
pub href_lang: Option<String>,
|
||||||
|
#[serde(rename = "mediaType")]
|
||||||
|
pub media_type: Option<String>,
|
||||||
|
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, Resolvable)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Activity {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub base: ObjectBase,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: Option<ActivityKind>,
|
||||||
|
pub id: String,
|
||||||
|
#[serde(deserialize_with = "expand_partial")]
|
||||||
|
pub actor: Option<Actor>,
|
||||||
|
#[serde(deserialize_with = "expand_partial")]
|
||||||
|
pub object: Option<Object>,
|
||||||
|
pub result: Option<APResult>,
|
||||||
|
pub target: Option<Basic>,
|
||||||
|
pub origin: Option<Basic>,
|
||||||
|
pub instrument: Option<Basic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instances of IntransitiveActivity are a subtype of Activity
|
||||||
|
/// representing intransitive actions.
|
||||||
|
#[derive(Debug, Clone, Deserialize, Resolvable)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct IntransitiveActivity {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub base: ObjectBase,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: Option<ActivityKind>,
|
||||||
|
pub id: String,
|
||||||
|
#[serde(deserialize_with = "expand_partial")]
|
||||||
|
pub actor: Option<Actor>,
|
||||||
|
pub result: Option<APResult>,
|
||||||
|
pub target: Option<Basic>,
|
||||||
|
pub origin: Option<Basic>,
|
||||||
|
pub instrument: Option<Basic>,
|
||||||
|
}
|
||||||
|
pub enum ActorType {
|
||||||
|
Application,
|
||||||
|
Group,
|
||||||
|
Organization,
|
||||||
|
Person,
|
||||||
|
Service,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct Basic {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: Option<ActivityKind>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, IRI, Default, Resolvable)]
|
||||||
|
pub struct Actor {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub kind: Option<ActivityKind>,
|
pub kind: Option<ActivityKind>,
|
||||||
|
@ -117,7 +322,7 @@ pub async fn test() {
|
||||||
"url": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ"
|
"url": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ"
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
let obj = serde_json::from_str::<Activity>(obj).unwrap();
|
let obj = serde_json::from_str::<Object>(obj).unwrap();
|
||||||
println!();
|
println!();
|
||||||
println!("{:#?}", obj);
|
println!("{:#?}", obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
context::{self, Context},
|
|
||||||
resolve, ActivityKind, Actor, ExpandError, ExpandLD, ObjectLD,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Note {
|
|
||||||
pub id: String,
|
|
||||||
pub content: Option<String>,
|
|
||||||
pub context: Option<String>,
|
|
||||||
pub published_at: Option<String>,
|
|
||||||
pub author: Actor,
|
|
||||||
pub to: Vec<Actor>,
|
|
||||||
pub url: Option<String>,
|
|
||||||
pub conversation: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl ExpandLD<Note> for Note {
|
|
||||||
async fn expand(obj: &ObjectLD) -> Result<Note, ExpandError> {
|
|
||||||
let obj = obj.clone();
|
|
||||||
let resolver = resolve::Resolver::new();
|
|
||||||
if let Some(kind) = obj.kind {
|
|
||||||
if let ActivityKind::Note = kind {
|
|
||||||
Ok(Note {
|
|
||||||
id: obj.id,
|
|
||||||
content: obj.content,
|
|
||||||
published_at: obj.published,
|
|
||||||
author: obj
|
|
||||||
.attributed_to
|
|
||||||
.map(|id| Actor { id })
|
|
||||||
.ok_or(ExpandError::NoAttribution)?,
|
|
||||||
to: obj.to_uris.into_iter().map(|id| Actor { id }).collect(),
|
|
||||||
url: obj.url,
|
|
||||||
context: obj.context,
|
|
||||||
conversation: obj.conversation,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(ExpandError::InvalidKind(Some(kind)))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ExpandError::InvalidKind(None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<ObjectLD> for Note {
|
|
||||||
fn into(self) -> ObjectLD {
|
|
||||||
ObjectLD {
|
|
||||||
context_uri: Some(context::CONTEXT_ID.to_string()),
|
|
||||||
id: self.id.clone(),
|
|
||||||
kind: Some(ActivityKind::Note),
|
|
||||||
attributed_to: Some(self.author.id),
|
|
||||||
published: self.published_at,
|
|
||||||
content: self.content,
|
|
||||||
context: self.context,
|
|
||||||
conversation: self.conversation,
|
|
||||||
url: Some(self.id),
|
|
||||||
to_uris: self.to.into_iter().map(|a| a.id).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue