@@ -43,7 +43,7 @@ import ../utils/options
4343import  ../ bittorrent/ manifest
4444import  ../ bittorrent/ torrentdownloader
4545
46- import  ../ tarballs/ directorymanifest
46+ import  ../ tarballs/ [ directorymanifest, directorydownloader, tarballnodeextensions] 
4747
4848import  ./ coders
4949import  ./ 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.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: " 
199+     directoryDownloader.start (cid)
200+ 
201+     echo  " streaming directory started: " 
202+     await  sleepAsync (1 .seconds)
203+     echo  " after sleep..." 
204+ 
205+     while  true :
206+       echo  " getNext: " "  entries in queue" 
207+       let  data =  await  directoryDownloader.getNext ()
208+       echo  " getNext[2]: " "  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: " "  entries in queue" 
216+     await  resp.finish ()
217+     codex_api_downloads.inc ()
218+   except  CancelledError  as  exc:
219+     info  " Streaming directory cancelled" =  exc.msg
220+     raise  exc
221+   finally :
222+     info  " Sent bytes for directory" 
223+     await  directoryDownloader.stop ()
224+ 
169225proc  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" 
637+ 
638+     if  cid.isErr:
639+       return  RestApiResponse .error (Http400 , $ cid.error (), headers =  headers)
640+ 
641+     if  corsOrigin =?  allowedOrigin:
642+       resp.setCorsHeaders (" GET" 
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