std/asyncftpclient

    Dark Mode
Search:
  Source   Edit

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 std/[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 std/[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 std/[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())

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
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
FtpEventType = enum
  EvTransferProgress, EvLines, EvRetr, EvStore
  Source   Edit
FtpJobType = enum
  JRetrText, JRetr, JStore
  Source   Edit
ProgressChangedProc = proc (total, progress: BiggestInt; speed: float): Future[
    void] {.closure, ...gcsafe.}
  Source   Edit
ReplyError = object of IOError
  Source   Edit

Procs

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 chmod(ftp: AsyncFtpClient; path: string; permissions: set[FilePermission]): owned(
    Future[void]) {....raises: [Exception], tags: [RootEffect].}
Changes permission of path to permissions.   Source   Edit
proc connect(ftp: AsyncFtpClient): owned(Future[void]) {....raises: [Exception],
    tags: [RootEffect].}
Connect to the FTP server specified by ftp.   Source   Edit
proc createDir(ftp: AsyncFtpClient; dir: string; recursive = false): owned(
    Future[void]) {....raises: [Exception], tags: [RootEffect].}
Creates a directory dir. If recursive is true, the topmost subdirectory of dir will be created first, following the secondmost... etc. this allows you to give a full path as the dir without worrying about subdirectories not existing.   Source   Edit
proc defaultOnProgressChanged(total, progress: BiggestInt; speed: float): Future[
    void] {.nimcall, ...gcsafe, raises: [Exception], tags: [RootEffect].}
Default FTP onProgressChanged handler. Does nothing.   Source   Edit
proc fileExists(ftp: AsyncFtpClient; file: string): Future[bool] {.
    ...raises: [Exception, ValueError], tags: [RootEffect].}
Determines whether file exists.   Source   Edit
proc list(ftp: AsyncFtpClient; dir = ""): Future[string] {.
    ...raises: [Exception, ValueError], tags: [RootEffect].}
Lists all files in dir. If dir is "", uses the current working 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 dir is "", the current directory is used. If async is true, this function will return immediately and it will be your job to use asyncdispatch's poll to progress this operation.   Source   Edit
proc newAsyncFtpClient(address: string; port = Port(21); user, pass = "";
                       progressInterval: int = 1000): AsyncFtpClient {.
    ...raises: [OSError, Exception], tags: [RootEffect].}
Creates a new AsyncFtpClient object.   Source   Edit
proc pwd(ftp: AsyncFtpClient): Future[string] {....raises: [Exception, ValueError],
    tags: [RootEffect].}
Returns the current working directory.   Source   Edit
proc removeDir(ftp: AsyncFtpClient; dir: string): owned(Future[void]) {.
    ...raises: [Exception], tags: [RootEffect].}
Delete a directory dir on the remote FTP server   Source   Edit
proc removeFile(ftp: AsyncFtpClient; filename: string): owned(Future[void]) {.
    ...raises: [Exception], tags: [RootEffect].}
Delete a file filename on the remote FTP server   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_from to new name name_to   Source   Edit
proc retrFile(ftp: AsyncFtpClient; file, dest: string;
              onProgressChanged: ProgressChangedProc = defaultOnProgressChanged): owned(
    Future[void]) {....raises: [Exception],
                    tags: [RootEffect, TimeEffect, WriteIOEffect].}
Downloads file and saves it to dest. The EvRetr event is passed to the specified handleEvent function when the download is finished. The event's filename field will be equal to file.   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 send(ftp: AsyncFtpClient; m: string): Future[string] {.
    ...raises: [Exception, ValueError], tags: [RootEffect].}

Send a message to the server, and wait for a primary reply. \c\L is added for you.

You need to make sure that the message m doesn't contain any newline characters. Failing to do so will raise AssertionDefect.

Note: The server may return multiple lines of coded replies.

  Source   Edit
proc store(ftp: AsyncFtpClient; file, dest: string;
           onProgressChanged: ProgressChangedProc = defaultOnProgressChanged): owned(
    Future[void]) {....raises: [Exception],
                    tags: [RootEffect, ReadIOEffect, TimeEffect].}
Uploads file to dest on the remote FTP server. Usage of this function asynchronously is recommended to view the progress of the download. The EvStore event is passed to the specified handleEvent function when the upload is finished, and the filename field will be equal to file.   Source   Edit