@eclipse-ditto/ditto-javascript-client-node
Version:
Node.js(r) implementation of Eclipse Ditto JavaScript API.
135 lines • 4.75 kB
JavaScript
"use strict";
/*!
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeWebSocketBuilder = exports.NodeWebSocket = void 0;
const auth_provider_1 = require("../../api/src/auth/auth-provider");
const WebSocket = require("ws");
/**
* Converts a Map to a plain js object.
*
* @param aMap - the map to convert.
* @return the plain js object.
*/
const mapToPlainObject = (aMap) => {
const objects = [...aMap.entries()].map(([k, v]) => ({ [k]: v }));
return Object.assign({}, ...objects);
};
/**
* NodeJs implementation of a web socket requester.
*/
class NodeWebSocket {
constructor(webSocket, webSocketUrl, handler, options) {
this.webSocket = webSocket;
this.webSocketUrl = webSocketUrl;
this.handler = handler;
this.options = options;
this.connected = true;
this.setHandles();
}
/**
* Builds an instance of NodeWebSocket.
*
* @param url - The Url of the service.
* @param handler - The handler that gets called for responses from the web socket.
* @param authProviders - The auth providers to use.
* @param agent - The proxy agent to use to establish the connection.
* @return a Promise for the web socket connection.
*/
static buildInstance(url, handler, authProviders, agent) {
return new Promise(resolve => {
const [authenticatedUrl, authenticatedHeaders] = auth_provider_1.authenticateWithUrlAndHeaders(url, new Map(), authProviders);
const plainHeaders = mapToPlainObject(authenticatedHeaders);
const options = {
agent: NodeWebSocket.getProxyAgentForProtocol(url, agent),
rejectUnauthorized: false,
headers: plainHeaders
};
const plainUrl = authenticatedUrl.toString();
const webSocket = new WebSocket(plainUrl, options);
webSocket.on('open', () => {
resolve(new NodeWebSocket(webSocket, plainUrl, handler, options));
});
});
}
static getProxyAgentForProtocol(url, agent) {
if ('wss' === url.protocol) {
return agent.proxyAgent;
}
return agent.httpProxyAgent;
}
executeCommand(request) {
this.webSocket.send(request);
}
/**
* Reestablishes a failed web socket connection.
*
* @param retry - The amount of time to wait to reconnect.
* @return a Promise for the reestablished web socket connection.
*/
reconnect(retry) {
return new Promise((resolve, reject) => {
this.webSocket = new WebSocket(this.webSocketUrl, this.options);
this.webSocket.on('open', () => {
this.connected = true;
this.setHandles();
resolve(this);
});
setTimeout(() => {
if (this.connected) {
return;
}
if (retry <= 120000) {
console.log('Reconnect failed! Trying again!');
resolve(this.reconnect(retry * 2));
}
console.log('Reconnect failed!');
reject('Reconnect failed: Timed out');
}, retry);
});
}
/**
* Sets up the handler so it receives events from the web socket.
*/
setHandles() {
this.webSocket.on('message', data => {
this.handler.handleInput(data.toString());
});
this.webSocket.on('close', () => {
this.connected = false;
this.handler.handleClose(Promise.resolve(this.reconnect(1000)));
});
this.webSocket.on('error', event => {
this.handler.handleError(event.toString());
});
}
}
exports.NodeWebSocket = NodeWebSocket;
/**
* Builder for the Node implementation of a web socket.
*/
class NodeWebSocketBuilder {
constructor(agent) {
this.agent = agent;
}
withHandler(handler) {
return NodeWebSocket.buildInstance(this.dittoUrl, handler, this.authProviders, this.agent);
}
withConnectionDetails(url, authProviders) {
this.dittoUrl = url;
this.authProviders = authProviders;
return this;
}
}
exports.NodeWebSocketBuilder = NodeWebSocketBuilder;
//# sourceMappingURL=node-websocket.js.map