"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createMessageConnection = exports.createServerSocketTransport = exports.createClientSocketTransport = exports.createServerPipeTransport = exports.createClientPipeTransport = exports.generateRandomPipeName = exports.StreamMessageWriter = exports.StreamMessageReader = exports.SocketMessageWriter = exports.SocketMessageReader = exports.PortMessageWriter = exports.PortMessageReader = exports.IPCMessageWriter = exports.IPCMessageReader = void 0; /* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. * ----------------------------------------------------------------------------------------- */ const ril_1 = require("./ril"); // Install the node runtime abstract. ril_1.default.install(); const path = require("path"); const os = require("os"); const crypto_1 = require("crypto"); const net_1 = require("net"); const api_1 = require("../common/api"); __exportStar(require("../common/api"), exports); class IPCMessageReader extends api_1.AbstractMessageReader { constructor(process) { super(); this.process = process; let eventEmitter = this.process; eventEmitter.on('error', (error) => this.fireError(error)); eventEmitter.on('close', () => this.fireClose()); } listen(callback) { this.process.on('message', callback); return api_1.Disposable.create(() => this.process.off('message', callback)); } } exports.IPCMessageReader = IPCMessageReader; class IPCMessageWriter extends api_1.AbstractMessageWriter { constructor(process) { super(); this.process = process; this.errorCount = 0; const eventEmitter = this.process; eventEmitter.on('error', (error) => this.fireError(error)); eventEmitter.on('close', () => this.fireClose); } write(msg) { try { if (typeof this.process.send === 'function') { this.process.send(msg, undefined, undefined, (error) => { if (error) { this.errorCount++; this.handleError(error, msg); } else { this.errorCount = 0; } }); } return Promise.resolve(); } catch (error) { this.handleError(error, msg); return Promise.reject(error); } } handleError(error, msg) { this.errorCount++; this.fireError(error, msg, this.errorCount); } end() { } } exports.IPCMessageWriter = IPCMessageWriter; class PortMessageReader extends api_1.AbstractMessageReader { constructor(port) { super(); this.onData = new api_1.Emitter; port.on('close', () => this.fireClose); port.on('error', (error) => this.fireError(error)); port.on('message', (message) => { this.onData.fire(message); }); } listen(callback) { return this.onData.event(callback); } } exports.PortMessageReader = PortMessageReader; class PortMessageWriter extends api_1.AbstractMessageWriter { constructor(port) { super(); this.port = port; this.errorCount = 0; port.on('close', () => this.fireClose()); port.on('error', (error) => this.fireError(error)); } write(msg) { try { this.port.postMessage(msg); return Promise.resolve(); } catch (error) { this.handleError(error, msg); return Promise.reject(error); } } handleError(error, msg) { this.errorCount++; this.fireError(error, msg, this.errorCount); } end() { } } exports.PortMessageWriter = PortMessageWriter; class SocketMessageReader extends api_1.ReadableStreamMessageReader { constructor(socket, encoding = 'utf-8') { super((0, ril_1.default)().stream.asReadableStream(socket), encoding); } } exports.SocketMessageReader = SocketMessageReader; class SocketMessageWriter extends api_1.WriteableStreamMessageWriter { constructor(socket, options) { super((0, ril_1.default)().stream.asWritableStream(socket), options); this.socket = socket; } dispose() { super.dispose(); this.socket.destroy(); } } exports.SocketMessageWriter = SocketMessageWriter; class StreamMessageReader extends api_1.ReadableStreamMessageReader { constructor(readable, encoding) { super((0, ril_1.default)().stream.asReadableStream(readable), encoding); } } exports.StreamMessageReader = StreamMessageReader; class StreamMessageWriter extends api_1.WriteableStreamMessageWriter { constructor(writable, options) { super((0, ril_1.default)().stream.asWritableStream(writable), options); } } exports.StreamMessageWriter = StreamMessageWriter; const XDG_RUNTIME_DIR = process.env['XDG_RUNTIME_DIR']; const safeIpcPathLengths = new Map([ ['linux', 107], ['darwin', 103] ]); function generateRandomPipeName() { const randomSuffix = (0, crypto_1.randomBytes)(21).toString('hex'); if (process.platform === 'win32') { return `\\\\.\\pipe\\vscode-jsonrpc-${randomSuffix}-sock`; } let result; if (XDG_RUNTIME_DIR) { result = path.join(XDG_RUNTIME_DIR, `vscode-ipc-${randomSuffix}.sock`); } else { result = path.join(os.tmpdir(), `vscode-${randomSuffix}.sock`); } const limit = safeIpcPathLengths.get(process.platform); if (limit !== undefined && result.length > limit) { (0, ril_1.default)().console.warn(`WARNING: IPC handle "${result}" is longer than ${limit} characters.`); } return result; } exports.generateRandomPipeName = generateRandomPipeName; function createClientPipeTransport(pipeName, encoding = 'utf-8') { let connectResolve; const connected = new Promise((resolve, _reject) => { connectResolve = resolve; }); return new Promise((resolve, reject) => { let server = (0, net_1.createServer)((socket) => { server.close(); connectResolve([ new SocketMessageReader(socket, encoding), new SocketMessageWriter(socket, encoding) ]); }); server.on('error', reject); server.listen(pipeName, () => { server.removeListener('error', reject); resolve({ onConnected: () => { return connected; } }); }); }); } exports.createClientPipeTransport = createClientPipeTransport; function createServerPipeTransport(pipeName, encoding = 'utf-8') { const socket = (0, net_1.createConnection)(pipeName); return [ new SocketMessageReader(socket, encoding), new SocketMessageWriter(socket, encoding) ]; } exports.createServerPipeTransport = createServerPipeTransport; function createClientSocketTransport(port, encoding = 'utf-8') { let connectResolve; const connected = new Promise((resolve, _reject) => { connectResolve = resolve; }); return new Promise((resolve, reject) => { const server = (0, net_1.createServer)((socket) => { server.close(); connectResolve([ new SocketMessageReader(socket, encoding), new SocketMessageWriter(socket, encoding) ]); }); server.on('error', reject); server.listen(port, '127.0.0.1', () => { server.removeListener('error', reject); resolve({ onConnected: () => { return connected; } }); }); }); } exports.createClientSocketTransport = createClientSocketTransport; function createServerSocketTransport(port, encoding = 'utf-8') { const socket = (0, net_1.createConnection)(port, '127.0.0.1'); return [ new SocketMessageReader(socket, encoding), new SocketMessageWriter(socket, encoding) ]; } exports.createServerSocketTransport = createServerSocketTransport; function isReadableStream(value) { const candidate = value; return candidate.read !== undefined && candidate.addListener !== undefined; } function isWritableStream(value) { const candidate = value; return candidate.write !== undefined && candidate.addListener !== undefined; } function createMessageConnection(input, output, logger, options) { if (!logger) { logger = api_1.NullLogger; } const reader = isReadableStream(input) ? new StreamMessageReader(input) : input; const writer = isWritableStream(output) ? new StreamMessageWriter(output) : output; if (api_1.ConnectionStrategy.is(options)) { options = { connectionStrategy: options }; } return (0, api_1.createMessageConnection)(reader, writer, logger, options); } exports.createMessageConnection = createMessageConnection;