UNPKG

socket-ipc

Version:

Message-based communications over UNIX sockets

171 lines (131 loc) 16.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _types = require("./types"); var _events = _interopRequireDefault(require("events")); var _net = _interopRequireDefault(require("net")); var _pTimeout = _interopRequireDefault(require("p-timeout")); var _pEvent = _interopRequireDefault(require("p-event")); var _verror = require("verror"); var _MessageConnection = _interopRequireDefault(require("./MessageConnection")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const RECONNECT_WAIT = 2000; // 2 seconds class MessageClient extends _events.default { constructor(options = {}) { super(); _defineProperty(this, "running", false); _defineProperty(this, "options", void 0); _defineProperty(this, "binary", void 0); _defineProperty(this, "connection", void 0); _defineProperty(this, "reconnectTimeout", void 0); _defineProperty(this, "socket", void 0); (0, _types.validateMessageHandlerOptions)(options); this.options = options; this.binary = Boolean(options.binary); } async start() { if (!this.running) { this.running = true; this.connect(); } await this.waitForConnection(); } stop() { if (this.running) { this.running = false; if (!this.connection) { this.emit('error', new Error('stopped before connection completed')); } this.cleanUp(); } } isConnected() { return Boolean(this.connection); } async waitForConnection() { if (!this.running) throw new Error('client is stopped'); if (this.isConnected()) return; const { host, port, path } = this.options; const connectionDescr = port ? `TCP connection to ${host || 'localhost'}:${port}` : `UNIX socket connection to ${path || ''}`; await (0, _pTimeout.default)((0, _pEvent.default)(this, 'connection'), 10000, `timed out waiting for socket IPC ${connectionDescr}`); } /** * @param message Buffer or string containing the message */ send(message) { if (this.connection) this.connection.send(message); } connect() { if (this.running) { if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout); this.reconnectTimeout = undefined; if (!this.socket) { const onConnectError = err => { if (err && 'ENOENT' !== err.code && 'ECONNREFUSED' !== err.code) { this.emit('error', new _verror.VError(err, 'MessageClient got socket error')); } this.cleanUp(); }; const { path, host, port } = this.options; const connectOptions = path ? { path } : { host, port }; const socket = this.socket = _net.default.connect(connectOptions, () => { if (this.running) { socket.removeListener('error', onConnectError); const connection = this.connection = new _MessageConnection.default(socket, { binary: this.binary }); connection.on('message', event => this.emit('message', event, connection)); connection.on('error', err => { this.cleanUp(); this.emit('error', new _verror.VError(err, 'MessageClient got error from MessageConnection')); }); connection.on('close', () => { this.emit('close', connection); this.cleanUp(); }); this.emit('connection', connection); } }); socket.on('error', onConnectError); } } } cleanUp() { this.socket = undefined; if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); this.reconnectTimeout = undefined; } if (this.connection) { this.connection.close(); this.connection = undefined; } if (this.running && !this.reconnectTimeout && !this.options.oneShot) { // schedule reconnect const timeout = this.reconnectTimeout = setTimeout(() => { if (timeout === this.reconnectTimeout) { this.reconnectTimeout = undefined; this.connect(); } }, RECONNECT_WAIT); } } } exports.default = MessageClient; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9NZXNzYWdlQ2xpZW50LnRzIl0sIm5hbWVzIjpbIlJFQ09OTkVDVF9XQUlUIiwiTWVzc2FnZUNsaWVudCIsIkV2ZW50RW1pdHRlciIsImNvbnN0cnVjdG9yIiwib3B0aW9ucyIsImJpbmFyeSIsIkJvb2xlYW4iLCJzdGFydCIsInJ1bm5pbmciLCJjb25uZWN0Iiwid2FpdEZvckNvbm5lY3Rpb24iLCJzdG9wIiwiY29ubmVjdGlvbiIsImVtaXQiLCJFcnJvciIsImNsZWFuVXAiLCJpc0Nvbm5lY3RlZCIsImhvc3QiLCJwb3J0IiwicGF0aCIsImNvbm5lY3Rpb25EZXNjciIsInNlbmQiLCJtZXNzYWdlIiwicmVjb25uZWN0VGltZW91dCIsImNsZWFyVGltZW91dCIsInVuZGVmaW5lZCIsInNvY2tldCIsIm9uQ29ubmVjdEVycm9yIiwiZXJyIiwiY29kZSIsIlZFcnJvciIsImNvbm5lY3RPcHRpb25zIiwibmV0IiwicmVtb3ZlTGlzdGVuZXIiLCJNZXNzYWdlQ29ubmVjdGlvbiIsIm9uIiwiZXZlbnQiLCJjbG9zZSIsIm9uZVNob3QiLCJ0aW1lb3V0Iiwic2V0VGltZW91dCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUtBOztBQUtBOztBQUtBOztBQUVBOztBQUNBOztBQUNBOztBQUVBOzs7Ozs7QUFSQSxNQUFNQSxjQUFjLEdBQUcsSUFBdkIsQyxDQUE0Qjs7QUEyQmIsTUFBTUMsYUFBTixTQUE2QkMsZUFBN0IsQ0FFWjtBQVNEQyxFQUFBQSxXQUFXLENBQUNDLE9BQTZCLEdBQUcsRUFBakMsRUFBcUM7QUFDOUM7O0FBRDhDLHFDQVI5QixLQVE4Qjs7QUFBQTs7QUFBQTs7QUFBQTs7QUFBQTs7QUFBQTs7QUFFOUMsOENBQThCQSxPQUE5QjtBQUNBLFNBQUtBLE9BQUwsR0FBZUEsT0FBZjtBQUNBLFNBQUtDLE1BQUwsR0FBY0MsT0FBTyxDQUFDRixPQUFPLENBQUNDLE1BQVQsQ0FBckI7QUFDRDs7QUFFRCxRQUFNRSxLQUFOLEdBQTZCO0FBQzNCLFFB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QXVDO0FBQ3JDLGVBQUtBLGdCQUFMLEdBQXdCRSxTQUF4QjtBQUNBLGVBQUtoQixPQUFMO0FBQ0Q7QUFDRixPQUxrRCxFQUtoRFQsY0FMZ0QsQ0FBbkQ7QUFNRDtBQUNGOztBQWxJQSIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gVGhpcyBmaWxlIGlzIHdyaXR0ZW4gaW4gRVM1IEphdmEsIHRvIG1ha2UgaXQgZWFzeSB0byB1c2UgaW4gc21hbGwgbm9kZS5qcyB1dGlsaXRpZXNcbiB0aGF0IGFyZW4ndCB0cmFuc3BpbGVkIGZyb20gRVM2IHRvIEVTNS5cbiAqL1xuXG5pbXBvcnQge1xuICBNZXNzYWdlRXZlbnQsXG4gIE1lc3NhZ2VIYW5kbGVyT3B0aW9ucyxcbiAgdmFsaWRhdGVNZXNzYWdlSGFuZGxlck9wdGlvbnMsXG59IGZyb20gJy4vdHlwZXMnXG5pbXBvcnQgRXZlbnRFbWl0dGVyIGZyb20gJ2V2ZW50cydcbmltcG9ydCB7IFN0cmljdEV2ZW50RW1pdHRlciB9IGZyb20gJ3N0cmljdC1ldmVudC1lbWl0dGVyLXR5cGVzJ1xuXG5jb25zdCBSRUNPTk5FQ1RfV0FJVCA9IDIwMDAgLy8gMiBzZWNvbmRzXG5cbmltcG9ydCBuZXQsIHsgTmV0Q29ubmVjdE9wdHMgfSBmcm9tICduZXQnXG5cbmltcG9ydCBwVGltZW91dCBmcm9tICdwLXRpbWVvdXQnXG5pbXBvcnQgZW1pdHRlZCBmcm9tICdwLWV2ZW50J1xuaW1wb3J0IHsgVkVycm9yIH0gZnJvbSAndmVycm9yJ1xuXG5pbXBvcnQgTWVzc2FnZUNvbm5lY3Rpb24gZnJvbSAnLi9NZXNzYWdlQ29ubmVjdGlvbidcblxuZXhwb3J0IHR5cGUgTWVzc2FnZUNsaWVudE9wdGlvbnMgPSBNZXNzYWdlSGFuZGxlck9wdGlvbnMgJiB7XG4gIGhvc3Q/OiBzdHJpbmdcbiAgb25lU2hvdD86IGJvb2xlYW5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZXNzYWdlQ2xpZW50RXZlbnRzIHtcbiAgY29ubmVjdGlvbjogTWVzc2FnZUNvbm5lY3Rpb25cbiAgbWVzc2FnZTogKGV2ZW50OiBNZXNzYWdlRXZlbnQsIGNvbm5lY3Rpb246IE1lc3NhZ2VDb25uZWN0aW9uKSA9PiB2b2lkXG4gIGNsb3NlOiBNZXNzYWdlQ29ubmVjdGlvblxuICBlcnJvcjogRXJyb3Jcbn1cblxudHlwZSBNZXNzYWdlQ2xpZW50RW1pdHRlciA9IFN0cmljdEV2ZW50RW1pdHRlcjxcbiAgRXZlbnRFbWl0dGVyLFxuICBNZXNzYWdlQ2xpZW50RXZlbnRzXG4+XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1lc3NhZ2VDbGllbnQgZXh0ZW5kcyAoRXZlbnRFbWl0dGVyIGFzIHtcbiAgbmV3ICgpOiBNZXNzYWdlQ2xpZW50RW1pdHRlclxufSkge1xuICBwcml2YXRlIHJ1bm5pbmcgPSBmYWxzZVxuICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IE1lc3NhZ2VDbGllbnRPcHRpb25zXG4gIHByaXZhdGUgcmVhZG9ubHkgYmluYXJ5OiBib29sZWFuXG5cbiAgcHJpdmF0ZSBjb25uZWN0aW9uOiBNZXNzYWdlQ29ubmVjdGlvbiB8IHVuZGVmaW5lZFxuICBwcml2YXRlIHJlY29ubmVjdFRpbWVvdXQ6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkXG4gIHByaXZhdGUgc29ja2V0OiBuZXQuU29ja2V0IHwgdW5kZWZpbmVkXG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogTWVzc2FnZUNsaWVudE9wdGlvbnMgPSB7fSkge1xuICAgIHN1cGVyKClcbiAgICB2YWxpZGF0ZU1lc3NhZ2VIYW5kbGVyT3B0aW9ucyhvcHRpb25zKVxuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnNcbiAgICB0aGlzLmJpbmFyeSA9IEJvb2xlYW4ob3B0aW9ucy5iaW5hcnkpXG4gIH1cblxuICBhc3luYyBzdGFydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMucnVubmluZykge1xuICAgICAgdGhpcy5ydW5uaW5nID0gdHJ1ZVxuICAgICAgdGhpcy5jb25uZWN0KClcbiAgICB9XG4gICAgYXdhaXQgdGhpcy53YWl0Rm9yQ29ubmVjdGlvbigpXG4gIH1cblxuICBzdG9wKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnJ1bm5pbmcpIHtcbiAgICAgIHRoaXMucnVubmluZyA9IGZhbHNlXG4gICAgICBpZiAoIXRoaXMuY29ubmVjdGlvbikge1xuICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgbmV3IEVycm9yKCdzdG9wcGVkIGJlZm9yZSBjb25uZWN0aW9uIGNvbXBsZXRlZCcpKVxuICAgICAgfVxuICAgICAgdGhpcy5jbGVhblVwKClcbiAgICB9XG4gIH1cblxuICBpc0Nvbm5lY3RlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gQm9vbGVhbih0aGlzLmNvbm5lY3Rpb24pXG4gIH1cblxuICBhc3luYyB3YWl0Rm9yQ29ubmVjdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMucnVubmluZykgdGhyb3cgbmV3IEVycm9yKCdjbGllbnQgaXMgc3RvcHBlZCcpXG4gICAgaWYgKHRoaXMuaXNDb25uZWN0ZWQoKSkgcmV0dXJuXG4gICAgY29uc3QgeyBob3N0LCBwb3J0LCBwYXRoIH0gPSB0aGlzLm9wdGlvbnNcbiAgICBjb25zdCBjb25uZWN0aW9uRGVzY3IgPSBwb3J0XG4gICAgICA/IGBUQ1AgY29ubmVjdGlvbiB0byAke2hvc3QgfHwgJ2xvY2FsaG9zdCd9OiR7cG9ydH1gXG4gICAgICA6IGBVTklYIHNvY2tldCBjb25uZWN0aW9uIHRvICR7cGF0aCB8fCAnJ31gXG4gICAgYXdhaXQgcFRpbWVvdXQoXG4gICAgICBlbWl0dGVkKHRoaXMsICdjb25uZWN0aW9uJyksXG4gICAgICAxMDAwMCxcbiAgICAgIGB0aW1lZCBvdXQgd2FpdGluZyBmb3Igc29ja2V0IElQQyAke2Nvbm5lY3Rpb25EZXNjcn1gXG4gICAgKVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBtZXNzYWdlIEJ1ZmZlciBvciBzdHJpbmcgY29udGFpbmluZyB0aGUgbWVzc2FnZVxuICAgKi9cbiAgc2VuZChtZXNzYWdlOiBCdWZmZXIgfCBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb25uZWN0aW9uKSB0aGlzLmNvbm5lY3Rpb24uc2VuZChtZXNzYWdlKVxuICB9XG5cbiAgcHJpdmF0ZSBjb25uZWN0KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnJ1bm5pbmcpIHtcbiAgICAgIGlmICh0aGlzLnJlY29ubmVjdFRpbWVvdXQpIGNsZWFyVGltZW91dCh0aGlzLnJlY29ubmVjdFRpbWVvdXQpXG4gICAgICB0aGlzLnJlY29ubmVjdFRpbWVvdXQgPSB1bmRlZmluZWRcbiAgICAgIGlmICghdGhpcy5zb2NrZXQpIHtcbiAgICAgICAgY29uc3Qgb25Db25uZWN0RXJyb3IgPSAoZXJyOiBFcnJvciAmIHsgY29kZTogc3RyaW5nIH0pOiB2b2lkID0+IHtcbiAgICAgICAgICBpZiAoZXJyICYmICdFTk9FTlQnICE9PSBlcnIuY29kZSAmJiAnRUNPTk5SRUZVU0VEJyAhPT0gZXJyLmNvZGUpIHtcbiAgICAgICAgICAgIHRoaXMuZW1pdChcbiAgICAgICAgICAgICAgJ2Vycm9yJyxcbiAgICAgICAgICAgICAgbmV3IFZFcnJvcihlcnIsICdNZXNzYWdlQ2xpZW50IGdvdCBzb2NrZXQgZXJyb3InKVxuICAgICAgICAgICAgKVxuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmNsZWFuVXAoKVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgcGF0aCwgaG9zdCwgcG9ydCB9ID0gdGhpcy5vcHRpb25zXG4gICAgICAgIGNvbnN0IGNvbm5lY3RPcHRpb25zOiBOZXRDb25uZWN0T3B0cyA9IChwYXRoXG4gICAgICAgICAgPyB7IHBhdGggfVxuICAgICAgICAgIDogeyBob3N0LCBwb3J0IH0pIGFzIE5ldENvbm5lY3RPcHRzXG4gICAgICAgIGNvbnN0IHNvY2tldCA9ICh0aGlzLnNvY2tldCA9IG5ldC5jb25uZWN0KGNvbm5lY3RPcHRpb25zLCAoKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMucnVubmluZykge1xuICAgICAgICAgICAgc29ja2V0LnJlbW92ZUxpc3RlbmVyKCdlcnJvcicsIG9uQ29ubmVjdEVycm9yKVxuICAgICAgICAgICAgY29uc3QgY29ubmVjdGlvbiA9ICh0aGlzLmNvbm5lY3Rpb24gPSBuZXcgTWVzc2FnZUNvbm5lY3Rpb24oXG4gICAgICAgICAgICAgIHNvY2tldCxcbiAgICAgICAgICAgICAgeyBiaW5hcnk6IHRoaXMuYmluYXJ5IH1cbiAgICAgICAgICAgICkpXG4gICAgICAgICAgICBjb25uZWN0aW9uLm9uKCdtZXNzYWdlJywgKGV2ZW50OiBNZXNzYWdlRXZlbnQpID0+XG4gICAgICAgICAgICAgIHRoaXMuZW1pdCgnbWVzc2FnZScsIGV2ZW50LCBjb25uZWN0aW9uKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5vbignZXJyb3InLCAoZXJyOiBFcnJvcikgPT4ge1xuICAgICAgICAgICAgICB0aGlzLmNsZWFuVXAoKVxuICAgICAgICAgICAgICB0aGlzLmVtaXQoXG4gICAgICAgICAgICAgICAgJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICBuZXcgVkVycm9yKFxuICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgJ01lc3NhZ2VDbGllbnQgZ290IGVycm9yIGZyb20gTWVzc2FnZUNvbm5lY3Rpb24nXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgY29ubmVjdGlvbi5vbignY2xvc2UnLCAoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMuZW1pdCgnY2xvc2UnLCBjb25uZWN0aW9uKVxuICAgICAgICAgICAgICB0aGlzLmNsZWFuVXAoKVxuICAgICAgICAgICAgfSlcblxuICAgICAgICAgICAgdGhpcy5lbWl0KCdjb25uZWN0aW9uJywgY29ubmVjdGlvbilcbiAgICAgICAgICB9XG4gICAgICAgIH0pKVxuICAgICAgICBzb2NrZXQub24oJ2Vycm9yJywgb25Db25uZWN0RXJyb3IpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjbGVhblVwKCk6IHZvaWQge1xuICAgIHRoaXMuc29ja2V0ID0gdW5kZWZpbmVkXG4gICAgaWYgKHRoaXMucmVjb25uZWN0VGltZW91dCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMucmVjb25uZWN0VGltZW91dClcbiAgICAgIHRoaXMucmVjb25uZWN0VGltZW91dCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgICBpZiAodGhpcy5jb25uZWN0aW9uKSB7XG4gICAgICB0aGlzLmNvbm5lY3Rpb24uY2xvc2UoKVxuICAgICAgdGhpcy5jb25uZWN0aW9uID0gdW5kZWZpbmVkXG4gICAgfVxuXG4gICAgaWYgKHRoaXMucnVubmluZyAmJiAhdGhpcy5yZWNvbm5lY3RUaW1lb3V0ICYmICF0aGlzLm9wdGlvbnMub25lU2hvdCkge1xuICAgICAgLy8gc2NoZWR1bGUgcmVjb25uZWN0XG4gICAgICBjb25zdCB0aW1lb3V0ID0gKHRoaXMucmVjb25uZWN0VGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpZiAodGltZW91dCA9PT0gdGhpcy5yZWNvbm5lY3RUaW1lb3V0KSB7XG4gICAgICAgICAgdGhpcy5yZWNvbm5lY3RUaW1lb3V0ID0gdW5kZWZpbmVkXG4gICAgICAgICAgdGhpcy5jb25uZWN0KClcbiAgICAgICAgfVxuICAgICAgfSwgUkVDT05ORUNUX1dBSVQpKVxuICAgIH1cbiAgfVxufVxuIl19