camstreamerlib
Version:
Helper library for CamStreamer ACAP applications.
153 lines (152 loc) • 6.6 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WsClient = void 0;
const EventEmitter = require("events");
const WebSocket = require("ws");
const Digest_1 = require("./Digest");
class WsClient extends EventEmitter {
constructor(options) {
var _a, _b, _c, _d, _e, _f, _g, _h;
super();
this.isAlive = true;
this.isClosed = false;
const tls = (_a = options === null || options === void 0 ? void 0 : options.tls) !== null && _a !== void 0 ? _a : false;
const tlsInsecure = (_b = options === null || options === void 0 ? void 0 : options.tlsInsecure) !== null && _b !== void 0 ? _b : false;
const ip = (_c = options === null || options === void 0 ? void 0 : options.ip) !== null && _c !== void 0 ? _c : '127.0.0.1';
const port = (_d = options === null || options === void 0 ? void 0 : options.port) !== null && _d !== void 0 ? _d : (tls ? 443 : 80);
this.user = (_e = options === null || options === void 0 ? void 0 : options.user) !== null && _e !== void 0 ? _e : '';
this.pass = (_f = options === null || options === void 0 ? void 0 : options.pass) !== null && _f !== void 0 ? _f : '';
const protocol = tls ? 'wss' : 'ws';
this.address = `${protocol}://${ip}:${port}${options.address}`;
this.digestAddress = options.address;
this.pingInterval = (_g = options.pingInterval) !== null && _g !== void 0 ? _g : 30000;
this.protocol = options.protocol;
this.wsOptions = {
auth: `${this.user}:${this.pass}`,
rejectUnauthorized: !tlsInsecure,
headers: (_h = options.headers) !== null && _h !== void 0 ? _h : {},
};
}
open(wwwAuthenticateHeader) {
try {
if (this.ws !== undefined) {
return;
}
this.isClosed = false;
if (this.protocol === undefined) {
this.ws = new WebSocket(this.address, this.wsOptions);
}
else {
this.ws = new WebSocket(this.address, this.protocol, this.wsOptions);
}
this.ws.binaryType = 'arraybuffer';
this.isAlive = true;
this.pingTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
var _a;
if ((this.ws && this.ws.readyState !== WebSocket.OPEN) || this.isAlive === false) {
this.emit('error', new Error('Connection timeout'));
yield this.closeWsConnection();
}
else {
this.isAlive = false;
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.ping();
}
}), this.pingInterval);
this.ws.on('pong', () => {
this.isAlive = true;
});
if (wwwAuthenticateHeader !== undefined) {
this.wsOptions.headers['Authorization'] = new Digest_1.Digest().getAuthHeader(this.user, this.pass, 'GET', this.digestAddress, wwwAuthenticateHeader);
}
this.ws.on('unexpected-response', (req, res) => __awaiter(this, void 0, void 0, function* () {
var _b;
if (res.statusCode === 401 && res.headers['www-authenticate'] !== undefined) {
if (this.pingTimer) {
clearInterval(this.pingTimer);
}
(_b = this.ws) === null || _b === void 0 ? void 0 : _b.removeAllListeners();
this.ws = undefined;
this.open(res.headers['www-authenticate']);
}
else {
this.emit('error', new Error('Status code: ' + res.statusCode));
yield this.closeWsConnection();
}
}));
this.ws.on('open', () => this.emit('open'));
this.ws.on('message', (data) => this.emit('message', data));
this.ws.on('error', (error) => {
this.emit('error', error);
this.closeWsConnection();
});
this.ws.on('close', () => this.closeWsConnection());
}
catch (error) {
this.emit('error', error instanceof Error ? error : new Error('Unknown error'));
this.closeWsConnection();
}
}
send(data) {
if (this.ws === undefined) {
throw new Error("This websocket hasn't been opened yet.");
}
if (this.ws.readyState === this.ws.OPEN) {
this.ws.send(data);
}
}
close() {
if (this.isClosed) {
return;
}
this.isClosed = true;
this.closeWsConnection();
}
reconnect() {
this.closeWsConnection();
}
closeWsConnection() {
if (this.ws === undefined) {
return;
}
const wsCopy = this.ws;
this.ws = undefined;
try {
if (this.pingTimer) {
clearInterval(this.pingTimer);
}
wsCopy.removeAllListeners();
wsCopy.on('error', () => { });
if (wsCopy.readyState !== WebSocket.CLOSING && wsCopy.readyState !== WebSocket.CLOSED) {
wsCopy.close();
}
setTimeout(() => {
if (wsCopy.readyState !== WebSocket.CLOSED) {
wsCopy.terminate();
}
}, 5000);
this.emit('close');
}
catch (err) {
console.error(err);
}
finally {
const shouldRestart = !this.isClosed;
setTimeout(() => {
wsCopy.removeAllListeners();
if (shouldRestart && !this.isClosed) {
this.open();
}
}, 10000);
}
}
}
exports.WsClient = WsClient;