Skip to content

Commit 7e073ad

Browse files
committed
adds API for retrieving directory
1 parent a19dbdf commit 7e073ad

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

codex/rest/api.nim

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import ../utils/options
4343
import ../bittorrent/manifest
4444
import ../bittorrent/torrentdownloader
4545

46-
import ../tarballs/directorymanifest
46+
import ../tarballs/[directorymanifest, directorydownloader, tarballnodeextensions]
4747

4848
import ./coders
4949
import ./json
@@ -166,6 +166,62 @@ proc retrieveCid(
166166
if not lpStream.isNil:
167167
await lpStream.close()
168168

169+
proc retrieveDirectory(
170+
node: CodexNodeRef, cid: Cid, resp: HttpResponseRef
171+
): Future[void] {.async: (raises: [CancelledError, HttpWriteError]).} =
172+
## Download torrent from the node in a streaming
173+
## manner
174+
##
175+
let directoryDownloader = newDirectoryDownloader(node)
176+
177+
var bytes = 0
178+
try:
179+
without directoryManifest =? (await node.fetchDirectoryManifest(cid)), err:
180+
error "Unable to fetch Directory Metadata", err = err.msg
181+
resp.status = Http404
182+
await resp.sendBody(err.msg)
183+
return
184+
185+
resp.addHeader("Content-Type", "application/octet-stream")
186+
187+
resp.setHeader(
188+
"Content-Disposition",
189+
"attachment; filename=\"" & directoryManifest.name & "\"",
190+
)
191+
192+
# ToDo: add contentSize to the directory manifest
193+
# let contentLength = codexManifest.datasetSize
194+
# resp.setHeader("Content-Length", $(contentLength.int))
195+
196+
await resp.prepare(HttpResponseStreamType.Plain)
197+
198+
echo "streaming directory: ", cid
199+
directoryDownloader.start(cid)
200+
201+
echo "streaming directory started: ", cid
202+
await sleepAsync(1.seconds)
203+
echo "after sleep..."
204+
205+
while true:
206+
echo "getNext: ", directoryDownloader.queue.len, " entries in queue"
207+
let data = await directoryDownloader.getNext()
208+
echo "getNext[2]: ", data.len, " bytes"
209+
await sleepAsync(1.seconds)
210+
if data.len == 0:
211+
break
212+
bytes += data.len
213+
await resp.sendChunk(addr data[0], data.len)
214+
215+
echo "out of loop: ", directoryDownloader.queue.len, " entries in queue"
216+
await resp.finish()
217+
codex_api_downloads.inc()
218+
except CancelledError as exc:
219+
info "Streaming directory cancelled", exc = exc.msg
220+
raise exc
221+
finally:
222+
info "Sent bytes for directory", cid, bytes
223+
await directoryDownloader.stop()
224+
169225
proc retrieveInfoHash(
170226
node: CodexNodeRef, infoHash: MultiHash, resp: HttpResponseRef
171227
): Future[void] {.async: (raises: [CancelledError, HttpWriteError]).} =
@@ -569,6 +625,25 @@ proc initDataApi(node: CodexNodeRef, repoStore: RepoStore, router: var RestRoute
569625

570626
resp.setHeader("Access-Control-Expose-Headers", "Content-Disposition")
571627
await node.retrieveCid(cid.get(), local = false, resp = resp)
628+
629+
router.api(MethodGet, "/api/codex/v1/dir/{cid}/network/stream") do(
630+
cid: Cid, resp: HttpResponseRef
631+
) -> RestApiResponse:
632+
## Download a file from the network in a streaming
633+
## manner
634+
##
635+
636+
var headers = buildCorsHeaders("GET", allowedOrigin)
637+
638+
if cid.isErr:
639+
return RestApiResponse.error(Http400, $cid.error(), headers = headers)
640+
641+
if corsOrigin =? allowedOrigin:
642+
resp.setCorsHeaders("GET", corsOrigin)
643+
resp.setHeader("Access-Control-Headers", "X-Requested-With")
644+
645+
resp.setHeader("Access-Control-Expose-Headers", "Content-Disposition")
646+
await node.retrieveDirectory(cid.get(), resp = resp)
572647

573648
router.api(MethodGet, "/api/codex/v1/torrent/{infoHash}/network/stream") do(
574649
infoHash: MultiHash, resp: HttpResponseRef

0 commit comments

Comments
 (0)