"use strict";
/**
 * DataAPI backed by tokens for logging and precedence
 *
 *  Copyright (C) 2010-2019 R-T Specialty, LLC.
 *
 *  This file is part of liza.
 *
 *  liza is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenedDataApi = void 0;
var ContextError_1 = require("../../error/ContextError");
/**
 * Wrap DataAPI request in a token
 *
 * If another request is made before the first finishes, then the first will
 * return in error stating that it has been superceded.  Under normal
 * circumstances, this otherwise acts like a typical DataAPI, with the
 * side-effect of having tokens created and replies logged.
 *
 * TODO: log inputs to token as data?
 */
var TokenedDataApi = /** @class */ (function () {
    /**
     * Wrap DataAPI
     *
     * The provided DataAPI will be wrapped such that requests will have
     * tokens created, namespaced to the id of the request.  A token store
     * will be created using the provided `_tstoreCtor` for each such id.
     *
     * @param _api        - DataAPI to decorate
     * @param _tstoreCtor - `TokenStore` constructor by namespace
     */
    function TokenedDataApi(_api, _tstoreCtor) {
        this._api = _api;
        this._tstoreCtor = _tstoreCtor;
    }
    /**
     * Perform request and generate corresponding token
     *
     * A token is created before each request using a store initialized to a
     * namespace identified by `id`.  If a token associated with a request
     * is still the most recently created token for that namespace by the
     * time the request completes, then the request is fulfilled as
     * normal.  But if another request has since been made in the same
     * namespace, then the request is considered to be superceded, and is
     * rejected in error.
     *
     * The token will be completed in either case so that there is a log of
     * the transaction.
     *
     * @param data     - request data
     * @param callback - success/failure callback
     * @param id       - unique dapi identifier
     *
     * @return self
     */
    TokenedDataApi.prototype.request = function (data, callback, id) {
        var _this = this;
        var store = this._tstoreCtor(id);
        // TODO: we should probably store raw data rather than converting it
        // to JSON
        store
            .createToken()
            .then(function (token) {
            return _this._dapiRequest(data, id).then(function (resp_data) {
                return store
                    .completeToken(token, JSON.stringify(resp_data))
                    .then(function (newtok) {
                    return _this._replyUnlessStale(store, newtok, resp_data, callback, id);
                });
            });
        })
            .catch(function (e) { return callback(e, null); });
        return this;
    };
    /**
     * Wrap underlying DataAPI request in a Promise
     *
     * The `DataApi` interface still uses the oldschool Node
     * callbacks.  This lifts it into a Promise.
     *
     * @param data - request data
     * @param id   - DataAPI id
     *
     * @return request as a Promise
     */
    TokenedDataApi.prototype._dapiRequest = function (data, id) {
        var _this = this;
        return new Promise(function (resolve, reject) {
            _this._api.request(data, function (e, resp_data) {
                if (e || resp_data === null) {
                    return reject(e);
                }
                resolve(resp_data);
            }, id);
        });
    };
    /**
     * Invoke callback successfully with data unless the request is stale
     *
     * A request is stale/superceded if it is not the most recently created
     * token for the namespace, implying that another request has since
     * taken place.
     *
     * @param newtok    - completed token
     * @param resp_data - response data from underlying DataAPI
     * @param callback  - success/failure callback
     * @param id        - DataApi id
     */
    TokenedDataApi.prototype._replyUnlessStale = function (store, newtok, resp_data, callback, id) {
        if (newtok.last_created) {
            return store
                .acceptToken(newtok, null)
                .then(function () { return callback(null, resp_data); });
        }
        return store
            .killToken(newtok, null)
            .then(function () {
            return callback(ContextError_1.context(Error('Request superceded'), { id: id }), null);
        });
    };
    return TokenedDataApi;
}());
exports.TokenedDataApi = TokenedDataApi;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9rZW5lZERhdGFBcGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJUb2tlbmVkRGF0YUFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7OztBQUtILHlEQUFpRDtBQUtqRDs7Ozs7Ozs7O0dBU0c7QUFDSDtJQUNFOzs7Ozs7Ozs7T0FTRztJQUNILHdCQUNtQixJQUFhLEVBQ2IsV0FBMkI7UUFEM0IsU0FBSSxHQUFKLElBQUksQ0FBUztRQUNiLGdCQUFXLEdBQVgsV0FBVyxDQUFnQjtJQUMzQyxDQUFDO0lBRUo7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FtQkc7SUFDSCxnQ0FBTyxHQUFQLFVBQ0UsSUFBa0IsRUFDbEIsUUFBcUMsRUFDckMsRUFBVTtRQUhaLGlCQXVCQztRQWxCQyxJQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFpQixFQUFFLENBQUMsQ0FBQztRQUVuRCxvRUFBb0U7UUFDcEUsVUFBVTtRQUNWLEtBQUs7YUFDRixXQUFXLEVBQUU7YUFDYixJQUFJLENBQUMsVUFBQSxLQUFLO1lBQ1QsT0FBQSxLQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBQSxTQUFTO2dCQUN4QyxPQUFBLEtBQUs7cUJBQ0YsYUFBYSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDO3FCQUMvQyxJQUFJLENBQUMsVUFBQSxNQUFNO29CQUNWLE9BQUEsS0FBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxFQUFFLENBQUM7Z0JBQTlELENBQThELENBQy9EO1lBSkgsQ0FJRyxDQUNKO1FBTkQsQ0FNQyxDQUNGO2FBQ0EsS0FBSyxDQUFDLFVBQUEsQ0FBQyxJQUFJLE9BQUEsUUFBUSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsRUFBakIsQ0FBaUIsQ0FBQyxDQUFDO1FBRWpDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7Ozs7O09BVUc7SUFDSyxxQ0FBWSxHQUFwQixVQUFxQixJQUFrQixFQUFFLEVBQVU7UUFBbkQsaUJBY0M7UUFiQyxPQUFPLElBQUksT0FBTyxDQUFDLFVBQUMsT0FBTyxFQUFFLE1BQU07WUFDakMsS0FBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQ2YsSUFBSSxFQUNKLFVBQUMsQ0FBQyxFQUFFLFNBQVM7Z0JBQ1gsSUFBSSxDQUFDLElBQUksU0FBUyxLQUFLLElBQUksRUFBRTtvQkFDM0IsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7aUJBQ2xCO2dCQUVELE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNyQixDQUFDLEVBQ0QsRUFBRSxDQUNILENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7T0FXRztJQUNLLDBDQUFpQixHQUF6QixVQUNFLEtBQWlCLEVBQ2pCLE1BQThCLEVBQzlCLFNBQXdCLEVBQ3hCLFFBQXFDLEVBQ3JDLEVBQVU7UUFFVixJQUFJLE1BQU0sQ0FBQyxZQUFZLEVBQUU7WUFDdkIsT0FBTyxLQUFLO2lCQUNULFdBQVcsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO2lCQUN6QixJQUFJLENBQUMsY0FBTSxPQUFBLFFBQVEsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLEVBQXpCLENBQXlCLENBQUMsQ0FBQztTQUMxQztRQUVELE9BQU8sS0FBSzthQUNULFNBQVMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO2FBQ3ZCLElBQUksQ0FBQztZQUNKLE9BQUEsUUFBUSxDQUFDLHNCQUFPLENBQUMsS0FBSyxDQUFDLG9CQUFvQixDQUFDLEVBQUUsRUFBQyxFQUFFLEVBQUUsRUFBRSxFQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7UUFBOUQsQ0FBOEQsQ0FDL0QsQ0FBQztJQUNOLENBQUM7SUFDSCxxQkFBQztBQUFELENBQUMsQUF2SEQsSUF1SEM7QUF2SFksd0NBQWMifQ==