Skip to content

Commit

Permalink
Fixes #245: Is socket support works correct?
Browse files Browse the repository at this point in the history
  • Loading branch information
dbaeumer committed Oct 2, 2017
1 parent 7254012 commit d40191a
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 37 deletions.
4 changes: 2 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vscode-languageclient",
"description": "VSCode Language client implementation",
"version": "3.4.5",
"version": "3.5.0-next.1",
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
Expand All @@ -20,7 +20,7 @@
"vscode": "^1.1.5"
},
"dependencies": {
"vscode-languageserver-protocol": "^3.4.4"
"vscode-languageserver-protocol": "^3.5.0-next.1"
},
"scripts": {
"prepublish": "npm run update-vscode && npm run compile && npm test",
Expand Down
79 changes: 63 additions & 16 deletions client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
import {
StreamMessageReader, StreamMessageWriter,
IPCMessageReader, IPCMessageWriter,
createClientPipeTransport, generateRandomPipeName
createClientPipeTransport, generateRandomPipeName, createClientSocketTransport
} from 'vscode-languageserver-protocol';

import * as is from './utils/is';
import * as Is from './utils/is';
import * as electron from './utils/electron';
import { terminate } from './utils/processes';

Expand Down Expand Up @@ -50,12 +50,27 @@ export interface ForkOptions {
export enum TransportKind {
stdio,
ipc,
pipe
pipe,
socket
}

export interface SocketTransport {
kind: TransportKind.socket;
port: number;
}

namespace Transport {
export function isSocket(value: Transport): value is SocketTransport {
let candidate = value as SocketTransport;
return candidate && candidate.kind === TransportKind.socket && Is.number(candidate.port);
}
}

export type Transport = TransportKind | SocketTransport;

export interface NodeModule {
module: string;
transport?: TransportKind;
transport?: Transport;
args?: string[];
runtime?: string;
options?: ForkOptions;
Expand All @@ -82,7 +97,7 @@ export class LanguageClient extends BaseLanguageClient {
let serverOptions: ServerOptions;
let clientOptions: LanguageClientOptions;
let forceDebug: boolean;
if (is.string(arg2)) {
if (Is.string(arg2)) {
id = arg1;
name = arg2;
serverOptions = arg3 as ServerOptions;
Expand Down Expand Up @@ -157,7 +172,7 @@ export class LanguageClient extends BaseLanguageClient {

let server = this._serverOptions;
// We got a function.
if (is.func(server)) {
if (Is.func(server)) {
return server().then((result) => {
if (MessageTransports.is(result)) {
return result;
Expand All @@ -167,7 +182,7 @@ export class LanguageClient extends BaseLanguageClient {
return { reader: new StreamMessageReader(info.reader), writer: new StreamMessageWriter(info.writer) };
} else {
let cp = result as ChildProcess;
cp.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
cp.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
return { reader: new StreamMessageReader(cp.stdout), writer: new StreamMessageWriter(cp.stdin) };
}
});
Expand Down Expand Up @@ -210,6 +225,8 @@ export class LanguageClient extends BaseLanguageClient {
} else if (transport === TransportKind.pipe) {
pipeName = generateRandomPipeName();
args.push(`--pipe=${pipeName}`);
} else if (Transport.isSocket(transport)) {
args.push(`--socket=${transport.port}`);
}
args.push(`--clientProcessId=${process.pid.toString()}`);
if (transport === TransportKind.ipc || transport === TransportKind.stdio) {
Expand All @@ -218,9 +235,9 @@ export class LanguageClient extends BaseLanguageClient {
return Promise.reject<MessageTransports>(`Launching server using runtime ${node.runtime} failed.`);
}
this._serverProcess = serverProcess;
serverProcess.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
serverProcess.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
if (transport === TransportKind.ipc) {
serverProcess.stdout.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
serverProcess.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
return Promise.resolve({ reader: new IPCMessageReader(serverProcess), writer: new IPCMessageWriter(serverProcess) });
} else {
return Promise.resolve({ reader: new StreamMessageReader(serverProcess.stdout), writer: new StreamMessageWriter(serverProcess.stdin) });
Expand All @@ -232,12 +249,25 @@ export class LanguageClient extends BaseLanguageClient {
return Promise.reject<MessageTransports>(`Launching server using runtime ${node.runtime} failed.`);
}
this._serverProcess = process;
process.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
process.stdout.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
process.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
process.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
return transport.onConnected().then((protocol) => {
return { reader: protocol[0], writer: protocol[1] };
});
})
} else if (Transport.isSocket(transport)) {
return createClientSocketTransport(transport.port).then((transport) => {
let process = cp.spawn(node.runtime!, args, execOptions);
if (!process || !process.pid) {
return Promise.reject<MessageTransports>(`Launching server using runtime ${node.runtime} failed.`);
}
this._serverProcess = process;
process.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
process.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
return transport.onConnected().then((protocol) => {
return { reader: protocol[0], writer: protocol[1] };
});
});
}
} else {
let pipeName: string | undefined = undefined;
Expand All @@ -250,6 +280,8 @@ export class LanguageClient extends BaseLanguageClient {
} else if (transport === TransportKind.pipe) {
pipeName = generateRandomPipeName();
args.push(`--pipe=${pipeName}`);
} else if (Transport.isSocket(transport)) {
args.push(`--socket=${transport.port}`);
}
args.push(`--clientProcessId=${process.pid.toString()}`);
let options: ForkOptions = node.options || Object.create(null);
Expand All @@ -261,9 +293,9 @@ export class LanguageClient extends BaseLanguageClient {
reject(error);
} else {
this._serverProcess = serverProcess;
serverProcess.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
serverProcess.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
if (transport === TransportKind.ipc) {
serverProcess.stdout.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
serverProcess.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
resolve({ reader: new IPCMessageReader(this._serverProcess), writer: new IPCMessageWriter(this._serverProcess) });
} else {
resolve({ reader: new StreamMessageReader(serverProcess.stdout), writer: new StreamMessageWriter(serverProcess.stdin) });
Expand All @@ -277,8 +309,23 @@ export class LanguageClient extends BaseLanguageClient {
reject(error);
} else {
this._serverProcess = cp;
cp.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
cp.stdout.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
cp.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
cp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
transport.onConnected().then((protocol) => {
resolve({ reader: protocol[0], writer: protocol[1]});
});
}
});
});
} else if (Transport.isSocket(transport)) {
createClientSocketTransport(transport.port).then((transport) => {
electron.fork(node.module, args || [], options, (error, cp) => {
if (error || !cp) {
reject(error);
} else {
this._serverProcess = cp;
cp.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
cp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
transport.onConnected().then((protocol) => {
resolve({ reader: protocol[0], writer: protocol[1]});
});
Expand All @@ -297,7 +344,7 @@ export class LanguageClient extends BaseLanguageClient {
if (!serverProcess || !serverProcess.pid) {
return Promise.reject<MessageTransports>(`Launching server using command ${command.command} failed.`);
}
serverProcess.stderr.on('data', data => this.outputChannel.append(is.string(data) ? data : data.toString(encoding)));
serverProcess.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
this._serverProcess = serverProcess;
return Promise.resolve({ reader: new StreamMessageReader(serverProcess.stdout), writer: new StreamMessageWriter(serverProcess.stdin) });
}
Expand Down
2 changes: 1 addition & 1 deletion jsonrpc/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vscode-jsonrpc",
"description": "A json rpc implementation over streams",
"version": "3.4.1",
"version": "3.5.0-next.1",
"author": "Microsoft Corporation",
"license": "MIT",
"repository": {
Expand Down
1 change: 1 addition & 0 deletions jsonrpc/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export {
Disposable, Event, Emitter
}
export * from './pipeSupport';
export * from './socketSupport';

interface CancelParams {
/**
Expand Down
45 changes: 45 additions & 0 deletions jsonrpc/src/socketSupport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';

import { Server, Socket, createServer, createConnection } from 'net';

import { MessageReader, SocketMessageReader } from './messageReader';
import { MessageWriter, SocketMessageWriter } from './messageWriter';

export interface SocketTransport {
onConnected(): Thenable<[MessageReader, MessageWriter]>;
}

export function createClientSocketTransport(port: number, encoding: string = 'utf-8'): Thenable<SocketTransport> {
let connectResolve: any;
let connected = new Promise<[MessageReader, MessageWriter]>((resolve, _reject) => {
connectResolve = resolve;
});
return new Promise<SocketTransport>((resolve, reject) => {
let server: Server = createServer((socket: 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; }
});
});
});
}

export function createServerSocketTransport(port: number, encoding: string = 'utf-8'): [MessageReader, MessageWriter] {
const socket: Socket = createConnection(port, '127.0.0.1');
return [
new SocketMessageReader(socket, encoding),
new SocketMessageWriter(socket, encoding)
];
}
4 changes: 2 additions & 2 deletions protocol/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vscode-languageserver-protocol",
"description": "VSCode Language Server Protocol implementation",
"version": "3.4.4",
"version": "3.5.0-next.1",
"author": "Microsoft Corporation",
"license": "MIT",
"repository": {
Expand All @@ -14,7 +14,7 @@
"main": "./lib/main.js",
"typings": "./lib/main",
"dependencies": {
"vscode-jsonrpc": "^3.4.1",
"vscode-jsonrpc": "^3.5.0-next.1",
"vscode-languageserver-types": "^3.4.0"
},
"scripts": {
Expand Down
4 changes: 3 additions & 1 deletion protocol/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
MessageReader, MessageWriter, Logger, ConnectionStrategy,
StreamMessageReader, StreamMessageWriter, IPCMessageReader, IPCMessageWriter,
createClientPipeTransport, createServerPipeTransport, generateRandomPipeName, DataCallback,
createClientSocketTransport, createServerSocketTransport,
createMessageConnection, Tracer
} from 'vscode-jsonrpc';

Expand All @@ -26,6 +27,7 @@ export {
StreamMessageReader, StreamMessageWriter,
IPCMessageReader, IPCMessageWriter,
createClientPipeTransport, createServerPipeTransport, generateRandomPipeName, DataCallback,
createClientSocketTransport, createServerSocketTransport,
Tracer
}
export * from 'vscode-languageserver-types';
Expand Down Expand Up @@ -61,7 +63,7 @@ export namespace Proposed {
export type MiddlewareSignature = folders.DidChangeWorkspaceFoldersNotification.MiddlewareSignature;
}


export type ColorProviderOptions = color.ColorProviderOptions;
export type DocumentColorParams = color.DocumentColorParams;
export type ColorPresentationParams = color.ColorPresentationParams;
Expand Down
4 changes: 2 additions & 2 deletions server/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vscode-languageserver",
"description": "Language server implementation for node",
"version": "3.4.3",
"version": "3.5.0-next.1",
"author": "Microsoft Corporation",
"license": "MIT",
"repository": {
Expand All @@ -18,7 +18,7 @@
"typings": "./lib/main",
"dependencies": {
"vscode-uri": "^1.0.1",
"vscode-languageserver-protocol": "^3.4.1"
"vscode-languageserver-protocol": "^3.5.0-next.1"
},
"scripts": {
"prepublish": "npm run compile",
Expand Down
20 changes: 7 additions & 13 deletions server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, StarNotificationHandler,
RPCMessageType, ResponseError,
Logger, MessageReader, IPCMessageReader,
MessageWriter, IPCMessageWriter, createServerPipeTransport,
MessageWriter, IPCMessageWriter, createServerPipeTransport, createServerSocketTransport,
CancellationToken, CancellationTokenSource,
Disposable, Event, Emitter, Trace, SetTraceNotification, LogTraceNotification,
ConnectionStrategy,
Expand Down Expand Up @@ -54,8 +54,6 @@ export * from 'vscode-languageserver-protocol';
export { Event }

import * as fm from './files';
import * as net from 'net';
import * as stream from 'stream';

export namespace Files {
export let uriToFilePath = fm.uriToFilePath;
Expand Down Expand Up @@ -1478,17 +1476,13 @@ function _createConnection<PConsole = _, PTracer = _, PTelemetry = _, PClient =
}
}
if (port) {
output = new stream.PassThrough();
input = new stream.PassThrough();
let server = net.createServer(socket => {
server.close();
socket.pipe(output as stream.PassThrough);
(input as stream.PassThrough).pipe(socket);
}).listen(port);
let transport = createServerSocketTransport(port);
input = transport[0];
output = transport[1];
} else if (pipeName) {
let protocol = createServerPipeTransport(pipeName);
input = protocol[0];
output = protocol[1];
let transport = createServerPipeTransport(pipeName);
input = transport[0];
output = transport[1];
}
}
var commandLineMessage = "Use arguments of createConnection or set command line parameters: '--node-ipc', '--stdio' or '--socket={number}'";
Expand Down

0 comments on commit d40191a

Please sign in to comment.