###################
Python API Examples
###################

.. _pyexamples#connecting_to_server:

Connecting To A Server
======================

.. code-block:: python

    from jetstream import JetStream

    serverAddress = 'localhost'
    serverPort = 8886   # default TCP client API control port.

    api = JetStream().api(serverAddress, serverPort)
    api.connect()

You can also use the ``api`` interface as a *context manager*:

.. code-block:: python

    with api:
        # Interface is connected...
        pass

    # Interface automatically disconnects.


Authenticating With a Server
============================
This assumes you have an API interface connected to a server. See :ref:`pyexamples#connecting_to_server`.

The following command will authenticate with the server as user 'jsmith' and password 'secret'. The :meth:`~.jetstream.serverinterface.ServerInterface.auth` method returns ``None`` on succes and throws an exception if there was an error.

.. code-block:: python

    >>> api.server.auth('jsmith', 'secret')
    None

Alternatively, you can use :meth:`~.jetstream.serverinterface.ServerInterface.authAsync` method to authenticate asynchronously. For more information about the asynchronous API interface, see :ref:`async#asynchronous-requests-vs-ongoing-tasks`.

.. code-block:: python

    >>> auth_request = api.server.authAsync('jsmith', 'secret')
    {'requestId': 1}

    >>> api.server.getRequestStatus(auth_request)
    {'errorMessage': '', 'processing': False, 'status': 'complete'}

    >>> api.server.getRequestResult(auth_request)
    None



.. _pyexamples#creating_manifest:

Creating a Manifest
===================
This assumes you have an API interface connected to a server. See :ref:`pyexamples#connecting_to_server`.

The following command will initialize a manifest that, when attached to a transfer, will send
the local file ``/local/home/readme.txt`` to a destination, saving it at the path ``/data/docs/readme.txt``.

Use :meth:`~.jetstream.sendinterface.SendInterface.createManifest` to initiate manifest creation:

.. code-block:: python

    >>> mappings = {'/data/docs/readme.txt': '/local/home/readme.txt'}
    >>> manifest = api.send.createManifest(mappings=mappings)
    >>> manifest
    {'status': 'pending', 'processing': True, 'totalFiles': None, 'totalSize': None, 'errorMessage': None, 'manifestId': '2'}


Monitoring a Manifest
=====================
A manifest is created immediately. However, before you can attach the manifest to a transfer, it
must finish its initialization. There are two ways to wait for completion:

    1. Use :meth:`~.jetstream.sendinterface.SendInterface.getManifest` and inspect the ``processing`` field.

       .. code-block:: python

           >>> manifest = api.send.getManifest(manifest)
           >>> manifest
           {'processing': True, 'status': 'pending', ' manifestId': '2'}

           ...

           >>> manifest = api.send.getManifest(manifest)
           >>> manifest
           {'processing': False, 'status': 'complete', 'manifestId': '2'}

       While waiting for a manifest, use the ``processing`` field to determine whether the manifest
       is still being processed by the server. The ``status`` field should only be used for informational
       purposes until the manifest has been completed.

       .. code-block:: python

           manifest = api.send.getManifest(manifest)
           while manifest['processing']:
               status = manifest['status']
               sleep(1)
               manifest = api.send.getManifest(manifest)

    2. Use :meth:`~.jetstream.sendinterface.SendInterface.waitForManifest` to block until the manifest is completed.

       .. code-block:: python

           >>> manifest = api.send.waitForManifest(manifest)
           >>> manifest
           {'processing': False, 'status': 'complete', 'manifestId': '2'}

      Note that :meth:`~.jetstream.sendinterface.SendInterface.waitForManifest` *will block*. If a manifest is
      large, your script may become unresponsive for a long time. 

There are two conditions in which a manifest stops being processed by the server. When a manifest
stops, the ``processing`` field will switch to ``False``, and the ``status`` field will indicate the
condition of the manifest.

    * ``complete``: The manifest has been completed successfully.
    * ``error``: The manifest failed. The ``errorMessage`` field will contain a description of the error.

.. code-block:: python

    manifest = api.send.waitForManifest(manifest)

    if manifest['status'] == 'error':
        raise MyError('The manifest failed, because {reason}'.format(reason=manifest['errorMessage']))

When a manifest has initialized successfully, its ``totalFiles`` and ``totalSize`` fields will
reflect the size of the manifest.

.. code-block:: python

    >>> manifest = api.send.waitForManifest(manifest)
    >>> manifest
    {'status': 'complete', 'totalFiles': 1, 'totalSize': 1091, 'manifestId': '2'}

Note that creating a manifest does not begin sending its files. For this, you need to attach the
manifest to a *transfer*, which is sent to a *destination*.

Deleting a Manifest
===================

The following command will delete a specified manifest.

Use :meth:`~.jetstream.sendinterface.SendInterface.deleteManifest` to initiate manifest deletion:

.. code-block:: python

    >>> manifest = api.send.deleteManifest(manifest)
    >>> manifest
    *null*

Note that a manifest may be deleted at any time, even if it has been used to initiate a transfer which is currently active.

.. _pyexamples#creating_destination:

Creating a Destination
======================
This assumes you have an API interface connected to a server. See :ref:`pyexamples#connecting_to_server`.

Before you can start a file transfer, you must create a destination.

.. code-block:: python

    >>> destinationAddress = 'localhost'
    >>> destinationPort = 8886  # default destination port

    >>> destination = api.send.createDestination(destinationAddress, destinationPort=destinationPort)
    {'destinationId': '42', 'destinationAddress': 'localhost', 'destinationPort': 8886, 'destinationIP': '127.0.0.1'}

There are many more fields returned than what is shown here. The important one is ``destinationId``.
The destination ID is required to initiate a file transfer. 


Creating a Transfer
===================
This assumes you have an API interface connected to a server. See :ref:`pyexamples#connecting_to_server`.

We'll use the :ref:`destination <pyexamples#creating_destination>` and :ref:`manifest <pyexamples#creating_manifest>` prepared above.

.. code-block:: python

    >>> transfer = api.send.createTransfer(destination, manifest)
    >>> transfer
    {'transferId': '17', 'processing': True, 'status': 'pending', 'destinationId': '42'}

There are many more fields returned than what is shown here. The important one is ``transferId``.
The transfer ID is required to monitor the status of the transfer.


Monitoring A Transfer
=====================
There are two ways to monitor a transfer:

    1. Use :meth:`~.jetstream.sendinterface.SendInterface.getTransfer` and inspect the ``processing`` field.

       .. code-block:: python

           >>> transfer = api.send.getTransfer(transfer)
           >>> transfer
           {'processing': True, 'status': 'sending', 'transferId': '17'}

           ...

           >>> transfer = api.send.getTransfer(transfer)
           >>> transfer
           {'processing': False, 'status': 'complete', 'transferId': '17'}

       While waiting for a transfer, use the ``processing`` field to determine whether the transfer
       is still being processed by the server. The ``status`` field should only be used for informational
       purposes until the transfer has stopped.

       .. code-block:: python

           transfer = api.send.getTransfer(transfer)
           while transfer['processing']:
               status = transfer['status']
               sleep(1)
               transfer = api.send.getTransfer(transfer)

    2. Use :meth:`~.jetstream.sendinterface.SendInterface.waitForTransfer` to block until the file send is completed.

       .. code-block:: python

           >>> transfer = api.send.waitForTransfer(transfer)
           >>> transfer
           {'processing': False, 'status': 'complete', 'transferId': '17'}

       Note that :meth:`~.jetstream.sendinterface.SendInterface.waitForTransfer` *will block*. If a transfer is
       large, your script may become unresponsive for a long time. 

There are three conditions in which a transfer stops being processed by the server. When a transfer
stops, the ``processing`` field will switch to ``False``, and the ``status`` field will indicate the
condition of the transfer.

    * ``complete``: The transfer has been completed successfully.
    * ``suspended``: The transfer was suspended. Use :meth:`~.jetstream.sendinterface.SendInterface.resumeTransfer` to resume transmitting.
    * ``error``: The transfer failed. The ``errorMessage`` field will contain a description of the error.

    .. code-block:: python

        transfer = api.send.waitForTransfer(transfer)

        if transfer['status'] == 'error':
            raise MyError('The transfer failed, because {reason}'.format(reason=transfer['errorMessage']))

        if transfer['status'] == 'suspended':
            print('The transfer has been paused.')


.. _pyexamples#creating_shared_token:

Creating a Shared Token
=======================
This assumes you have an API interface connected to a server. See :ref:`pyexamples#connecting_to_server`.

The following command will create a token that can be used to share files with third-parties who don't have an account on the server: We'll use the :ref:`manifest <pyexamples#creating_manifest>` prepared above.

.. code-block:: python

    >>> token = api.send.createSharedToken(manifest)
    >>> token
    {'creationTime': 1513291572659128, 'description': '', 'downloadCount': 0, 'downloadLimit': None, 'expiryTime': None, 'manifestId': '2', 'owner': 'user', 'passwordRequired': False, 'token': 'MAYWEBRO.TRUPO.VEVEEBLU'}


Using a Shared Token
====================
This assumes you have an API interface connected to a server. See :ref:`pyexamples#connecting_to_server`.

The following command will initialize a download using a given token. We'll use the :ref:`token <pyexamples#creating_shared_token>` and :ref:`destination <pyexamples#creating_destination>` prepared above.

.. code-block:: python

    >>> api.server.authToken('MAYWEBRO.TRUPO.VEVEEBLU')
    None

    >>> manifests = api.send.getManifests()
    >>> manifests
    [{'errorMessage': None, 'manifestId': u'2', 'owner': u'', 'processing': False, 'status': u'complete', 'totalFiles': 1, 'totalSize': 1152}]

    >>> transfer = api.send.createTransfer(destination, manifests[0])
    >>> transfer
    {'transferId': '17', 'processing': True, 'status': 'pending', 'destinationId': '42'}


