fe110d74ff62d9f16683bae0adcf82c65ce5c4c18cf2ada50927bf2509e0fa5e.tri (6069B)
1 !import base as B 2 !import handlers as H 3 !import io_v2 as V2 4 !import io_v2_storage as Storage 5 !import io_v2_artifacts as Stream 6 !import arboricx_server as Store 7 !export load 8 !export loadFrom 9 !export publish 10 !export publishTo 11 !export withFilesystemV2 12 !export withFilesystemForV2 13 !export prepareFilesystemV2 14 !export publishStreamV2 15 16 -- Domain Results always have empty remainders. HTTP status mapping belongs to 17 -- the caller, not this interface. Invalid digests are ordinary input failures; 18 -- malformed request/reply protocols are interpreter failures. 19 -- Eight bounded bit steps, each checking exact Boolean shape and canonical 20 -- termination. The continuation chain replaces a per-bit recursive fuel test; 21 -- it neither accepts redundant high zeros nor delegates to unchecked arithmetic. 22 octetEnd = B.triage (t t) (_ : t) (_ _ : t) 23 octetStep next value = B.triage (t t) (_ : t) 24 (bit tail : B.triage 25 (B.triage t (_ : t) (_ _ : next tail) tail) 26 (child : B.triage (next tail) (_ : t) (_ _ : t) child) 27 (_ _ : t) bit) 28 value 29 octetValid = octetStep (octetStep (octetStep (octetStep 30 (octetStep (octetStep (octetStep (octetStep octetEnd))))))) 31 byteC = B.guardC "expected octet" octetValid 32 33 -- These contracts are predicates, never element transformers. Scan without 34 -- rebuilding the accepted list or allocating a Result for each accepted byte. 35 -- Preserve the old first-error diagnostics and the caller's remainder. 36 bytesC value rest = let rec 37 walk remaining = B.triage 38 (B.contractOk value rest) 39 (_ : B.contractErr "not a list" rest) 40 (byte tail : case octetValid byte of 41 (t t) = walk tail 42 _ = B.contractErr "expected octet" rest) 43 remaining 44 in walk value 45 46 loadFrom service digest = case B.checkContract Store.bundleHashC digest of 47 ((t t), (checked, t)) = H.checkedRequest service "load" B.anyC loadReplyC checked 48 (t, (message, _)) = H.pure (B.err ["invalid-digest" message] t) 49 _ = H.fail "invalid-contract" service "load" digest 50 load digest = loadFrom "artifacts" digest 51 publishTo service bytes = H.checkedRequest service "publish" bytesC publishReplyC bytes 52 publish bytes = publishTo "artifacts" bytes 53 54 loadReplyC value{((t t), (bytes, t))} rest = case B.checkContract bytesC bytes of 55 ((t t), _) = B.contractOk value rest 56 _ = B.contractErr "expected artifact bytes" rest 57 loadReplyC value{(t, (message, t))} rest = B.contractOk value rest 58 loadReplyC _ rest = B.contractErr "expected artifact-load Result with empty remainder" rest 59 publishReplyC value{((t t), (digest, t))} rest = case B.checkContract Store.bundleHashC digest of 60 ((t t), _) = B.contractOk value rest 61 _ = B.contractErr "expected canonical artifact digest" rest 62 publishReplyC value{(t, (message, t))} rest = B.contractOk value rest 63 publishReplyC _ rest = B.contractErr "expected artifact-publication Result with empty remainder" rest 64 65 -- Native v2 adapter for the same domain interface. Limits are explicit byte 66 -- budgets, not heap guarantees. Roots/paths follow OS authority, not v1 grants. 67 -- Objects are immutable: verify and sync every winner; never repair corruption 68 -- by overwriting it. Loads authenticate the exact bytes returned to the caller. 69 loadV2 root limit digest = do V2.onOk 70 bytes <- Storage.readBytes (Store.bundleObjectPath root digest) limit 71 actual <- Storage.hashBytes limit bytes 72 case B.equal? actual digest of 73 (t t) = V2.pure (B.ok bytes t) 74 _ = V2.pure (B.err ["integrity-failed" "artifacts/load" "digest mismatch" "unknown"] t) 75 76 publishV2 root limit bytes = do V2.onOk 77 digest <- Storage.hashBytes limit bytes 78 case B.checkContract Store.bundleHashC digest of 79 ((t t), (checked, t)) = let directory = Store.objectDir root (Store.hashShard checked) in do V2.onOk 80 V2.ensureDirectory directory 81 V2.syncDirectory (Store.pathJoin root "objects") 82 Storage.publishBytes directory (Store.bundleObjectPath root checked) 0 limit bytes 83 V2.pure (B.ok checked t) 84 _ = V2.fail "Invalid artifact digest reply" 85 86 filesystemV2 root limit service "load" digest = case B.checkContract Store.bundleHashC digest of 87 ((t t), (checked, t)) = H.liftIO (loadV2 root limit checked) 88 (t, (message, _)) = H.pure (B.err ["invalid-digest" message] t) 89 _ = H.fail "invalid-contract" service "load" digest 90 filesystemV2 root limit service "publish" bytes = case B.checkContract bytesC bytes of 91 ((t t), (checked, t)) = H.liftIO (publishV2 root limit checked) 92 (t, (message, _)) = H.fail "invalid-request" service "publish" message 93 _ = H.fail "invalid-contract" service "publish" bytes 94 filesystemV2 _ _ service operation payload = H.forward service operation payload 95 withFilesystemForV2 service root limit action = H.handle service (filesystemV2 root limit service) action 96 withFilesystemV2 root limit action = withFilesystemForV2 "artifacts" root limit action 97 98 -- Parent-first initialization; the configured root's parent must already exist. 99 -- Sync directory entries under host filesystem guarantees, not a crash theorem. 100 ensureV2 path = do V2.onOk 101 V2.ensureDirectory path 102 V2.syncDirectory (Storage.parentPath path) 103 prepareFilesystemV2 root = H.liftIO (do V2.onOk 104 ensureV2 root 105 ensureV2 (Store.pathJoin root "tmp") 106 ensureV2 (Store.pathJoin root "objects") 107 ensureV2 (Store.pathJoin root "aliases") 108 ensureV2 (Store.pathJoin (Store.pathJoin root "aliases") "names") 109 ensureV2 (Store.pathJoin (Store.pathJoin root "aliases") "packages") 110 ensureV2 (Store.pathJoin root "manifests") 111 V2.pure (B.ok t t)) 112 113 -- Bounded producer, existing registry layout. The shard is chosen only after 114 -- hashing the complete stream, never by buffering the whole body or guessing its 115 -- digest. Temporary and object directories must share a filesystem. 116 streamDestination root digest = H.liftIO (do V2.onOk 117 V2.ensureDirectory (Store.objectDir root (Store.hashShard digest)) 118 V2.syncDirectory (Store.pathJoin root "objects") 119 V2.pure (B.ok (Store.bundleObjectPath root digest) t)) 120 publishStreamV2 root expected producer = Stream.publishWith 121 (Store.pathJoin root "tmp") expected (streamDestination root) producer