AP: move types to their own directory
This commit is contained in:
74
source/ap/types/actor.d
Normal file
74
source/ap/types/actor.d
Normal file
@@ -0,0 +1,74 @@
|
||||
module ap.types.actor;
|
||||
|
||||
import std.json;
|
||||
|
||||
import ap.types.object;
|
||||
import util;
|
||||
|
||||
/++
|
||||
* Represents an ActivityPub Actor
|
||||
* https://www.w3.org/TR/activitypub/#actors
|
||||
+/
|
||||
class Actor : ASObject {
|
||||
/* Required fields */
|
||||
string inbox; /// Link to messages received by this actor. Required
|
||||
string outbox; /// Link to messages produced by this actor. Required
|
||||
string following; /// Link to a collection of the actors that this actor is following. Required
|
||||
string followers; /// Link to a collection of the actors that follow this actor. Required
|
||||
|
||||
/* Optional fields */
|
||||
string liked; /// Link to a collection of objects this actor has liked
|
||||
string streams; /// Supplementary list of Collections of interest
|
||||
string preferredUsername; /// A short username for referencing this actor
|
||||
ActorEndpoints endpoints; /// Useful endpoints for this actor
|
||||
|
||||
JSONValue raw;
|
||||
|
||||
/++
|
||||
+ Creates an Actor object based on its json representation
|
||||
+ Params:
|
||||
+ json = ActivityPub actor JSON representation
|
||||
+/
|
||||
this(JSONValue json) {
|
||||
super(json);
|
||||
|
||||
with (this) {
|
||||
required(json, "inbox", inbox);
|
||||
required(json, "outbox", outbox);
|
||||
required(json, "following", following);
|
||||
required(json, "followers", followers);
|
||||
|
||||
optional(json, "liked", liked);
|
||||
optional(json, "streams", streams);
|
||||
optional(json, "preferredUsername", preferredUsername);
|
||||
|
||||
endpoints = ActorEndpoints.fromJson(json.optional!JSONValue("endpoints"));
|
||||
|
||||
raw = json;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ActorEndpoints {
|
||||
string proxyUrl;
|
||||
string oauthAuthorizationEndpoint;
|
||||
string oauthTokenEndpoint;
|
||||
string provideClientKey;
|
||||
string signClientKey;
|
||||
string sharedInbox;
|
||||
|
||||
static ActorEndpoints fromJson(JSONValue json) {
|
||||
ActorEndpoints endpoints = ActorEndpoints();
|
||||
|
||||
with (endpoints) {
|
||||
optional(json, "proxyUrl", proxyUrl);
|
||||
optional(json, "oauthAuthorizationEndpoint", oauthAuthorizationEndpoint);
|
||||
optional(json, "oauthTokenEndpoint", oauthTokenEndpoint);
|
||||
optional(json, "provideClientKey", provideClientKey);
|
||||
optional(json, "signClientKey", signClientKey);
|
||||
optional(json, "sharedInbox", sharedInbox);
|
||||
}
|
||||
|
||||
return endpoints;
|
||||
}
|
||||
}
|
||||
28
source/ap/types/collection.d
Normal file
28
source/ap/types/collection.d
Normal file
@@ -0,0 +1,28 @@
|
||||
module ap.types.collection;
|
||||
|
||||
import std.json;
|
||||
|
||||
import ap.types.object;
|
||||
import ap.types.collection_page;
|
||||
import util;
|
||||
|
||||
class Collection : ASObject {
|
||||
int totalItems;
|
||||
CollectionPage current;
|
||||
CollectionPage first;
|
||||
CollectionPage last;
|
||||
ASObject items;
|
||||
|
||||
this(JSONValue json) {
|
||||
super(json);
|
||||
|
||||
if (this.m_objType != ObjectType.Object)
|
||||
throw new Exception("Wrong Collection format?");
|
||||
|
||||
optional(json, "totalItems", totalItems);
|
||||
current = new CollectionPage(json.optional!JSONValue("current"));
|
||||
first = new CollectionPage(json.optional!JSONValue("first"));
|
||||
last = new CollectionPage(json.optional!JSONValue("last"));
|
||||
items = new ASObject(json.optional!JSONValue("items"));
|
||||
}
|
||||
}
|
||||
24
source/ap/types/collection_page.d
Normal file
24
source/ap/types/collection_page.d
Normal file
@@ -0,0 +1,24 @@
|
||||
module ap.types.collection_page;
|
||||
|
||||
import std.json;
|
||||
|
||||
import ap.types.collection;
|
||||
import ap.types.object;
|
||||
import util;
|
||||
|
||||
class CollectionPage : Collection {
|
||||
CollectionPage partOf;
|
||||
CollectionPage next;
|
||||
CollectionPage prev;
|
||||
|
||||
this(JSONValue json) {
|
||||
super(json);
|
||||
|
||||
if (this.m_objType != ObjectType.Object)
|
||||
throw new Exception("Wrong CollectionPage format?");
|
||||
|
||||
partOf = new CollectionPage(json.optional!JSONValue("partOf"));
|
||||
next = new CollectionPage(json.optional!JSONValue("next"));
|
||||
prev = new CollectionPage(json.optional!JSONValue("prev"));
|
||||
}
|
||||
}
|
||||
105
source/ap/types/link.d
Normal file
105
source/ap/types/link.d
Normal file
@@ -0,0 +1,105 @@
|
||||
module ap.types.link;
|
||||
|
||||
import std.algorithm;
|
||||
import std.array;
|
||||
import std.format;
|
||||
import std.json;
|
||||
|
||||
import ap.types.object;
|
||||
import util;
|
||||
|
||||
class Link {
|
||||
string type;
|
||||
string href;
|
||||
string[] rel;
|
||||
string mediaType;
|
||||
string name;
|
||||
int height, width;
|
||||
ASObject preview;
|
||||
|
||||
protected Store m_store;
|
||||
protected ObjectType m_objType;
|
||||
|
||||
JSONValue raw;
|
||||
|
||||
this() {
|
||||
}
|
||||
|
||||
this(JSONValue json) {
|
||||
switch (json.type) {
|
||||
case JSONType.ARRAY:
|
||||
m_objType = ObjectType.Array;
|
||||
m_store.links = json.array.map!(item => new Link(item)).array;
|
||||
break;
|
||||
|
||||
case JSONType.OBJECT:
|
||||
m_objType = ObjectType.Object;
|
||||
|
||||
optional(json, "type", type);
|
||||
optional(json, "href", href);
|
||||
optional(json, "mediaType", mediaType);
|
||||
optional(json, "name", name);
|
||||
optional(json, "height", height);
|
||||
optional(json, "width", width);
|
||||
|
||||
const(JSONValue)* j;
|
||||
if ((j = "rel" in json) != null)
|
||||
rel = (*j).array.map!(item => item.str).array;
|
||||
|
||||
preview = new ASObject(json.optional!JSONValue("preview"));
|
||||
break;
|
||||
|
||||
case JSONType.STRING:
|
||||
m_objType = ObjectType.String;
|
||||
m_store.str = json.str;
|
||||
break;
|
||||
|
||||
case JSONType.NULL:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unrecognized ActivityStream Link JSON format");
|
||||
}
|
||||
|
||||
this.raw = json;
|
||||
}
|
||||
|
||||
string stringRep(int indentation = 0, string indentStr = " ") const {
|
||||
string[] output;
|
||||
string indent = "";
|
||||
string j;
|
||||
|
||||
if (this.m_objType == ObjectType.String)
|
||||
return format("%s%s", indent, this.m_store.str);
|
||||
|
||||
for (int i = 0; i < indentation; i++)
|
||||
indent ~= indentStr;
|
||||
|
||||
output ~= format("%s {", this.type);
|
||||
|
||||
if (href)
|
||||
output ~= format("%s%shref = %s", indent, indentStr, href);
|
||||
|
||||
if (mediaType)
|
||||
output ~= format("%s%smediaType = %s", indent, indentStr, mediaType);
|
||||
|
||||
if (name)
|
||||
output ~= format("%s%sname = %s", indent, indentStr, name);
|
||||
|
||||
if (height)
|
||||
output ~= format("%s%sheight = %d", indent, indentStr, height);
|
||||
|
||||
if (width)
|
||||
output ~= format("%s%swidth = %d", indent, indentStr, width);
|
||||
|
||||
if (preview && (j = preview.stringRep(indentation + 1)) != string.init)
|
||||
output ~= format("%s%spreview = %s", indent, indentStr, j);
|
||||
|
||||
output ~= indent ~ "}";
|
||||
|
||||
if (output.length == 2)
|
||||
return "";
|
||||
|
||||
return output.join("\n");
|
||||
}
|
||||
}
|
||||
201
source/ap/types/object.d
Normal file
201
source/ap/types/object.d
Normal file
@@ -0,0 +1,201 @@
|
||||
module ap.types.object;
|
||||
|
||||
import std.algorithm;
|
||||
import std.array;
|
||||
import std.datetime;
|
||||
import std.format;
|
||||
import std.json;
|
||||
|
||||
import ap.types.link;
|
||||
import ap.types.collection;
|
||||
import util;
|
||||
|
||||
union Store {
|
||||
string str;
|
||||
ASObject[] array;
|
||||
Link[] links;
|
||||
}
|
||||
|
||||
enum ObjectType {
|
||||
Object,
|
||||
String,
|
||||
Array,
|
||||
}
|
||||
|
||||
/++
|
||||
* Basic ActivityStream Object
|
||||
* https://www.w3.org/TR/activitypub/#obj
|
||||
+/
|
||||
class ASObject {
|
||||
// Required fields (for root objects)
|
||||
JSONValue context; /// Must be activitystream context
|
||||
string id; /// AP requirement for unique identifier
|
||||
string type; /// AP requirement for type of object
|
||||
|
||||
// Optional fields
|
||||
ASObject attachment;
|
||||
ASObject attributedTo;
|
||||
ASObject audience;
|
||||
string content;
|
||||
string name;
|
||||
DateTime endTime;
|
||||
ASObject generator;
|
||||
ASObject icon;
|
||||
ASObject image;
|
||||
ASObject inReplyTo;
|
||||
ASObject location;
|
||||
ASObject preview;
|
||||
DateTime published;
|
||||
Collection replies;
|
||||
DateTime startTime;
|
||||
string summary;
|
||||
ASObject tag;
|
||||
DateTime updated;
|
||||
Link url;
|
||||
ASObject to;
|
||||
ASObject bto;
|
||||
ASObject cc;
|
||||
ASObject bcc;
|
||||
string mediaType;
|
||||
string duration;
|
||||
|
||||
JSONValue raw;
|
||||
|
||||
protected Store m_store;
|
||||
protected ObjectType m_objType;
|
||||
|
||||
this() {
|
||||
}
|
||||
|
||||
/++
|
||||
+ Constructs the object according to json source
|
||||
+ Params:
|
||||
+ json = the source json
|
||||
+ Returns: Object
|
||||
+/
|
||||
this(JSONValue json) {
|
||||
switch (json.type) {
|
||||
case JSONType.ARRAY:
|
||||
this.m_objType = ObjectType.Array;
|
||||
this.m_store.array = json.array.map!(item => new ASObject(item)).array;
|
||||
break;
|
||||
|
||||
case JSONType.OBJECT:
|
||||
this.m_objType = ObjectType.Object;
|
||||
|
||||
// String properties
|
||||
optional(json, "context", context);
|
||||
optional(json, "id", id);
|
||||
optional(json, "type", type);
|
||||
optional(json, "content", content);
|
||||
optional(json, "name", name);
|
||||
optional(json, "summary", summary);
|
||||
optional(json, "mediaType", mediaType);
|
||||
optional(json, "duration", duration);
|
||||
|
||||
// AS Object properties
|
||||
generator = new ASObject(json.optional!JSONValue("generator"));
|
||||
icon = new ASObject(json.optional!JSONValue("icon"));
|
||||
image = new ASObject(json.optional!JSONValue("image"));
|
||||
inReplyTo = new ASObject(json.optional!JSONValue("inReplyTo"));
|
||||
location = new ASObject(json.optional!JSONValue("location"));
|
||||
preview = new ASObject(json.optional!JSONValue("preview"));
|
||||
tag = new ASObject(json.optional!JSONValue("tag"));
|
||||
to = new ASObject(json.optional!JSONValue("to"));
|
||||
bto = new ASObject(json.optional!JSONValue("bto"));
|
||||
cc = new ASObject(json.optional!JSONValue("cc"));
|
||||
bcc = new ASObject(json.optional!JSONValue("bcc"));
|
||||
|
||||
const(JSONValue)* j;
|
||||
|
||||
// Date properties
|
||||
// if ((j = "endTime" in json) != null)
|
||||
// endTime = DateTime.fromISOString(json["endTime"].str);
|
||||
|
||||
// if ((j = "published" in json) != null)
|
||||
// published = DateTime.fromISOString(json["published"].str);
|
||||
|
||||
// if ((j = "startTime" in json) != null)
|
||||
// startTime = DateTime.fromISOString(json["startTime"].str);
|
||||
|
||||
// if ((j = "updated" in json) != null)
|
||||
// updated = DateTime.fromISOString(json["updated"].str);
|
||||
|
||||
url = new Link(json.optional!JSONValue("url"));
|
||||
|
||||
break;
|
||||
|
||||
case JSONType.STRING:
|
||||
this.m_objType = ObjectType.String;
|
||||
this.m_store.str = json.str;
|
||||
break;
|
||||
|
||||
case JSONType.NULL:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unrecognized ActivityStream Object JSON format: " ~ json.type);
|
||||
}
|
||||
|
||||
raw = json;
|
||||
}
|
||||
|
||||
string stringRep(int indentation = 0, string indentStr = " ") const {
|
||||
string[] output;
|
||||
string indent = "";
|
||||
string j;
|
||||
|
||||
if (this.m_objType == ObjectType.String)
|
||||
return format("%s%s\n", indent, this.m_store.str);
|
||||
|
||||
if (this.m_objType == ObjectType.Array) {
|
||||
output ~= "[";
|
||||
|
||||
foreach (obj; this.m_store.array)
|
||||
output ~= format("%s%s%s%s,", indent, indentStr, indentStr, obj.stringRep(indentation + 1));
|
||||
|
||||
output ~= format("%s%s]", indent, indentStr);
|
||||
|
||||
return output.length == 2 ? "" : output.join("\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < indentation; i++)
|
||||
indent ~= indentStr;
|
||||
|
||||
output ~= format("%s {", this.type);
|
||||
|
||||
if (id)
|
||||
output ~= format("%s%sid = %s", indent, indentStr, id);
|
||||
|
||||
if (content)
|
||||
output ~= format("%s%scontent = %s", indent, indentStr, content);
|
||||
|
||||
if (name)
|
||||
output ~= format("%s%sname = %s", indent, indentStr, name);
|
||||
|
||||
// if (summary)
|
||||
// output ~= format("%s%ssummary = %s", indent, indentStr, summary);
|
||||
|
||||
if (mediaType)
|
||||
output ~= format("%s%smediaType = %s", indent, indentStr, mediaType);
|
||||
|
||||
if (duration)
|
||||
output ~= format("%s%sduration = %s", indent, indentStr, duration);
|
||||
|
||||
if (url && (j = url.stringRep(indentation + 1)) != string.init)
|
||||
output ~= format("%s%surl = %s", indent, indentStr, j);
|
||||
|
||||
if (icon && (j = icon.stringRep(indentation + 1)) != string.init)
|
||||
output ~= format("%s%sicon = %s", indent, indentStr, j);
|
||||
|
||||
if (image && (j = image.stringRep(indentation + 1)) != string.init)
|
||||
output ~= format("%s%simage = %s", indent, indentStr, j);
|
||||
|
||||
if (tag && (j = tag.stringRep(indentation + 1)) != string.init)
|
||||
output ~= format("%s%stag = %s", indent, indentStr, j);
|
||||
|
||||
output ~= indent ~ "}";
|
||||
|
||||
return output.length == 2 ? "" : output.join("\n");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user