asyncftpclient
This module implements an asynchronous FTP client. It allows you to connect to an FTP server and perform operations on it such as for example:
- The upload of new files.
 - The removal of existing files.
 - Download of files.
 - Changing of files' permissions.
 - Navigation through the FTP server's directories.
 
Connecting to an FTP server
In order to begin any sort of transfer of files you must first connect to an FTP server. You can do so with the connect procedure.
import asyncdispatch, asyncftpclient
proc main() {.async.} =
  var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
  await ftp.connect()
  echo("Connected")
waitFor(main())
A new main async procedure must be declared to allow the use of the await keyword. The connection will complete asynchronously and the client will be connected after the await ftp.connect() call.
Uploading a new file
After a connection is made you can use the store procedure to upload a new file to the FTP server. Make sure to check you are in the correct working directory before you do so with the pwd procedure, you can also instead specify an absolute path.
import asyncdispatch, asyncftpclient
proc main() {.async.} =
  var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
  await ftp.connect()
  let currentDir = await ftp.pwd()
  assert currentDir == "/home/user/"
  await ftp.store("file.txt", "file.txt")
  echo("File finished uploading")
waitFor(main()) Checking the progress of a file transfer
The progress of either a file upload or a file download can be checked by specifying a onProgressChanged procedure to the store or retrFile procedures.
Procs that take an onProgressChanged callback will call this every progressInterval milliseconds.
import asyncdispatch, asyncftpclient
proc onProgressChanged(total, progress: BiggestInt,
                        speed: float) {.async.} =
  echo("Uploaded ", progress, " of ", total, " bytes")
  echo("Current speed: ", speed, " kb/s")
proc main() {.async.} =
  var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test", progressInterval = 500)
  await ftp.connect()
  await ftp.store("file.txt", "/home/user/file.txt", onProgressChanged)
  echo("File finished uploading")
waitFor(main())  Imports
Types
AsyncFtpClient = ref object csock*: AsyncSocket dsock*: AsyncSocket user*, pass*: string address*: string port*: Port progressInterval: int jobInProgress*: bool job*: FtpJob dsockConnected*: bool
- Source Edit
 FtpJobType = enum JRetrText, JRetr, JStore
- Source Edit
 FtpEventType = enum EvTransferProgress, EvLines, EvRetr, EvStore
- Source Edit
 FtpEvent = object filename*: string case typ*: FtpEventType of EvLines: lines*: string ## Lines that have been transferred. of EvRetr, EvStore: ## Retr/Store operation finished. nil of EvTransferProgress: bytesTotal*: BiggestInt ## Bytes total. bytesFinished*: BiggestInt ## Bytes transferred. speed*: BiggestInt ## Speed in bytes/s currentJob*: FtpJobType ## The current job being performed.- Event Source Edit
 ReplyError = object of IOError
- Source Edit
 ProgressChangedProc = proc (total, progress: BiggestInt; speed: float): Future[ void] {...}{.closure, gcsafe.}- Source Edit
 
Procs
proc send(ftp: AsyncFtpClient; m: string): Future[TaintedString] {...}{. raises: [Exception, ValueError], tags: [RootEffect].}-  
Send a message to the server, and wait for a primary reply.
\c\Lis added for you.You need to make sure that the message
mdoesn't contain any newline characters. Failing to do so will raiseAssertionDefect.Note: The server may return multiple lines of coded replies.
Source Edit proc connect(ftp: AsyncFtpClient): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}-  Connect to the FTP server specified by 
ftp. Source Edit proc pwd(ftp: AsyncFtpClient): Future[TaintedString] {...}{. raises: [Exception, ValueError], tags: [RootEffect].}- Returns the current working directory. Source Edit
 proc cd(ftp: AsyncFtpClient; dir: string): owned(Future[void]) {...}{. raises: [Exception], tags: [RootEffect].}-  Changes the current directory on the remote FTP server to 
dir. Source Edit proc cdup(ftp: AsyncFtpClient): owned(Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}- Changes the current directory to the parent of the current directory. Source Edit
 proc listDirs(ftp: AsyncFtpClient; dir = ""): Future[seq[string]] {...}{. raises: [Exception, ValueError], tags: [RootEffect].}-  Returns a list of filenames in the given directory. If 
diris "", the current directory is used. Ifasyncis true, this function will return immediately and it will be your job to use asyncdispatch'spollto progress this operation. Source Edit proc fileExists(ftp: AsyncFtpClient; file: string): Future[bool] {...}{. raises: [Exception, ValueError], tags: [RootEffect].}-  Determines whether 
fileexists. Source Edit proc createDir(ftp: AsyncFtpClient; dir: string; recursive = false): owned( Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}-  Creates a directory 
dir. Ifrecursiveis true, the topmost subdirectory ofdirwill be created first, following the secondmost... etc. this allows you to give a full path as thedirwithout worrying about subdirectories not existing. Source Edit proc chmod(ftp: AsyncFtpClient; path: string; permissions: set[FilePermission]): owned( Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}-  Changes permission of 
pathtopermissions. Source Edit proc list(ftp: AsyncFtpClient; dir = ""): Future[string] {...}{. raises: [Exception, ValueError], tags: [RootEffect].}-  Lists all files in 
dir. Ifdiris"", uses the current working directory. Source Edit proc retrText(ftp: AsyncFtpClient; file: string): Future[string] {...}{. raises: [Exception, ValueError], tags: [RootEffect].}-  Retrieves 
file. File must be ASCII text. Source Edit proc defaultOnProgressChanged(total, progress: BiggestInt; speed: float): Future[ void] {...}{.nimcall, gcsafe, raises: [Exception], tags: [RootEffect].}-  Default FTP 
onProgressChangedhandler. Does nothing. Source Edit proc retrFile(ftp: AsyncFtpClient; file, dest: string; onProgressChanged: ProgressChangedProc = defaultOnProgressChanged): owned( Future[void]) {...}{.raises: [Exception], tags: [RootEffect, TimeEffect, WriteIOEffect].}-  Downloads 
fileand saves it todest. TheEvRetrevent is passed to the specifiedhandleEventfunction when the download is finished. The event'sfilenamefield will be equal tofile. Source Edit proc store(ftp: AsyncFtpClient; file, dest: string; onProgressChanged: ProgressChangedProc = defaultOnProgressChanged): owned( Future[void]) {...}{.raises: [Exception], tags: [RootEffect, ReadIOEffect, TimeEffect].}-  Uploads 
filetodeston the remote FTP server. Usage of this function asynchronously is recommended to view the progress of the download. TheEvStoreevent is passed to the specifiedhandleEventfunction when the upload is finished, and thefilenamefield will be equal tofile. Source Edit proc rename(ftp: AsyncFtpClient; nameFrom: string; nameTo: string): owned( Future[void]) {...}{.raises: [Exception], tags: [RootEffect].}-  Rename a file or directory on the remote FTP Server from current name 
name_fromto new namename_toSource Edit proc removeFile(ftp: AsyncFtpClient; filename: string): owned(Future[void]) {...}{. raises: [Exception], tags: [RootEffect].}-  Delete a file 
filenameon the remote FTP server Source Edit proc removeDir(ftp: AsyncFtpClient; dir: string): owned(Future[void]) {...}{. raises: [Exception], tags: [RootEffect].}-  Delete a directory 
diron the remote FTP server Source Edit proc newAsyncFtpClient(address: string; port = Port(21); user, pass = ""; progressInterval: int = 1000): AsyncFtpClient {...}{. raises: [OSError, Exception], tags: [RootEffect].}-  Creates a new 
AsyncFtpClientobject. Source Edit 
    © 2006–2021 Andreas Rumpf
Licensed under the MIT License.
    https://nim-lang.org/docs/asyncftpclient.html