"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Watch = exports.DefaultRequest = void 0;
const byline = require("byline");
const request = require("request");
class DefaultRequest {
    constructor(requestImpl) {
        this.requestImpl = requestImpl ? requestImpl : request;
    }
    // Using request lib can be confusing when combining Stream- with Callback-
    // style API. We avoid the callback and handle HTTP response errors, that
    // would otherwise require a different error handling, in a transparent way
    // to the user (see github issue request/request#647 for more info).
    webRequest(opts) {
        const req = this.requestImpl(opts);
        // pause the stream until we get a response not to miss any bytes
        req.pause();
        req.on('response', (resp) => {
            if (resp.statusCode === 200) {
                req.resume();
            }
            else {
                const error = new Error(resp.statusMessage);
                error.statusCode = resp.statusCode;
                req.emit('error', error);
            }
        });
        return req;
    }
}
exports.DefaultRequest = DefaultRequest;
class Watch {
    constructor(config, requestImpl) {
        this.config = config;
        if (requestImpl) {
            this.requestImpl = requestImpl;
        }
        else {
            this.requestImpl = new DefaultRequest();
        }
    }
    // Watch the resource and call provided callback with parsed json object
    // upon event received over the watcher connection.
    //
    // "done" callback is called either when connection is closed or when there
    // is an error. In either case, watcher takes care of properly closing the
    // underlaying connection so that it doesn't leak any resources.
    async watch(path, queryParams, callback, done) {
        const cluster = this.config.getCurrentCluster();
        if (!cluster) {
            throw new Error('No currently active cluster');
        }
        const url = cluster.server + path;
        queryParams.watch = true;
        const headerParams = {};
        const requestOptions = {
            method: 'GET',
            qs: queryParams,
            headers: headerParams,
            uri: url,
            useQuerystring: true,
            json: true,
            pool: false,
        };
        await this.config.applyToRequest(requestOptions);
        let req;
        let doneCalled = false;
        const doneCallOnce = (err) => {
            if (!doneCalled) {
                req.abort();
                doneCalled = true;
                done(err);
            }
        };
        req = this.requestImpl.webRequest(requestOptions);
        const stream = byline.createStream();
        req.on('error', doneCallOnce);
        req.on('socket', (socket) => {
            socket.setTimeout(30000);
            socket.setKeepAlive(true, 30000);
        });
        stream.on('error', doneCallOnce);
        stream.on('close', () => doneCallOnce(null));
        stream.on('data', (line) => {
            let data;
            try {
                data = JSON.parse(line);
            }
            catch (ignore) {
                // ignore parse errors
                return;
            }
            callback(data.type, data.object, data);
        });
        req.pipe(stream);
        return req;
    }
}
exports.Watch = Watch;
Watch.SERVER_SIDE_CLOSE = { error: 'Connection closed on server' };
//# sourceMappingURL=watch.js.map