Home Reference Source Repository

src/auvsi-client.js

'use strict';

import request from 'request-promise-native';

import { verifyTelem } from './helpers';

/**
 * Client to interact with the AUVSI SUAS Interoperability Server.
 */
export default class AUVSIClient {
    /**
     * Create a new AUVSIClient.
     *
     * This does not handle logging in the server. To log in, see
     * {@link login}.
     */
    constructor() {
        this._setup();
    }

    /**
     * Whether or not the client is currently logged in.
     *
     * @type {boolean}
     */
    get loggedIn() {
        return this._loggedIn;
    }

    /**
     * The base URL of the interop server.
     *
     * This will be an empty string if not logged in.
     *
     * @type {string}
     */
    get url() {
        return this._url;
    }

    /**
     * Set up the base request function and logged out status.
     */
    _setup() {
        this._loggedIn = false;
        this._url = '';

        this._req = request.defaults({ jar: true });
    }

    /**
     * Send a base request.
     *
     * @private
     * @see https://github.com/request/request-promise-native#readme
     * @param  {Object} options           - Request options
     * @param  {string} options.url       - Interop server URL
     * @param  {string} options.uri       - Interop server endpoint
     * @param  {string} options.method    - Must be one of 'GET',
     *                                      POST', 'PUT', or 'DELETE'
     * @param  {Object} [options.headers] - Custom HTTP headers
     * @param  {string} [options.headers['content-type']]
     *                                    - Content type header
     * @param  {Object} [options.form]    - Encodes and sends a form
     * @param  {Object} [options.json]    - Send an object as json
     * @param  {number} [options.timeout=10000]
     *                                    - Request timeout in ms
     * @return {Promise<Response, Error>}
     */
    _request(options) {
        // If we're not logged in and we're not trying to, return an
        // error
        if (!this.loggedIn && options.url === undefined) {
            return Promise.reject(new Error('not logged in'));
        }

        options.url = (options.url || this.url) + options.uri;
        delete options.uri;

        options.resolveWithFullResponse = true;
        options.timeout = options.timeout || 10000;

        return this._req(options).then((response) => {
            if (!/^2/.exec(response.statusCode.toString())) {
                throw new Error(response.body || 'unknown error');
            }

            return response;
        });
    }

    /**
     * Log in to the interop server.
     *
     * @param  {string} url            - Interop url
     * @param  {string} username       - Interop username
     * @param  {string} password       - Interop password
     * @param  {number} [timeout=1000] - Request timeout in ms
     * @return {Promise<void, Error>}
     */
    login(url, username, password, timeout) {
        return this._request({
            method: 'POST',
            url,
            uri: '/api/login',
            form: { username, password },
            timeout
        }).then(() => {
            this._url = url;
            this._loggedIn = true;
        }).catch((err) => {
            this._url = '';
            throw err;
        });
    }

    /**
     * Log out of the interop server.
     *
     * @return {Promise<void, Error>}
     */
    logout() {
        this._setup();
    }

    /**
     * Post telemetry to the interop server.
     *
     * @param  {Telemetry} telem           - Telemetry to post
     * @param  {number}    [timeout=10000] - Request timeout in ms
     * @return {Promise<void, Error>}
     */
    postTelemetry(telem, timeout = 10000) {
        return verifyTelem(telem).then(() => this._request({
            method: 'POST',
            uri: '/api/telemetry',
            form: {
                latitude: telem.lat,
                longitude: telem.lon,
                altitude_msl: telem.alt_msl,
                uas_heading: telem.yaw
            },
            timeout
        }));
    }
}