;; lib/host/ta.sx — TA: the fed-sx TRANSPORT ADAPTER (plans/business-logic-fed-flows.md). A seam ;; transport {:emit :deliver} (behavior.sx) over a directional WIRE, so an activity emitted on one ;; instance reaches another instance's engine and fires ITS behaviors — federation. ;; ;; The transport is the SERIALIZATION boundary: activities cross the wire as SX-source strings ;; (string-keyed for persist/wire safety, reconstructed on arrival). The wire is dumb string ;; transport {:send :recv}; the REAL wire is next/ delivery (outbox→peers / inbox), DEFERRED to ;; TA-live (same persistent-kernel prerequisite as RA-live); a mem-wire drives the tests. ;; ;; DIRECTIONAL: :emit → an OUT wire (this instance's outbox → followers); :deliver → an IN wire ;; (its inbox ← those it follows). Separate channels, so processing a delivered activity (which the ;; seam re-emits to log it) goes to THIS instance's outbox, NOT back into the inbox — no loop. ;; canonical activity (keyword-keyed) <-> the flat string-keyed WIRE form (persist/serialise-safe). (define host/ta--activity->wire (fn (a) {"verb" (get a :verb) "actor" (get a :actor) "object" (get a :object) "type" (get a :object-type) "slug" (get a :slug) "category" (get a :category) "relation" (get a :relation) "target" (get a :target) "to" (get a :to) "delta" (get a :delta) "id" (get a :id)})) (define host/ta--wire->activity (fn (w) {:verb (get w "verb") :actor (get w "actor") :object (get w "object") :object-type (get w "type") :slug (get w "slug") :category (get w "category") :relation (get w "relation") :target (get w "target") :to (get w "to") :delta (get w "delta") :id (get w "id")})) (define host/ta--serialize (fn (a) (serialize (host/ta--activity->wire a)))) (define host/ta--deserialize (fn (s) (host/ta--wire->activity (parse-safe s)))) ;; the transport: emit serialises to the OUT wire; deliver deserialises from the IN wire. (define host/ta--make-transport (fn (out-wire in-wire) {:emit (fn (a) ((get out-wire :send) (host/ta--serialize a))) :deliver (fn () (map host/ta--deserialize ((get in-wire :recv))))})) ;; an in-memory directional wire {:send :recv} (a captured mutable queue) — the test substrate. (define host/ta--make-mem-wire (fn () (let ((q (list))) {:send (fn (s) (set! q (concat q (list s)))) :recv (fn () (let ((batch q)) (begin (set! q (list)) batch)))}))) ;; TA-LIVE: an HTTP fed-wire — :send POSTs a serialized activity to a PEER's /inbox over real HTTP ;; (http-request, native primitive). :recv is unused: a peer's /inbox route pushes received ;; activities straight into its engine (host/blog--receive!), so delivery is push, not poll. This is ;; the fed-sx transport in production — an activity emitted here fires a REMOTE instance's behaviors. ;; POST a pre-serialized wire string to a peer's /inbox (may raise on connection failure — callers ;; that must not fail the local emit wrap this in a guard, per the durable-outbox pattern). (define host/ta--post (fn (peer-base s) (http-request "POST" (str peer-base "/inbox") {"content-type" "text/plain"} s))) (define host/ta--make-http-wire (fn (peer-base) {:send (fn (s) (host/ta--post peer-base s)) :recv (fn () (list))})) ;; serialize an activity + POST it to a peer (direct; the outbox path serializes-then-queues instead). (define host/ta--federate (fn (peer-base a) (host/ta--post peer-base (host/ta--serialize a))))