diff --git a/codex/bittorrent/manifest/manifest.nim b/codex/bittorrent/manifest/manifest.nim index 83a31ec2..657bf6e2 100644 --- a/codex/bittorrent/manifest/manifest.nim +++ b/codex/bittorrent/manifest/manifest.nim @@ -15,6 +15,7 @@ type name*: ?string BitTorrentInfoHash* = MultiHash + BitTorrentInfoHashV1* = distinct array[20, byte] BitTorrentManifest* = ref object info*: BitTorrentInfo @@ -25,6 +26,11 @@ proc newBitTorrentManifest*( ): BitTorrentManifest = BitTorrentManifest(info: info, codexManifestCid: codexManifestCid) +# needed to be able to create a MultiHash from BitTorrentInfoHashV1 +proc init*( + mhtype: typedesc[MultiHash], hashname: string, bdigest: BitTorrentInfoHashV1 +): MhResult[MultiHash] {.borrow.} + func bencode*(info: BitTorrentInfo): seq[byte] = # flatten pieces var pieces: seq[byte] diff --git a/codex/rest/api.nim b/codex/rest/api.nim index e31a0f59..5758ff1c 100644 --- a/codex/rest/api.nim +++ b/codex/rest/api.nim @@ -39,6 +39,7 @@ import ../manifest import ../streams/asyncstreamwrapper import ../stores import ../utils/options +import ../bittorrent/manifest import ./coders import ./json @@ -181,7 +182,7 @@ proc getFilenameFromContentDisposition(contentDisposition: string): ?string = return filename[0 ..^ 2].some proc initDataApi(node: CodexNodeRef, repoStore: RepoStore, router: var RestRouter) = - let allowedOrigin = router.allowedOrigin # prevents capture inside of api defintion + let allowedOrigin = router.allowedOrigin # prevents capture inside of api definition router.api(MethodOptions, "/api/codex/v1/data") do( resp: HttpResponseRef @@ -347,6 +348,25 @@ proc initDataApi(node: CodexNodeRef, repoStore: RepoStore, router: var RestRoute resp.setHeader("Access-Control-Expose-Headers", "Content-Disposition") await node.retrieveCid(cid.get(), local = false, resp = resp) + router.api(MethodGet, "/api/codex/v1/data/{infoHash}/network/torrent") do( + infoHash: BitTorrentInfoHashV1, resp: HttpResponseRef + ) -> RestApiResponse: + var headers = buildCorsHeaders("GET", allowedOrigin) + + without infoHash =? infoHash.tryGet.catch, error: + return RestApiResponse.error(Http400, error.msg, headers = headers) + + without infoMultiHash =? MultiHash.init($Sha1HashCodec, infoHash).mapFailure, error: + return RestApiResponse.error(Http400, error.msg, headers = headers) + + if corsOrigin =? allowedOrigin: + resp.setCorsHeaders("GET", corsOrigin) + resp.setHeader("Access-Control-Headers", "X-Requested-With") + + trace "torrent requested: ", multihash = $infoMultiHash + + return RestApiResponse.response(Http200) + router.api(MethodGet, "/api/codex/v1/data/{cid}/network/manifest") do( cid: Cid, resp: HttpResponseRef ) -> RestApiResponse: diff --git a/codex/rest/coders.nim b/codex/rest/coders.nim index 319ce3d6..95d39373 100644 --- a/codex/rest/coders.nim +++ b/codex/rest/coders.nim @@ -21,6 +21,8 @@ import ../sales import ../purchasing import ../utils/stintutils +from ../bittorrent/manifest import BitTorrentInfoHashV1 + proc encodeString*(cid: type Cid): Result[string, cstring] = ok($cid) @@ -82,6 +84,19 @@ proc decodeString*( except ValueError as e: err e.msg.cstring +proc decodeString*( + _: type array[20, byte], value: string +): Result[array[20, byte], cstring] = + try: + ok array[20, byte].fromHex(value) + except ValueError as e: + err e.msg.cstring + +proc decodeString*[T: BitTorrentInfoHashV1]( + _: type T, value: string +): Result[T, cstring] = + array[20, byte].decodeString(value).map(id => T(id)) + proc decodeString*[T: PurchaseId | RequestId | Nonce | SlotId | AvailabilityId]( _: type T, value: string ): Result[T, cstring] =