"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MotionMasterReqResWebSocket = void 0;
const rxjs_1 = require("rxjs");
const webSocket_1 = require("rxjs/webSocket");
const logger_1 = require("./logger");
const types_1 = require("./types");
const util_1 = require("./util");
class MotionMasterReqResWebSocket {
    constructor() {
        this.opened$ = new rxjs_1.BehaviorSubject(false);
        this.close$ = new rxjs_1.Subject();
        this.alive$ = new rxjs_1.BehaviorSubject(false);
        this.message$ = new rxjs_1.Subject();
        this.aliveTimeoutId = 0;
        this.pingSystemObserver = { next: () => this.send({ request: { pingSystem: {} } }) };
    }
    get url() {
        return this._url;
    }
    get pingSystemInterval() {
        return this._pingSystemInterval;
    }
    get systemAliveTimeout() {
        return this._systemAliveTimeout;
    }
    open(url, pingSystemInterval = 250, systemAliveTimeout = 1000) {
        var _a;
        this._url = url;
        this._pingSystemInterval = pingSystemInterval;
        this._systemAliveTimeout = systemAliveTimeout;
        this.webSocket$ = this.createWebSocket(url, pingSystemInterval);
        (_a = this.webSocket$) === null || _a === void 0 ? void 0 : _a.pipe((0, rxjs_1.map)((data) => types_1.MotionMasterMessage.decode(data)), (0, rxjs_1.tap)(() => this.keepalive(systemAliveTimeout)), (0, rxjs_1.filter)((message) => { var _a; return !((_a = message.status) === null || _a === void 0 ? void 0 : _a.systemPong); }), (0, rxjs_1.map)((message) => (0, util_1.createPlainObjectFromMotionMasterMessage)(message)), (0, rxjs_1.tap)((message) => {
            const context = (0, util_1.convertMotionMasterMessageToLoggerContext)(message);
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            logger_1.logger.info(context, `Received ${context.name}`);
        })).subscribe({
            next: (message) => this.message$.next(message),
            error: (err) => {
                console.error(err);
                // ignore, clients will receive close$ event instead
            },
        });
    }
    close() {
        var _a;
        (_a = this.webSocket$) === null || _a === void 0 ? void 0 : _a.complete();
    }
    reopen() {
        if (this.url && this.opened$.value === false) {
            this.open(this.url, this.pingSystemInterval, this.systemAliveTimeout);
        }
    }
    send(message) {
        var _a, _b;
        if (!((_a = message.request) === null || _a === void 0 ? void 0 : _a.pingSystem)) {
            const context = (0, util_1.convertMotionMasterMessageToLoggerContext)(message);
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            logger_1.logger.info(context, `Send ${context.name}`);
        }
        (_b = this.webSocket$) === null || _b === void 0 ? void 0 : _b.next(types_1.MotionMasterMessage.encode(message).finish());
    }
    createWebSocket(url, pingSystemInterval = 250) {
        const webSocketConfig = {
            binaryType: 'arraybuffer',
            closeObserver: {
                next: (ev) => {
                    var _a;
                    (_a = this.pingSystemSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
                    clearTimeout(this.aliveTimeoutId);
                    this.alive$.next(false);
                    this.opened$.next(false);
                    this.close$.next({ code: ev.code, reason: ev.reason });
                    logger_1.logger.info(`Connection closed ${url}`);
                },
            },
            deserializer: (e) => new Uint8Array(e.data),
            openObserver: {
                next: () => {
                    this.pingSystemSubscription = (0, rxjs_1.interval)(pingSystemInterval).subscribe(this.pingSystemObserver);
                    this.opened$.next(true);
                    logger_1.logger.info(`Connection opened ${url}`);
                },
            },
            serializer: (value) => value,
            url,
        };
        return (0, webSocket_1.webSocket)(webSocketConfig);
    }
    keepalive(systemAliveTimeout = 1000) {
        if (this.alive$.getValue() === false) {
            this.alive$.next(true);
        }
        clearTimeout(this.aliveTimeoutId);
        this.aliveTimeoutId = setTimeout(() => this.alive$.next(false), systemAliveTimeout);
    }
}
exports.MotionMasterReqResWebSocket = MotionMasterReqResWebSocket;
//# sourceMappingURL=motion-master-req-res-web-socket.js.map