# asyncftpclient

- Manual
- Standard library
- Index

Search:
Group by:

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.

>     import asyncdispatch, asyncftpclient

>     proc onProgressChanged(total, progress: BiggestInt,
>                             speed: float): Future[void] =
>       echo("Uploaded ", progress, " of ", total, " bytes")
>       echo("Current speed: ", speed, " kb/s")

>     proc main() {.async.} =
>       var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
>       await ftp.connect()
>       await ftp.store("file.txt", "/home/user/file.txt", onProgressChanged)
>       echo("File finished uploading")
>     waitFor(main())

# Imports

asyncdispatch, asyncnet, nativesockets, strutils, parseutils, os, times, net

# Types

    AsyncFtpClient = ref object
      csock*: AsyncSocket
      dsock*: AsyncSocket
      user*, pass*: string
      address*: string
      port*: Port
      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, FutureError], tags: [RootEffect].}

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

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

  Source Edit

    proc connect(ftp: AsyncFtpClient): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], tags: [RootEffect].}

  Connect to the FTP server specified by `ftp`. Source Edit

    proc pwd(ftp: AsyncFtpClient): Future[TaintedString] {...}{.
        raises: [Exception, ValueError, FutureError], tags: [RootEffect].}

  Returns the current working directory. Source Edit

    proc cd(ftp: AsyncFtpClient; dir: string): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], tags: [RootEffect].}

  Changes the current directory on the remote FTP server to `dir`. Source Edit

    proc cdup(ftp: AsyncFtpClient): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], 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, FutureError], 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 existsFile(ftp: AsyncFtpClient; file: string): Future[bool] {...}{.
        raises: [Exception, ValueError, FutureError], tags: [RootEffect].}

  Determines whether `file` exists. Source Edit

    proc createDir(ftp: AsyncFtpClient; dir: string; recursive = false): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], 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 chmod(ftp: AsyncFtpClient; path: string; permissions: set[FilePermission]): owned(
        Future[void]) {...}{.raises: [Exception, FutureError], tags: [RootEffect].}

  Changes permission of `path` to `permissions`. Source Edit

    proc list(ftp: AsyncFtpClient; dir = ""): Future[string] {...}{.
        raises: [Exception, ValueError, FutureError], tags: [RootEffect].}

  Lists all files in `dir`. If `dir` is `""`, uses the current working directory. Source Edit

    proc retrText(ftp: AsyncFtpClient; file: string): Future[string] {...}{.
        raises: [Exception, ValueError, FutureError], tags: [RootEffect].}

  Retrieves `file`. File must be ASCII text. Source Edit

    proc defaultOnProgressChanged(total, progress: BiggestInt; speed: float): Future[void] {...}{.
        nimcall, gcsafe, procvar, raises: [FutureError, Exception], tags: [RootEffect].}

  Default FTP `onProgressChanged` handler. Does nothing. Source Edit

    proc retrFile(ftp: AsyncFtpClient; file, dest: string;
                 onProgressChanged: ProgressChangedProc = defaultOnProgressChanged): owned(
        Future[void]) {...}{.raises: [Exception, FutureError],
                       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 store(ftp: AsyncFtpClient; file, dest: string;
              onProgressChanged: ProgressChangedProc = defaultOnProgressChanged): owned(
        Future[void]) {...}{.raises: [Exception, FutureError],
                       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

    proc rename(ftp: AsyncFtpClient; nameFrom: string; nameTo: string): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], 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 removeFile(ftp: AsyncFtpClient; filename: string): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], tags: [RootEffect].}

  Delete a file `filename` on the remote FTP server Source Edit

    proc removeDir(ftp: AsyncFtpClient; dir: string): owned(Future[void]) {...}{.
        raises: [Exception, FutureError], tags: [RootEffect].}

  Delete a directory `dir` on the remote FTP server Source Edit

    proc newAsyncFtpClient(address: string; port = Port(21); user, pass = ""): AsyncFtpClient {...}{.
        raises: [OSError, Exception], tags: [RootEffect].}

  Creates a new `AsyncFtpClient` object. Source Edit