diff --git a/codex/rest/api.nim b/codex/rest/api.nim index cf8ddefb..bd56d36c 100644 --- a/codex/rest/api.nim +++ b/codex/rest/api.nim @@ -53,6 +53,11 @@ declareCounter(codex_api_downloads, "codex API downloads") proc validate(pattern: string, value: string): int {.gcsafe, raises: [Defect].} = 0 +proc formatTorrentManifest( + infoHash: MultiHash, torrentManifest: BitTorrentManifest +): RestTorrentContent = + return RestTorrentContent.init(infoHash, torrentManifest) + proc formatManifest(cid: Cid, manifest: Manifest): RestContent = return RestContent.init(cid, manifest) @@ -210,7 +215,7 @@ proc retrieveInfoHash( while not stream.atEof: var - buff = newSeqUninitialized[byte](int(NBytes 1024 * 16)) + buff = newSeqUninitialized[byte](BitTorrentBlockSize.int) len = await stream.readOnce(addr buff[0], buff.len) buff.setLen(len) @@ -545,6 +550,37 @@ proc initDataApi(node: CodexNodeRef, repoStore: RepoStore, router: var RestRoute let json = %formatManifest(cid.get(), manifest) return RestApiResponse.response($json, contentType = "application/json") + router.api(MethodGet, "/api/codex/v1/torrent/{infoHash}/network/manifest") do( + infoHash: MultiHash, resp: HttpResponseRef + ) -> RestApiResponse: + ## Download only the Bit Torrent manifest (if found) + ## + + var headers = buildCorsHeaders("GET", allowedOrigin) + + without infoHash =? infoHash.mapFailure, error: + return RestApiResponse.error(Http400, error.msg, headers = headers) + + if infoHash.mcodec != Sha1HashCodec: + return RestApiResponse.error( + Http400, "Only torrents version 1 are currently supported!", headers = headers + ) + + without infoHashCid =? Cid.init(CIDv1, InfoHashV1Codec, infoHash).mapFailure, err: + error "Unable to create CID for BitTorrent info hash", err = err.msg + resp.status = Http404 + await resp.sendBody(err.msg) + return + + without torrentManifest =? (await node.fetchTorrentManifest(infoHashCid)), err: + error "Unable to fetch Torrent Manifest", err = err.msg + resp.status = Http404 + await resp.sendBody(err.msg) + return + + let json = %formatTorrentManifest(infoHash, torrentManifest) + return RestApiResponse.response($json, contentType = "application/json") + router.api(MethodGet, "/api/codex/v1/space") do() -> RestApiResponse: let json = %RestRepoStore( diff --git a/codex/rest/json.nim b/codex/rest/json.nim index 1b9459c1..d321064e 100644 --- a/codex/rest/json.nim +++ b/codex/rest/json.nim @@ -9,6 +9,8 @@ import ../utils/json import ../manifest import ../units +import ../bittorrent/manifest + export json type @@ -47,6 +49,10 @@ type cid* {.serialize.}: Cid manifest* {.serialize.}: Manifest + RestTorrentContent* = object + infoHash* {.serialize.}: MultiHash + torrentManifest* {.serialize.}: BitTorrentManifest + RestContentList* = object content* {.serialize.}: seq[RestContent] @@ -81,6 +87,11 @@ proc init*(_: type RestContentList, content: seq[RestContent]): RestContentList proc init*(_: type RestContent, cid: Cid, manifest: Manifest): RestContent = RestContent(cid: cid, manifest: manifest) +proc init*( + _: type RestTorrentContent, infoHash: MultiHash, torrentManifest: BitTorrentManifest +): RestTorrentContent = + RestTorrentContent(infoHash: infoHash, torrentManifest: torrentManifest) + proc init*(_: type RestNode, node: dn.Node): RestNode = RestNode( nodeId: RestNodeId.init(node.id),