Implement first webhook API (ignoring the input)
3 files changed, 104 insertions(+), 3 deletions(-)

M HOWTO.org
M guix.scm
M wispwot/server.w
M HOWTO.org +49 -3
@@ 361,15 361,61 @@ GET http://127.0.0.1:4280/subscriptions/
 : link: http://example.org
 
 
-
 * Data structures
 
 - =store/known-identities= contains the list of IDs.
 - =store/trust/ab/cd= contains the trust values given by the ID with index abcd (base 16 formatted number).
 
-* Usage in Mastodon
+* Usage in Mastodon: Webhooks
+
+For the details of the wispwot-compatible webhooks, see
+
+- https://github.com/mastodon/mastodon/pull/28744
+- https://github.com/mastodon/mastodon/pull/28958
+- https://gitlab.com/babka_net/mastodon-babka/-/merge_requests/22
+
+The webhooks are POST requests that receive JSON data.
+
+The =block.created= endpoint:
+
+#+begin_src http :pretty :exports both
+POST http://127.0.0.1:4280/webhook
+Content-type: application/json
 
-For a rough first shot to get a Mastodon backed by wispwot, see https://github.com/ArneBab/mastodon/pull/1/files
+{
+    "event": "block.created",
+    "created_at": "2024-01-15T19:22:28.134Z",
+    "object": {
+        "id": 1,
+        "created_at": "2024-01-15T19:22:28.025Z",
+        "updated_at": "2024-01-15T19:22:28.025Z",
+        "account_id": 110482205265885150,
+        "target_account_id": 111484398945680759,
+        "uri": "https://<mastodon.example>/68e9cf81-ec5e-40ab-a775-1e510c83fcea"
+    }
+}
+#+end_src
+
+#+RESULTS:
+: block.created
+
+The =action= endpoint:
+
+#+begin_src http :pretty :exports both
+POST http://127.0.0.1:4280/webhook
+Content-type: application/json
+
+{
+    "status": 12345,
+    "sender": 111484398945680759,
+    "receiver": 110482205265885150,
+    "timeline_type": "home"
+}
+#+end_src
+
+#+RESULTS:
+: 12345
+
 
 # Local Variables:
 # org-confirm-babel-evaluate: nil

          
M guix.scm +2 -0
@@ 15,6 15,8 @@ 
    (propagated-inputs `(
                         ("guile" ,guile-3.0)
                         ("guile-wisp" ,guile-wisp)
+                        ("guile-fibers" ,guile-fibers)
+                        ("guile-json" ,guile-json-4)
                         ))
    (home-page "")
    (synopsis "")

          
M wispwot/server.w +53 -0
@@ 43,6 43,7 @@ import : wispwot doctests
          prefix (fibers web server) fibers: ;; using fibers, mind the different arguments of run-server!
          prefix (fibers channels) fibers:
          prefix (fibers) fibers:
+         json
          web server ;; standard Guile server, mind the different arguments of run-server!
          web client
          web request

          
@@ 561,6 562,58 @@ define-handler 'POST "/addtrust/" : post
           . someid
 
 
+define : handle-webhook-event event json-object
+        . "Handle an event webhook"
+        . event
+        
+
+define : handle-webhook-action json-body
+        . "Handle a filtering action webhook"
+        . "{\"notOk\": true}"
+
+define-handler 'POST "/webhook" : post-webhook-handler request body wotstate
+        . "Endpoint: /webhook
+
+        Handle a webhook with a JSON payload.
+
+        Example:
+        POST /webhook
+        Content-type: application/json
+
+        {
+            \"event\": \"block.created\",
+            \"created_at\": \"2024-01-15T19:22:28.134Z\",
+            \"object\": {
+                \"id\": 1,
+                \"created_at\": \"2024-01-15T19:22:28.025Z\",
+                \"updated_at\": \"2024-01-15T19:22:28.025Z\",
+                \"account_id\": 110482205265885150,
+                \"target_account_id\": 111484398945680759,
+                \"uri\": \"https://<mastodon.example>/68e9cf81-ec5e-40ab-a775-1e510c83fcea\" 
+            }
+        }
+        => SOMEID
+
+        Increases the trust given to OTHERID by 5, preserving invariants (max is 100).
+        "
+        define content-type : request-content-type request
+        define body-string : bytevector->string body "UTF-8"
+        define body-json : json-string->scm body-string
+        define event : assoc-ref body-json "event"
+        define status : assoc-ref body-json "status"
+        define result
+            cond
+                event : handle-webhook-event event : assoc-ref body-json "object"
+                status : handle-webhook-action body-json
+                else #f
+        log-format "/webhook\n~s\n~s\n" event body-json
+        values
+          build-response
+            . #:headers `((content-type . (text/plain)))
+            . #:code : if result 200 500
+          or result ""
+
+
 
 
 ;; subscription handling