adds API for streaming torrents

This commit is contained in:
Marcin Czenko 2025-03-05 00:37:10 +01:00
parent 8a8bab3672
commit d5928988d0
No known key found for this signature in database
GPG Key ID: 33DEA0C8E30937C0
3 changed files with 42 additions and 1 deletions

View File

@ -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]

View File

@ -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:

View File

@ -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] =