This commit is contained in:
gr
2026-11-11 14:22:02 +08:00
parent 245618dcdc
commit a62311a8da
64878 changed files with 3747172 additions and 66 deletions
+73
View File
@@ -0,0 +1,73 @@
import { ChildProcess } from 'child_process';
import { Socket } from 'net';
import { MessagePort, Worker } from 'worker_threads';
import { RAL, AbstractMessageReader, DataCallback, AbstractMessageWriter, Message, ReadableStreamMessageReader, WriteableStreamMessageWriter, MessageWriterOptions, MessageReaderOptions, MessageReader, MessageWriter, ConnectionStrategy, ConnectionOptions, MessageConnection, Logger, Disposable } from '../common/api';
export * from '../common/api';
export declare class IPCMessageReader extends AbstractMessageReader {
private process;
constructor(process: NodeJS.Process | ChildProcess);
listen(callback: DataCallback): Disposable;
}
export declare class IPCMessageWriter extends AbstractMessageWriter implements MessageWriter {
private readonly process;
private errorCount;
constructor(process: NodeJS.Process | ChildProcess);
write(msg: Message): Promise<void>;
private handleError;
end(): void;
}
export declare class PortMessageReader extends AbstractMessageReader implements MessageReader {
private onData;
constructor(port: MessagePort | Worker);
listen(callback: DataCallback): Disposable;
}
export declare class PortMessageWriter extends AbstractMessageWriter implements MessageWriter {
private readonly port;
private errorCount;
constructor(port: MessagePort | Worker);
write(msg: Message): Promise<void>;
private handleError;
end(): void;
}
export declare class SocketMessageReader extends ReadableStreamMessageReader {
constructor(socket: Socket, encoding?: RAL.MessageBufferEncoding);
}
export declare class SocketMessageWriter extends WriteableStreamMessageWriter {
private socket;
constructor(socket: Socket, options?: RAL.MessageBufferEncoding | MessageWriterOptions);
dispose(): void;
}
export declare class StreamMessageReader extends ReadableStreamMessageReader {
constructor(readable: NodeJS.ReadableStream, encoding?: RAL.MessageBufferEncoding | MessageReaderOptions);
}
export declare class StreamMessageWriter extends WriteableStreamMessageWriter {
constructor(writable: NodeJS.WritableStream, options?: RAL.MessageBufferEncoding | MessageWriterOptions);
}
export declare function generateRandomPipeName(): string;
export interface PipeTransport {
onConnected(): Promise<[MessageReader, MessageWriter]>;
/**
* Closes the underlying server if a client hasn't connected yet. Callers
* should invoke this if they abandon the transport before `onConnected`
* resolves (for example because the server process failed to start) to
* avoid leaking the listening pipe.
*/
close(): void;
}
export declare function createClientPipeTransport(pipeName: string, encoding?: RAL.MessageBufferEncoding): Promise<PipeTransport>;
export declare function createServerPipeTransport(pipeName: string, encoding?: RAL.MessageBufferEncoding): [MessageReader, MessageWriter];
export interface SocketTransport {
port(): number;
onConnected(): Promise<[MessageReader, MessageWriter]>;
/**
* Closes the underlying server if a client hasn't connected yet. Callers
* should invoke this if they abandon the transport before `onConnected`
* resolves (for example because the server process failed to start) to
* avoid leaking the listening socket.
*/
close(): void;
}
export declare function createClientSocketTransport(port: number, encoding?: RAL.MessageBufferEncoding): Promise<SocketTransport>;
export declare function createServerSocketTransport(port: number, encoding?: RAL.MessageBufferEncoding): [MessageReader, MessageWriter];
export declare function createMessageConnection(reader: MessageReader, writer: MessageWriter, logger?: Logger, options?: ConnectionStrategy | ConnectionOptions): MessageConnection;
export declare function createMessageConnection(inputStream: NodeJS.ReadableStream, outputStream: NodeJS.WritableStream, logger?: Logger, options?: ConnectionStrategy | ConnectionOptions): MessageConnection;
+298
View File
@@ -0,0 +1,298 @@
"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; },
close: () => { server.close(); }
});
});
});
}
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);
const address = server.address();
if (address === null || typeof address === 'string') {
reject(new Error(`Unexpected server address: ${address}`));
return;
}
const boundPort = address.port;
resolve({
port: () => boundPort,
onConnected: () => { return connected; },
close: () => { server.close(); }
});
});
});
}
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);
}
+12
View File
@@ -0,0 +1,12 @@
import { RAL } from '../common/api';
interface RIL extends RAL {
readonly stream: {
readonly asReadableStream: (stream: NodeJS.ReadableStream) => RAL.ReadableStream;
readonly asWritableStream: (stream: NodeJS.WritableStream) => RAL.WritableStream;
};
}
declare function RIL(): RIL;
declare namespace RIL {
function install(): void;
}
export default RIL;
+167
View File
@@ -0,0 +1,167 @@
"use strict";
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("util");
const crypto_1 = require("crypto");
const api_1 = require("../common/api");
class MessageBuffer extends api_1.AbstractMessageBuffer {
static emptyBuffer = Buffer.allocUnsafe(0);
constructor(encoding = 'utf-8') {
super(encoding);
}
emptyBuffer() {
return MessageBuffer.emptyBuffer;
}
fromString(value, encoding) {
return Buffer.from(value, encoding);
}
toString(value, encoding) {
if (value instanceof Buffer) {
return value.toString(encoding);
}
else {
return new util_1.TextDecoder(encoding).decode(value);
}
}
asNative(buffer, length) {
if (length === undefined) {
return buffer instanceof Buffer ? buffer : Buffer.from(buffer);
}
else {
return buffer instanceof Buffer ? buffer.slice(0, length) : Buffer.from(buffer.subarray(0, length));
}
}
allocNative(length) {
return Buffer.allocUnsafe(length);
}
}
class ReadableStreamWrapper {
stream;
constructor(stream) {
this.stream = stream;
}
onClose(listener) {
this.stream.on('close', listener);
return api_1.Disposable.create(() => this.stream.off('close', listener));
}
onError(listener) {
this.stream.on('error', listener);
return api_1.Disposable.create(() => this.stream.off('error', listener));
}
onEnd(listener) {
this.stream.on('end', listener);
return api_1.Disposable.create(() => this.stream.off('end', listener));
}
onData(listener) {
this.stream.on('data', listener);
return api_1.Disposable.create(() => this.stream.off('data', listener));
}
}
class WritableStreamWrapper {
stream;
constructor(stream) {
this.stream = stream;
}
onClose(listener) {
this.stream.on('close', listener);
return api_1.Disposable.create(() => this.stream.off('close', listener));
}
onError(listener) {
this.stream.on('error', listener);
return api_1.Disposable.create(() => this.stream.off('error', listener));
}
onEnd(listener) {
this.stream.on('end', listener);
return api_1.Disposable.create(() => this.stream.off('end', listener));
}
write(data, encoding) {
return new Promise((resolve, reject) => {
const callback = (error) => {
if (error === undefined || error === null) {
resolve();
}
else {
reject(error);
}
};
if (typeof data === 'string') {
this.stream.write(data, encoding, callback);
}
else {
this.stream.write(data, callback);
}
});
}
end() {
this.stream.end();
}
}
const _ril = Object.freeze({
crypto: Object.freeze({
randomUUID: () => (0, crypto_1.randomUUID)()
}),
messageBuffer: Object.freeze({
create: (encoding) => new MessageBuffer(encoding)
}),
applicationJson: Object.freeze({
encoder: Object.freeze({
name: 'application/json',
encode: (msg, options) => {
try {
return Promise.resolve(Buffer.from(JSON.stringify(msg, undefined, 0), options.charset));
}
catch (err) {
return Promise.reject(err);
}
}
}),
decoder: Object.freeze({
name: 'application/json',
decode: (buffer, options) => {
try {
if (buffer instanceof Buffer) {
return Promise.resolve(JSON.parse(buffer.toString(options.charset)));
}
else {
return Promise.resolve(JSON.parse(new util_1.TextDecoder(options.charset).decode(buffer)));
}
}
catch (err) {
return Promise.reject(err);
}
}
})
}),
stream: Object.freeze({
asReadableStream: (stream) => new ReadableStreamWrapper(stream),
asWritableStream: (stream) => new WritableStreamWrapper(stream)
}),
console: console,
timer: Object.freeze({
setTimeout(callback, ms, ...args) {
const handle = setTimeout(callback, ms, ...args);
return { dispose: () => clearTimeout(handle) };
},
setImmediate(callback, ...args) {
const handle = setImmediate(callback, ...args);
return { dispose: () => clearImmediate(handle) };
},
setInterval(callback, ms, ...args) {
const handle = setInterval(callback, ms, ...args);
return { dispose: () => clearInterval(handle) };
}
})
});
function RIL() {
return _ril;
}
(function (RIL) {
function install() {
api_1.RAL.install(_ril);
}
RIL.install = install;
})(RIL || (RIL = {}));
exports.default = RIL;