From 380bc3f52515521f3a591d81408157ac34129b3b Mon Sep 17 00:00:00 2001 From: Jaidyn Ann <10477760+JadedCtrl@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:25:35 -0600 Subject: [PATCH] Implement a basic, bare-bones inbox! Adding a new interface, the RECEIVE method. This allows objects to be received on the inbox, however sans signature validation. --- docs/examples/simple-server.lisp | 11 ++++++++++- src/activity-servist.lisp | 21 +++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/examples/simple-server.lisp b/docs/examples/simple-server.lisp index 0c063e7..65433c4 100644 --- a/docs/examples/simple-server.lisp +++ b/docs/examples/simple-server.lisp @@ -27,6 +27,9 @@ (defvar *store* (make-hash-table :test #'equal) "Our “object-store” — stores all ActivityPub objects, mapped by their IRI @ID.") +(defvar *inbox* nil + "Our inbox, a simple list containing all received objects.") + (defvar *config* '(:host "http://localhost:8080" :address "0.0.0.0" :port 8080 :fetch fetch)) @@ -60,13 +63,19 @@ For example: “https://localhost:8080/users/lena”.") ;;; Activity-Servist callbacks ;;; ———————————————————————————————————————— (defun fetch (uri) - "activity-servist callback: Returns the JSON-LD-OBJECT of the given @ID or URI + "activity-servist callback: Returns the JSON-LD OBJECT of the given @ID or URI from our object-store. This example server simply stores objects in a hash-table mapping IDs to objects." (let ((id (or (uri->id uri) uri))) (gethash id *store*))) +(defmethod as:receive ((obj json-ld:object)) + "activity-servist callback: Recieve a JSON-LD OBJECT (posted to the server's +inbox, and decide what to do with it!" + (setq *inbox* (append *inbox* (list obj)))) + + ;;; ID-management ;;; ———————————————————————————————————————— diff --git a/src/activity-servist.lisp b/src/activity-servist.lisp index df30fc9..06e18d2 100644 --- a/src/activity-servist.lisp +++ b/src/activity-servist.lisp @@ -21,6 +21,8 @@ (:export ;; Functions :server :start-server + ;; Methods + :receive ;; Globals *config*)) @@ -75,6 +77,15 @@ Returns the ActivityPub object associated with the given URI." (funcall func uri) (error "No FETCH function found in ACTIVITY-SERVIST:*CONFIG*.")))) +(defgeneric receive (obj) + (:documentation + "Called when an OBJECT is “sent” to activity-servist’s HTTP inbox. +This is done by other servers, and is how activities and objects get federated +with ActivityPub. +To receive objects, you should overload this generic with (at the bare minimum) +a method accepting JSON-LD:OBJECTs. Doing so is required — not defining this +method will cause an error when an object is sent to the inbox.")) + ;;; Host-info response @@ -145,9 +156,11 @@ can be found). Uses the callback :FETCH, defined in *CONFIG*." ;;; Inbox requests ;;; ———————————————————————————————————————— (defun http-inbox (env path-items params) - (let* ((raw-contents (alexandria:read-stream-content-into-byte-vector (getf env :raw-body))) - (contents (babel:octets-to-string raw-contents))) - '(400 (:content-type "text/plain") ("You tried!")))) + "If one tries to send an activity to our inbox, pass it along to +the overloaded RECEIVE method." + (let* ((contents (body-contents (getf env :raw-body)))) + (receive (json-ld:parse contents)) + '(200 (:content-type "text/plain") ("You win!")))) @@ -228,7 +241,7 @@ can be found). Uses the callback :FETCH, defined in *CONFIG*." ;;; ———————————————————————————————————————— (defun server (env) "Returns the response data for Clack, given the request property-list ENV." - (setq *logs* (append *logs* (list env (body-contents (getf env :raw-body))))) + (setq *logs* (append *logs* (list env))) (let* ((path (pathname-sans-parameters (getf env :request-uri))) (params (pathname-parameters (getf env :request-uri))) (response-function