module E = Decoders_yojson.Safe.Encode let (<:) = function | (_, None) -> fun _ -> [] | (field, Some vl) -> fun ty -> [field, ty vl] let (@) field vl = (field, Some vl) let (@?) field vl = (field, vl) let ptime time = E.string (Ptime.to_rfc3339 ~tz_offset_s:0 time) let obj ls = E.obj @@ List.flatten ls let ap_obj ty ls = E.obj (Constants.ActivityStreams.context :: ("type", E.string ty) :: List.flatten ls) let or_raw conv = function | `Raw v -> v | `Value v -> conv v (** * Collections *) let ordered_collection_page enc ({ id; prev; next; is_ordered; items; part_of; total_items }: _ Types.ordered_collection_page) = ap_obj "OrderedCollectionPage" [ "id" @ id <: E.string; "next" @? next <: E.string; "prev" @? prev <: E.string; "partOf" @? part_of <: E.string; "totalItems" @? total_items <: E.int; (match is_ordered with | true -> "orderedItems" | false -> "items") @ items <: E.list enc ] let ordered_collection enc ({ id; total_items; contents }: _ Types.ordered_collection) = ap_obj "OrderedCollection" [ "id" @? id <: E.string; "totalItems" @ total_items <: E.int; match contents with | `First page -> "first" @ page <: ordered_collection_page enc | `Items (true, items) -> "orderedItems" @ items <: E.list enc | `Items (false, items) -> "items" @ items <: E.list enc ] (** * Events *) let create enc ({ id; actor; published; to_; cc; direct_message; obj; raw=_ }: _ Types.create) = ap_obj "Create" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "published" @? published <: ptime; "to" @ to_ <: E.(list string); "cc" @ cc <: E.(list string); "directMessage" @ direct_message <: E.bool; "object" @ obj <: enc; ] let announce enc ({ id; actor; published; to_; cc; obj; raw=_ } : _ Types.announce) = ap_obj "Announce" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "published" @? published <: ptime; "to" @ to_ <: E.(list string); "cc" @ cc <: E.(list string); "object" @ obj <: enc; ] let accept enc ({ id; actor; published; obj; raw=_ } : _ Types.accept) = ap_obj "Accept" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "published" @? published <: ptime; "object" @ obj <: enc; ] let undo enc ({ id; actor; published; obj; raw=_ } : _ Types.undo) = ap_obj "Undo" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "published" @? published <: ptime; "object" @ obj <: enc; ] let delete enc ({ id; actor; published; obj; raw=_ } : _ Types.delete) = ap_obj "Delete" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "published" @? published <: ptime; "object" @ obj <: enc; ] (** * Objects *) let public_key (key: Types.public_key) = obj [ "id" @ key.id <: E.string; "owner" @ key.owner <: E.string; "publicKeyPem" @ key.pem <: E.string; ] let icon (url: string) = obj [ "type" @ "Image" <: E.string; "url" @ url <: E.string; ] let person ({ id; name; url; inbox; outbox; preferred_username; summary; manually_approves_followers; discoverable; followers; following; public_key=key; icon=i; raw=_ }: Types.person) = ap_obj "Person" [ "id" @ id <: E.string; "name" @? name <: E.string; "url" @? url <: E.string; "preferredUsername" @? preferred_username <: E.string; "inbox" @ inbox <: E.string; "outbox" @ outbox <: E.string; "summary" @? summary <: E.string; "publicKey" @ key <: public_key; "manuallyApprovesFollowers" @ manually_approves_followers <: E.bool; "discoverable" @ discoverable <: E.bool; "followers" @? followers <: E.string; "following" @? following <: E.string; "icon" @? i <: icon; ] let state = function `Pending -> E.string "pending" | `Cancelled -> E.string "cancelled" let follow ({ id; actor; cc; object_; to_; state=st; raw=_ }: Types.follow) = ap_obj "Follow" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "to" @ to_ <: E.list E.string; "cc" @ cc <: E.list E.string; "object" @ object_ <: E.string; "state" @? st <: state; ] let tag ({ ty; href; name }: Types.tag) = ap_obj (match ty with `Mention -> "Mention" | `Hashtag -> "Hashtag") [ "href" @ href <: E.string; "name" @ name <: E.string; ] let attachment ({media_type; name; url; type_}: Types.attachment) = obj [ "type" @? type_ <: E.string; "mediaType" @? media_type <: E.string; "name" @? name <: E.string; "url" @ url <: E.string; ] let note ({ id; actor; to_; in_reply_to; cc; content; sensitive; source; summary; attachment=att; published; tags; raw=_ }: Types.note) = let att = match att with [] -> None | _ -> Some att in ap_obj "Note" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "attachment" @? att <: E.list attachment; "to" @ to_ <: E.list E.string; "inReplyTo" @? in_reply_to <: E.string; "cc" @ cc <: E.list E.string; "content" @ content <: E.string; "sensitive" @ sensitive <: E.bool; "source" @? source <: E.string; "summary" @? summary <: E.string; "published" @? published <: ptime; "tags" @ tags <: E.list (or_raw tag); ] let block ({ id; obj; published; actor; raw=_ }: Types.block) = ap_obj "Block" [ "id" @ id <: E.string; "object" @ obj <: E.string; "actor" @ actor <: E.string; "published" @? published <: ptime; ] let like ({ id; actor; published; obj; raw=_ }: Types.like) = ap_obj "Like" [ "id" @ id <: E.string; "actor" @ actor <: E.string; "object" @ obj <: E.string; "published" @? published <: ptime; ] let core_obj : Types.core_obj E.encoder = function | `Follow f -> follow f | `Block b -> block b | `Note n -> note n | `Person p -> person p | `Like l -> like l | `Link r -> E.string r let event enc : _ Types.event E.encoder = function | `Announce a -> announce enc a | `Undo u -> undo enc u | `Delete d -> delete enc d | `Create c -> create enc c | `Accept a -> accept enc a let object_ : Types.obj E.encoder = function | #Types.core_obj as c -> core_obj c | #Types.core_event as e -> event core_obj e module Webfinger = struct let ty = function | `ActivityJson -> E.string Constants.ContentType.activity_json | `Html -> E.string Constants.ContentType.html | `ActivityJsonLd -> E.string Constants.ContentType.ld_json_activity_streams | `Json -> E.string Constants.ContentType.plain_json let link = function | Types.Webfinger.Self (t, href) -> obj [ "href" @ href <: E.string; "rel" @ Constants.Webfinger.self_rel <: E.string; "type" @ t <: ty; ] | ProfilePage (t, href) -> obj [ "href" @ href <: E.string; "rel" @ Constants.Webfinger.profile_page <: E.string; "type" @ t <: ty; ] | OStatusSubscribe template -> obj [ "rel" @ Constants.Webfinger.ostatus_rel <: E.string; "template" @ template <: E.string; ] let query_result ({subject;aliases;links}: Types.Webfinger.query_result) = obj [ "subject" @ subject <: E.string; "aliases" @ aliases <: E.(list string); "links" @ links <: E.list link; ] end module Nodeinfo = struct let software (s: Types.Nodeinfo.software) = obj [ "name" @ s.name <: E.string; "version" @ s.version <: E.string; ] let usage_users ({ total; active_month; active_half_year }: Types.Nodeinfo.usage_users) = obj [ "total" @ total <: E.int; "activeMonth" @ active_month <: E.int; "activeHalfyear" @ active_half_year <: E.int; ] let usage ({ local_posts; users } : Types.Nodeinfo.usage) = obj [ "users" @ users <: usage_users; "localPosts" @ local_posts <: E.int ] let t ({ software=software'; protocols; inbound_services; outbound_services; usage=usage'; open_registrations; metadata; raw=_ } : Types.Nodeinfo.t) = obj [ "version" @ "2.0" <: E.string; "software" @ software' <: software; "protocols" @ protocols <: E.list E.string; "services" @ obj [ "inbound" @ inbound_services <: E.list E.string; "outbound" @ outbound_services <: E.list E.string; ] <: Fun.id; "usage" @ usage' <: usage; "openRegistrations" @ open_registrations <: E.bool; "metadata" @? metadata <: Fun.id; ] end (* module Build (S: sig * type user * * val owner: user -> Uri.t * * end) = struct * * end *)