node-opcua-transport
Version:
pure nodejs OPCUA SDK - module transport
162 lines (161 loc) • 6.31 kB
JavaScript
;
/**
* @module node-opcua-transport
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientTCP_transport = void 0;
const node_net_1 = require("node:net");
const node_os_1 = __importDefault(require("node:os"));
const node_util_1 = require("node:util");
const chalk_1 = __importDefault(require("chalk"));
const node_opcua_assert_1 = require("node-opcua-assert");
const node_opcua_debug_1 = require("node-opcua-debug");
const client_transport_base_1 = require("./client_transport_base");
const tcp_transport_1 = require("./tcp_transport");
const tools_1 = require("./tools");
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
const errorLog = (0, node_opcua_debug_1.make_errorLog)(__filename);
const gHostname = node_os_1.default.hostname();
function createClientSocket(endpointUrl, timeout) {
// create a socket based on Url
const ep = (0, tools_1.parseEndpointUrl)(endpointUrl);
const port = parseInt(ep.port || "4840", 10);
const hostname = ep.hostname;
let socket;
switch (ep.protocol) {
case "opc.tcp:":
socket = (0, node_net_1.createConnection)({ host: hostname, port, timeout }, () => {
doDebug && debugLog(`connected to server! ${hostname}:${port} timeout:${timeout} `);
});
socket.setNoDelay(false);
socket.setKeepAlive(true, timeout >> 1);
return socket;
case "fake:":
(0, node_opcua_assert_1.assert)(ep.protocol === "fake:", " Unsupported transport protocol");
socket = (0, tcp_transport_1.getFakeTransport)();
return socket;
default: {
const msg = `[NODE-OPCUA-E05] this transport protocol is not supported :${ep.protocol}`;
errorLog(msg);
throw new Error(msg);
}
}
}
/**
* a ClientTCP_transport connects to a remote server socket and
* initiates a communication with a HEL/ACK transaction.
* It negotiates the communication parameters with the other end.
* @example
*
* ```javascript
* const transport = ClientTCP_transport(url);
*
* transport.timeout = 10000;
*
* transport.connect(function (err)) {
* if (err) {
* // cannot connect
* } else {
* // connected
*
* }
* });
* ....
*
* transport.write(message_chunk, 'F');
*
* ....
*
* transport.on("chunk", function (message_chunk) {
* // do something with chunk from server...
* });
*
*
* ```
*
*
*/
class ClientTCP_transport extends client_transport_base_1.ClientTransportBase {
dispose() {
/* c8 ignore next */
doDebug && debugLog(" ClientTCP_transport disposed");
super.dispose();
}
connect(endpointUrl, callback) {
this.endpointUrl = endpointUrl;
this.serverUri = `urn:${gHostname}:Sample`;
/* c8 ignore next */
doDebug && debugLog(chalk_1.default.cyan(`ClientTCP_transport#connect(endpointUrl = ${endpointUrl})`));
let socket = null;
try {
// validate the URL upfront so a parse error is reported synchronously
(0, tools_1.parseEndpointUrl)(endpointUrl);
socket = createClientSocket(endpointUrl, this.timeout);
socket.setTimeout(this.timeout >> 1, () => {
this.forceConnectionBreak();
});
}
catch (err) {
/* c8 ignore next */
doDebug && debugLog("CreateClientSocket has failed");
callback(err);
return;
}
const _on_socket_connect = () => {
/* c8 ignore next */
doDebug && debugLog("entering _on_socket_connect");
_remove_connect_listeners();
this._perform_HEL_ACK_transaction((err) => {
if (!err) {
/* c8 ignore next */
if (!this._socket) {
return callback(new Error("Abandoned"));
}
// install the post-connect "connection break" detector inherited from ClientTransportBase
this._install_post_connect_error_handler(endpointUrl);
/**
* notify the observers that the transport is connected (the socket is connected and the the HEL/ACK
* transaction has been done)
* @event connect
*/
this.emit("connect");
}
else {
debugLog("_perform_HEL_ACK_transaction has failed with err=", err.message);
}
callback(err);
});
};
const _on_socket_error_for_connect = (err) => {
// this handler will catch attempt to connect to an inaccessible address.
/* c8 ignore next */
doDebug && debugLog(chalk_1.default.cyan("ClientTCP_transport#connect - _on_socket_error_for_connect"), err.message);
(0, node_opcua_assert_1.assert)(node_util_1.types.isNativeError(err));
_remove_connect_listeners();
callback(err);
};
const _on_socket_end_for_connect = () => {
/* c8 ignore next */
doDebug &&
debugLog(chalk_1.default.cyan("ClientTCP_transport#connect -> _on_socket_end_for_connect Socket has been closed by server"));
};
const _remove_connect_listeners = () => {
/* c8 ignore next */
if (!this._socket) {
return;
}
this._socket.removeListener("error", _on_socket_error_for_connect);
this._socket.removeListener("end", _on_socket_end_for_connect);
};
this._install_socket(socket);
this._socket?.once("error", _on_socket_error_for_connect);
this._socket?.once("end", _on_socket_end_for_connect);
this._socket?.once("connect", _on_socket_connect);
}
}
exports.ClientTCP_transport = ClientTCP_transport;
//# sourceMappingURL=client_tcp_transport.js.map