Hi, I'm still trying to figure out async/await. I am writing a script that 
parses a json returned by a forum API and tries to download all the files 
described by the json. Writing a synchronous downloader script was a breeze: 
[https://play.nim-lang.org/#ix=2gcb](https://play.nim-lang.org/#ix=2gcb)

However I have been struggling with making the downloads asynchronous. First of 
all I used the `AsyncHTTPClient` called `webClient`. Then I iterate over the 
json nodes to look for parts that I need to construct file download link. Then 
I created a `seq[Future[void]]` caled `futures` to store all the futures 
returned by `downloadFile()` method. Then I start the loop. Each time I make a 
call to `downloadFile()`, I store the future into `futures` seq.

Lastly when the loop finishes I call `waitFor futures.all()` to wait for the 
future returned by the `all()` function 
([https://nim-lang.org/docs/asyncfutures.html#all%2Cvarargs%5BFuture%5BT%5D%5D](https://nim-lang.org/docs/asyncfutures.html#all%2Cvarargs%5BFuture%5BT%5D%5D))
 to yield.

And at the very last I `waitFor` my main function.
    
    
    import strutils, os, json, strformat, httpclient, asyncdispatch
    
    proc mediaLink(node: JsonNode; board, thread: string): string =
      let
        fileID = node["tim"].getInt()
        ext = node["ext"].getStr()
      
      result = fmt"https://i.4cdn.org/{board}/{fileID}{ext}";
    
    proc parseBoardAndThread(uri: string): (string, string) =
        var
            slashCount = 0
            board = newStringOfCap(2)
            thread = newStringOfCap(8)
        
        for c in uri:
            if c == '/':
                slashCount += 1
            elif slashCount == 3:
                board &= c
            elif slashCount == 5:
                if c >= '0' and c <= '9':
                    thread &= c
                else:
                    break
        return (board, thread)
    
    proc getAPILink(board, thread: string): string =
      fmt"https://a.4cdn.org/{board}/thread/{thread}.json";
    
    proc getRawLink(): string =
      if os.paramCount() < 1:
        when not defined release: # debugging purposes so I can just call 
./threadgrabber without any link and dir
          result = "https://boards.4channel.org/wsg/thread/3360760";
        else:
          quit("Link required. Usage: $threadgrabber <Thread link> <Relative 
download directory>")
      else:
        result = paramStr(1)
    
    proc getRawDownPath(): string =
      if os.paramCount() < 2:
        when not defined release:
          result = "out"
        else:
          quit("Download destination required. Usage: $threadgrabber <Thread 
link> <Relative download directory>")
      else:
        result = paramStr(2)
    
    proc main() {.async.} =
      var
        boardAndThread = parseBoardAndThread(getRawLink())
        downPath = getCurrentDir() & "/" & getRawDownPath()
        board = boardAndThread[0]
        thread = boardAndThread[1]
      if not downPath.existsDir():
        echo("Local path not recognized. Creating directory: ", downPath)
        createDir downPath
      var
        webClient = newAsyncHttpClient()
        link = getAPILink(board, thread)
        j: string = await webClient.getContent(link)
        futures: seq[Future[void]]
      
      for node in parseJson(j)["posts"]:
        if node{"tim"} != nil:
          var
            tim = node["tim"].getInt()
            ext = node["ext"].getStr()
            downFileName = fmt"{downPath}/{tim}{ext}"
          echo("Downloading ", node.mediaLink(board, thread), " as ", 
downFileName, "...")
          var downloadFuture = webClient.downloadFile(node.mediaLink(board, 
thread), downFileName)
          downloadFuture.callback=
            proc() =
              echo("Downloading ", tim, ext, " Complete")
          futures &= downloadFuture
      waitFor futures.all()
    
    waitFor main()
    
    
    Run

The program crashes with vague error messages, complaining that the http 
version is not correct: 
[https://pastebin.com/2jXHKbMV](https://pastebin.com/2jXHKbMV)

I'm compiling with `--d:ssl --threads:on` flag. Any pointers? 

Reply via email to