Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
blob.sx: a blob ref is {:cid :size :mime}; the blob store is a separate
injected dependency (perform in prod, mock content store in tests).
persist/blob-store puts bytes and returns only the ref; bytes live in a
content-addressed store (artdag/IPFS). Tests assert refs in log/kv never carry
the bytes + content-address dedup. 105/105.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
2.7 KiB
Plaintext
67 lines
2.7 KiB
Plaintext
; persist/blob — large objects (images, media) are NOT persist's to hold. They
|
|
; live in a content-addressed store (artdag/IPFS); persist stores only a
|
|
; reference: {:cid :size :mime}. The blob store is a SEPARATE injected
|
|
; dependency with its own transport (perform in production, a mock content store
|
|
; in tests), distinct from the event/kv backend. The invariant: a blob ref that
|
|
; lands in the log or kv carries the CID + metadata and never the bytes.
|
|
; Requires: lib/persist/backend.sx.
|
|
|
|
(define persist/blob-ref (fn (cid size mime) {:mime mime :size size :cid cid}))
|
|
(define persist/blob-ref? (fn (r) (has-key? r :cid)))
|
|
(define persist/blob-cid (fn (r) (get r :cid)))
|
|
(define persist/blob-size (fn (r) (get r :size)))
|
|
(define persist/blob-mime (fn (r) (get r :mime)))
|
|
|
|
; blob store protocol over an injectable transport
|
|
(define persist/blob-io (fn (transport) {:put (fn (bytes mime) (transport {:op "blob/put" :args (list bytes mime)})) :get (fn (cid) (transport {:op "blob/get" :args (list cid)})) :has? (fn (cid) (transport {:op "blob/has?" :args (list cid)}))}))
|
|
|
|
; production blob store — transport is the kernel's perform
|
|
(define
|
|
persist/blob-store-backend
|
|
(fn () (persist/blob-io (fn (req) (perform req)))))
|
|
|
|
; store bytes via the blob backend; return ONLY the ref (cid + metadata) — this
|
|
; is what the caller persists in the log/kv. The bytes never enter persist.
|
|
(define
|
|
persist/blob-store
|
|
(fn
|
|
(blob bytes mime)
|
|
(let
|
|
((cid ((get blob :put) bytes mime)))
|
|
(persist/blob-ref cid (len bytes) mime))))
|
|
|
|
(define
|
|
persist/blob-fetch
|
|
(fn (blob ref) ((get blob :get) (persist/blob-cid ref))))
|
|
(define
|
|
persist/blob-exists?
|
|
(fn (blob ref) ((get blob :has?) (persist/blob-cid ref))))
|
|
|
|
; mock content-addressed store (stands in for artdag/IPFS). CID is a
|
|
; deterministic content address: identical bytes dedupe to one CID. A real
|
|
; store computes a SHA3/IPFS CID host-side; the prefix keeps the mock readable.
|
|
(define persist/blob-cid-of (fn (bytes) (str "cid:" bytes)))
|
|
|
|
(define
|
|
persist/blob-serve
|
|
(fn
|
|
(store req)
|
|
(let
|
|
((op (get req :op)) (args (get req :args)))
|
|
(cond
|
|
((equal? op "blob/put")
|
|
(let
|
|
((cid (persist/blob-cid-of (first args))))
|
|
(begin (persist/backend-kv-put store cid (first args)) cid)))
|
|
((equal? op "blob/get") (persist/backend-kv-get store (first args)))
|
|
((equal? op "blob/has?")
|
|
(persist/backend-kv-has? store (first args)))
|
|
(else (error (str "persist/blob-serve: unknown op " op)))))))
|
|
|
|
(define
|
|
persist/blob-mock-transport
|
|
(fn (store) (fn (req) (persist/blob-serve store req))))
|
|
(define
|
|
persist/mock-blob
|
|
(fn (store) (persist/blob-io (persist/blob-mock-transport store))))
|