UNPKG

vscode-jsonrpc

Version:
290 lines (289 loc) 10.9 kB
"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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); 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); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StreamMessageWriter = exports.StreamMessageReader = exports.SocketMessageWriter = exports.SocketMessageReader = exports.PortMessageWriter = exports.PortMessageReader = exports.IPCMessageWriter = exports.IPCMessageReader = void 0; exports.generateRandomPipeName = generateRandomPipeName; exports.createClientPipeTransport = createClientPipeTransport; exports.createServerPipeTransport = createServerPipeTransport; exports.createClientSocketTransport = createClientSocketTransport; exports.createServerSocketTransport = createServerSocketTransport; exports.createMessageConnection = createMessageConnection; /* -------------------------------------------------------------------------------------------- * 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 = __importDefault(require("./ril")); // Install the node runtime abstract. ril_1.default.install(); const path = __importStar(require("path")); const os = __importStar(require("os")); const fs = __importStar(require("fs")); 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 { process; constructor(process) { super(); this.process = process; const 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 { process; errorCount; 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 { onData; 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 { port; errorCount; 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 { socket; 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', 102] ]); function generateRandomPipeName() { if (process.platform === 'win32') { return `\\\\.\\pipe\\lsp-${(0, crypto_1.randomBytes)(16).toString('hex')}-sock`; } let randomLength = 32; const fixedLength = '/lsp-.sock'.length; const tmpDir = fs.realpathSync(XDG_RUNTIME_DIR ?? os.tmpdir()); const limit = safeIpcPathLengths.get(process.platform); if (limit !== undefined) { randomLength = Math.min(limit - tmpDir.length - fixedLength, randomLength); } if (randomLength < 16) { throw new Error(`Unable to generate a random pipe name with ${randomLength} characters.`); } const randomSuffix = (0, crypto_1.randomBytes)(Math.floor(randomLength / 2)).toString('hex'); return path.join(tmpDir, `lsp-${randomSuffix}.sock`); } function createClientPipeTransport(pipeName, 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(pipeName, () => { server.removeListener('error', reject); resolve({ onConnected: () => { return connected; } }); }); }); } function createServerPipeTransport(pipeName, encoding = 'utf-8') { const socket = (0, net_1.createConnection)(pipeName); return [ new SocketMessageReader(socket, encoding), new SocketMessageWriter(socket, encoding) ]; } 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; } }); }); }); } 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) ]; } 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); }