From 8fc88c6dc6d680278069bfcf4ebf36c8ad7633fa Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 22 Mar 2019 18:03:03 +0100 Subject: [PATCH] Move ipc.ts to /common/ --- src/vs/base/parts/ipc/common/ipc.ts | 748 +++++++++++++++++- .../electron-browser/ipc.electron-browser.ts | 2 +- .../ipc/electron-main/ipc.electron-main.ts | 2 +- src/vs/base/parts/ipc/node/ipc.cp.ts | 3 +- src/vs/base/parts/ipc/node/ipc.electron.ts | 2 +- src/vs/base/parts/ipc/node/ipc.net.ts | 2 +- src/vs/base/parts/ipc/node/ipc.ts | 748 ------------------ src/vs/base/parts/ipc/test/node/ipc.test.ts | 3 +- .../issue/issueReporterMain.ts | 2 +- .../sharedProcess/sharedProcessMain.ts | 3 +- src/vs/code/electron-main/app.ts | 2 +- .../platform/driver/electron-main/driver.ts | 2 +- .../electron-browser/sharedProcessService.ts | 3 +- .../electron-browser/extensionHost.ts | 2 +- .../extensionHostProcessManager.ts | 2 +- .../extensions/node/extensionHostMain.ts | 2 +- .../extensions/node/extensionHostProcess.ts | 2 +- .../services/extensions/node/rpcProtocol.ts | 2 +- .../extensions/test/node/rpcProtocol.test.ts | 2 +- .../files/node/watcher/nsfw/watcherService.ts | 2 +- .../files/node/watcher/unix/watcherService.ts | 2 +- .../remoteAgentServiceImpl.ts | 3 +- .../services/search/node/searchService.ts | 2 +- 23 files changed, 766 insertions(+), 777 deletions(-) delete mode 100644 src/vs/base/parts/ipc/node/ipc.ts diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index af712fd86b3..88d71c6e643 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -3,8 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from 'vs/base/common/cancellation'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter, Relay } from 'vs/base/common/event'; +import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import * as errors from 'vs/base/common/errors'; +import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { VSBuffer } from 'vs/base/common/buffer'; /** * An `IChannel` is an abstraction over a collection of commands. @@ -25,4 +30,741 @@ export interface IChannel { export interface IServerChannel { call(ctx: TContext, command: string, arg?: any, cancellationToken?: CancellationToken): Promise; listen(ctx: TContext, event: string, arg?: any): Event; -} \ No newline at end of file +} + + +export const enum RequestType { + Promise = 100, + PromiseCancel = 101, + EventListen = 102, + EventDispose = 103 +} + +type IRawPromiseRequest = { type: RequestType.Promise; id: number; channelName: string; name: string; arg: any; }; +type IRawPromiseCancelRequest = { type: RequestType.PromiseCancel, id: number }; +type IRawEventListenRequest = { type: RequestType.EventListen; id: number; channelName: string; name: string; arg: any; }; +type IRawEventDisposeRequest = { type: RequestType.EventDispose, id: number }; +type IRawRequest = IRawPromiseRequest | IRawPromiseCancelRequest | IRawEventListenRequest | IRawEventDisposeRequest; + +export const enum ResponseType { + Initialize = 200, + PromiseSuccess = 201, + PromiseError = 202, + PromiseErrorObj = 203, + EventFire = 204 +} + +type IRawInitializeResponse = { type: ResponseType.Initialize }; +type IRawPromiseSuccessResponse = { type: ResponseType.PromiseSuccess; id: number; data: any }; +type IRawPromiseErrorResponse = { type: ResponseType.PromiseError; id: number; data: { message: string, name: string, stack: string[] | undefined } }; +type IRawPromiseErrorObjResponse = { type: ResponseType.PromiseErrorObj; id: number; data: any }; +type IRawEventFireResponse = { type: ResponseType.EventFire; id: number; data: any }; +type IRawResponse = IRawInitializeResponse | IRawPromiseSuccessResponse | IRawPromiseErrorResponse | IRawPromiseErrorObjResponse | IRawEventFireResponse; + +interface IHandler { + (response: IRawResponse): void; +} + +export interface IMessagePassingProtocol { + send(buffer: VSBuffer): void; + onMessage: Event; +} + +enum State { + Uninitialized, + Idle +} + +/** + * An `IChannelServer` hosts a collection of channels. You are + * able to register channels onto it, provided a channel name. + */ +export interface IChannelServer { + registerChannel(channelName: string, channel: IServerChannel): void; +} + +/** + * An `IChannelClient` has access to a collection of channels. You + * are able to get those channels, given their channel name. + */ +export interface IChannelClient { + getChannel(channelName: string): T; +} + +export interface Client { + readonly ctx: TContext; +} + +export interface IConnectionHub { + readonly connections: Connection[]; + readonly onDidChangeConnections: Event>; +} + +/** + * An `IClientRouter` is responsible for routing calls to specific + * channels, in scenarios in which there are multiple possible + * channels (each from a separate client) to pick from. + */ +export interface IClientRouter { + routeCall(hub: IConnectionHub, command: string, arg?: any, cancellationToken?: CancellationToken): Promise>; + routeEvent(hub: IConnectionHub, event: string, arg?: any): Promise>; +} + +/** + * Similar to the `IChannelClient`, you can get channels from this + * collection of channels. The difference being that in the + * `IRoutingChannelClient`, there are multiple clients providing + * the same channel. You'll need to pass in an `IClientRouter` in + * order to pick the right one. + */ +export interface IRoutingChannelClient { + getChannel(channelName: string, router: IClientRouter): T; +} + +interface IReader { + read(bytes: number): VSBuffer; +} + +interface IWriter { + write(buffer: VSBuffer): void; +} + +class BufferReader implements IReader { + + private pos = 0; + + constructor(private buffer: VSBuffer) { } + + read(bytes: number): VSBuffer { + const result = this.buffer.slice(this.pos, this.pos + bytes); + this.pos += result.byteLength; + return result; + } +} + +class BufferWriter implements IWriter { + + private buffers: VSBuffer[] = []; + + get buffer(): VSBuffer { + return VSBuffer.concat(this.buffers); + } + + write(buffer: VSBuffer): void { + this.buffers.push(buffer); + } +} + +enum DataType { + Undefined = 0, + String = 1, + Buffer = 2, + VSBuffer = 3, + Array = 4, + Object = 5 +} + +function createSizeBuffer(size: number): VSBuffer { + const result = VSBuffer.alloc(4); + result.writeUint32BE(size, 0); + return result; +} + +function readSizeBuffer(reader: IReader): number { + return reader.read(4).readUint32BE(0); +} + +function createOneByteBuffer(value: number): VSBuffer { + const result = VSBuffer.alloc(1); + result.writeUint8(value, 0); + return result; +} + +const BufferPresets = { + Undefined: createOneByteBuffer(DataType.Undefined), + String: createOneByteBuffer(DataType.String), + Buffer: createOneByteBuffer(DataType.Buffer), + VSBuffer: createOneByteBuffer(DataType.VSBuffer), + Array: createOneByteBuffer(DataType.Array), + Object: createOneByteBuffer(DataType.Object), +}; + +function serialize(writer: IWriter, data: any): void { + if (typeof data === 'undefined') { + writer.write(BufferPresets.Undefined); + } else if (typeof data === 'string') { + const buffer = VSBuffer.fromString(data); + writer.write(BufferPresets.String); + writer.write(createSizeBuffer(buffer.byteLength)); + writer.write(buffer); + } else if (Buffer.isBuffer(data)) { + const buffer = VSBuffer.wrap(data); + writer.write(BufferPresets.Buffer); + writer.write(createSizeBuffer(buffer.byteLength)); + writer.write(buffer); + } else if (data instanceof VSBuffer) { + writer.write(BufferPresets.VSBuffer); + writer.write(createSizeBuffer(data.byteLength)); + writer.write(data); + } else if (Array.isArray(data)) { + writer.write(BufferPresets.Array); + writer.write(createSizeBuffer(data.length)); + + for (const el of data) { + serialize(writer, el); + } + } else { + const buffer = VSBuffer.fromString(JSON.stringify(data)); + writer.write(BufferPresets.Object); + writer.write(createSizeBuffer(buffer.byteLength)); + writer.write(buffer); + } +} + +function deserialize(reader: IReader): any { + const type = reader.read(1).readUint8(0); + + switch (type) { + case DataType.Undefined: return undefined; + case DataType.String: return reader.read(readSizeBuffer(reader)).toString(); + case DataType.Buffer: return reader.read(readSizeBuffer(reader)).toBuffer(); + case DataType.VSBuffer: return reader.read(readSizeBuffer(reader)); + case DataType.Array: { + const length = readSizeBuffer(reader); + const result: any[] = []; + + for (let i = 0; i < length; i++) { + result.push(deserialize(reader)); + } + + return result; + } + case DataType.Object: return JSON.parse(reader.read(readSizeBuffer(reader)).toString()); + } +} + +export class ChannelServer implements IChannelServer, IDisposable { + + private channels = new Map>(); + private activeRequests = new Map(); + private protocolListener: IDisposable | null; + + constructor(private protocol: IMessagePassingProtocol, private ctx: TContext) { + this.protocolListener = this.protocol.onMessage(msg => this.onRawMessage(msg)); + this.sendResponse({ type: ResponseType.Initialize }); + } + + registerChannel(channelName: string, channel: IServerChannel): void { + this.channels.set(channelName, channel); + } + + private sendResponse(response: IRawResponse): void { + switch (response.type) { + case ResponseType.Initialize: + return this.send([response.type]); + + case ResponseType.PromiseSuccess: + case ResponseType.PromiseError: + case ResponseType.EventFire: + case ResponseType.PromiseErrorObj: + return this.send([response.type, response.id], response.data); + } + } + + private send(header: any, body: any = undefined): void { + const writer = new BufferWriter(); + serialize(writer, header); + serialize(writer, body); + this.sendBuffer(writer.buffer); + } + + private sendBuffer(message: VSBuffer): void { + try { + this.protocol.send(message); + } catch (err) { + // noop + } + } + + private onRawMessage(message: VSBuffer): void { + const reader = new BufferReader(message); + const header = deserialize(reader); + const body = deserialize(reader); + const type = header[0] as RequestType; + + switch (type) { + case RequestType.Promise: + return this.onPromise({ type, id: header[1], channelName: header[2], name: header[3], arg: body }); + case RequestType.EventListen: + return this.onEventListen({ type, id: header[1], channelName: header[2], name: header[3], arg: body }); + case RequestType.PromiseCancel: + return this.disposeActiveRequest({ type, id: header[1] }); + case RequestType.EventDispose: + return this.disposeActiveRequest({ type, id: header[1] }); + } + } + + private onPromise(request: IRawPromiseRequest): void { + const channel = this.channels.get(request.channelName); + if (!channel) { + throw new Error('Unknown channel'); + } + const cancellationTokenSource = new CancellationTokenSource(); + let promise: Promise; + + try { + promise = channel.call(this.ctx, request.name, request.arg, cancellationTokenSource.token); + } catch (err) { + promise = Promise.reject(err); + } + + const id = request.id; + + promise.then(data => { + this.sendResponse({ id, data, type: ResponseType.PromiseSuccess }); + this.activeRequests.delete(request.id); + }, err => { + if (err instanceof Error) { + this.sendResponse({ + id, data: { + message: err.message, + name: err.name, + stack: err.stack ? (err.stack.split ? err.stack.split('\n') : err.stack) : undefined + }, type: ResponseType.PromiseError + }); + } else { + this.sendResponse({ id, data: err, type: ResponseType.PromiseErrorObj }); + } + + this.activeRequests.delete(request.id); + }); + + const disposable = toDisposable(() => cancellationTokenSource.cancel()); + this.activeRequests.set(request.id, disposable); + } + + private onEventListen(request: IRawEventListenRequest): void { + const channel = this.channels.get(request.channelName); + if (!channel) { + throw new Error('Unknown channel'); + } + + const id = request.id; + const event = channel.listen(this.ctx, request.name, request.arg); + const disposable = event(data => this.sendResponse({ id, data, type: ResponseType.EventFire })); + + this.activeRequests.set(request.id, disposable); + } + + private disposeActiveRequest(request: IRawRequest): void { + const disposable = this.activeRequests.get(request.id); + + if (disposable) { + disposable.dispose(); + this.activeRequests.delete(request.id); + } + } + + public dispose(): void { + if (this.protocolListener) { + this.protocolListener.dispose(); + this.protocolListener = null; + } + this.activeRequests.forEach(d => d.dispose()); + this.activeRequests.clear(); + } +} + +export class ChannelClient implements IChannelClient, IDisposable { + + private state: State = State.Uninitialized; + private activeRequests = new Set(); + private handlers = new Map(); + private lastRequestId: number = 0; + private protocolListener: IDisposable | null; + + private _onDidInitialize = new Emitter(); + readonly onDidInitialize = this._onDidInitialize.event; + + constructor(private protocol: IMessagePassingProtocol) { + this.protocolListener = this.protocol.onMessage(msg => this.onBuffer(msg)); + } + + getChannel(channelName: string): T { + const that = this; + + return { + call(command: string, arg?: any, cancellationToken?: CancellationToken) { + return that.requestPromise(channelName, command, arg, cancellationToken); + }, + listen(event: string, arg: any) { + return that.requestEvent(channelName, event, arg); + } + } as T; + } + + private requestPromise(channelName: string, name: string, arg?: any, cancellationToken = CancellationToken.None): Promise { + const id = this.lastRequestId++; + const type = RequestType.Promise; + const request: IRawRequest = { id, type, channelName, name, arg }; + + if (cancellationToken.isCancellationRequested) { + return Promise.reject(errors.canceled()); + } + + let disposable: IDisposable; + + const result = new Promise((c, e) => { + if (cancellationToken.isCancellationRequested) { + return e(errors.canceled()); + } + + let uninitializedPromise: CancelablePromise | null = createCancelablePromise(_ => this.whenInitialized()); + uninitializedPromise.then(() => { + uninitializedPromise = null; + + const handler: IHandler = response => { + switch (response.type) { + case ResponseType.PromiseSuccess: + this.handlers.delete(id); + c(response.data); + break; + + case ResponseType.PromiseError: + this.handlers.delete(id); + const error = new Error(response.data.message); + (error).stack = response.data.stack; + error.name = response.data.name; + e(error); + break; + + case ResponseType.PromiseErrorObj: + this.handlers.delete(id); + e(response.data); + break; + } + }; + + this.handlers.set(id, handler); + this.sendRequest(request); + }); + + const cancel = () => { + if (uninitializedPromise) { + uninitializedPromise.cancel(); + uninitializedPromise = null; + } else { + this.sendRequest({ id, type: RequestType.PromiseCancel }); + } + + e(errors.canceled()); + }; + + const cancellationTokenListener = cancellationToken.onCancellationRequested(cancel); + disposable = combinedDisposable([toDisposable(cancel), cancellationTokenListener]); + this.activeRequests.add(disposable); + }); + + return result.finally(() => this.activeRequests.delete(disposable)); + } + + private requestEvent(channelName: string, name: string, arg?: any): Event { + const id = this.lastRequestId++; + const type = RequestType.EventListen; + const request: IRawRequest = { id, type, channelName, name, arg }; + + let uninitializedPromise: CancelablePromise | null = null; + + const emitter = new Emitter({ + onFirstListenerAdd: () => { + uninitializedPromise = createCancelablePromise(_ => this.whenInitialized()); + uninitializedPromise.then(() => { + uninitializedPromise = null; + this.activeRequests.add(emitter); + this.sendRequest(request); + }); + }, + onLastListenerRemove: () => { + if (uninitializedPromise) { + uninitializedPromise.cancel(); + uninitializedPromise = null; + } else { + this.activeRequests.delete(emitter); + this.sendRequest({ id, type: RequestType.EventDispose }); + } + } + }); + + const handler: IHandler = (res: IRawEventFireResponse) => emitter.fire(res.data); + this.handlers.set(id, handler); + + return emitter.event; + } + + private sendRequest(request: IRawRequest): void { + switch (request.type) { + case RequestType.Promise: + case RequestType.EventListen: + return this.send([request.type, request.id, request.channelName, request.name], request.arg); + + case RequestType.PromiseCancel: + case RequestType.EventDispose: + return this.send([request.type, request.id]); + } + } + + private send(header: any, body: any = undefined): void { + const writer = new BufferWriter(); + serialize(writer, header); + serialize(writer, body); + this.sendBuffer(writer.buffer); + } + + private sendBuffer(message: VSBuffer): void { + try { + this.protocol.send(message); + } catch (err) { + // noop + } + } + + private onBuffer(message: VSBuffer): void { + const reader = new BufferReader(message); + const header = deserialize(reader); + const body = deserialize(reader); + const type: ResponseType = header[0]; + + switch (type) { + case ResponseType.Initialize: + return this.onResponse({ type: header[0] }); + + case ResponseType.PromiseSuccess: + case ResponseType.PromiseError: + case ResponseType.EventFire: + case ResponseType.PromiseErrorObj: + return this.onResponse({ type: header[0], id: header[1], data: body }); + } + } + + private onResponse(response: IRawResponse): void { + if (response.type === ResponseType.Initialize) { + this.state = State.Idle; + this._onDidInitialize.fire(); + return; + } + + const handler = this.handlers.get(response.id); + + if (handler) { + handler(response); + } + } + + private whenInitialized(): Promise { + if (this.state === State.Idle) { + return Promise.resolve(); + } else { + return Event.toPromise(this.onDidInitialize); + } + } + + dispose(): void { + if (this.protocolListener) { + this.protocolListener.dispose(); + this.protocolListener = null; + } + this.activeRequests.forEach(p => p.dispose()); + this.activeRequests.clear(); + } +} + +export interface ClientConnectionEvent { + protocol: IMessagePassingProtocol; + onDidClientDisconnect: Event; +} + +interface Connection extends Client { + readonly channelClient: ChannelClient; +} + +/** + * An `IPCServer` is both a channel server and a routing channel + * client. + * + * As the owner of a protocol, you should extend both this + * and the `IPCClient` classes to get IPC implementations + * for your protocol. + */ +export class IPCServer implements IChannelServer, IRoutingChannelClient, IConnectionHub, IDisposable { + + private channels = new Map>(); + private _connections = new Set>(); + + private _onDidChangeConnections = new Emitter>(); + readonly onDidChangeConnections: Event> = this._onDidChangeConnections.event; + + get connections(): Connection[] { + const result: Connection[] = []; + this._connections.forEach(ctx => result.push(ctx)); + return result; + } + + constructor(onDidClientConnect: Event) { + onDidClientConnect(({ protocol, onDidClientDisconnect }) => { + const onFirstMessage = Event.once(protocol.onMessage); + + onFirstMessage(msg => { + const reader = new BufferReader(msg); + const ctx = deserialize(reader) as TContext; + + const channelServer = new ChannelServer(protocol, ctx); + const channelClient = new ChannelClient(protocol); + + this.channels.forEach((channel, name) => channelServer.registerChannel(name, channel)); + + const connection: Connection = { channelClient, ctx }; + this._connections.add(connection); + this._onDidChangeConnections.fire(connection); + + onDidClientDisconnect(() => { + channelServer.dispose(); + channelClient.dispose(); + this._connections.delete(connection); + }); + }); + }); + } + + getChannel(channelName: string, router: IClientRouter): T { + const that = this; + + return { + call(command: string, arg?: any, cancellationToken?: CancellationToken) { + const channelPromise = router.routeCall(that, command, arg) + .then(connection => (connection as Connection).channelClient.getChannel(channelName)); + + return getDelayedChannel(channelPromise) + .call(command, arg, cancellationToken); + }, + listen(event: string, arg: any) { + const channelPromise = router.routeEvent(that, event, arg) + .then(connection => (connection as Connection).channelClient.getChannel(channelName)); + + return getDelayedChannel(channelPromise) + .listen(event, arg); + } + } as T; + } + + registerChannel(channelName: string, channel: IServerChannel): void { + this.channels.set(channelName, channel); + } + + dispose(): void { + this.channels.clear(); + this._connections.clear(); + this._onDidChangeConnections.dispose(); + } +} + +/** + * An `IPCClient` is both a channel client and a channel server. + * + * As the owner of a protocol, you should extend both this + * and the `IPCClient` classes to get IPC implementations + * for your protocol. + */ +export class IPCClient implements IChannelClient, IChannelServer, IDisposable { + + private channelClient: ChannelClient; + private channelServer: ChannelServer; + + constructor(protocol: IMessagePassingProtocol, ctx: TContext) { + const writer = new BufferWriter(); + serialize(writer, ctx); + protocol.send(writer.buffer); + + this.channelClient = new ChannelClient(protocol); + this.channelServer = new ChannelServer(protocol, ctx); + } + + getChannel(channelName: string): T { + return this.channelClient.getChannel(channelName) as T; + } + + registerChannel(channelName: string, channel: IServerChannel): void { + this.channelServer.registerChannel(channelName, channel); + } + + dispose(): void { + this.channelClient.dispose(); + this.channelServer.dispose(); + } +} + +export function getDelayedChannel(promise: Promise): T { + return { + call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { + return promise.then(c => c.call(command, arg, cancellationToken)); + }, + + listen(event: string, arg?: any): Event { + const relay = new Relay(); + promise.then(c => relay.input = c.listen(event, arg)); + return relay.event; + } + } as T; +} + +export function getNextTickChannel(channel: T): T { + let didTick = false; + + return { + call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { + if (didTick) { + return channel.call(command, arg, cancellationToken); + } + + return timeout(0) + .then(() => didTick = true) + .then(() => channel.call(command, arg, cancellationToken)); + }, + listen(event: string, arg?: any): Event { + if (didTick) { + return channel.listen(event, arg); + } + + const relay = new Relay(); + + timeout(0) + .then(() => didTick = true) + .then(() => relay.input = channel.listen(event, arg)); + + return relay.event; + } + } as T; +} + +export class StaticRouter implements IClientRouter { + + constructor(private fn: (ctx: TContext) => boolean | Promise) { } + + routeCall(hub: IConnectionHub): Promise> { + return this.route(hub); + } + + routeEvent(hub: IConnectionHub): Promise> { + return this.route(hub); + } + + private async route(hub: IConnectionHub): Promise> { + for (const connection of hub.connections) { + if (await Promise.resolve(this.fn(connection.ctx))) { + return Promise.resolve(connection); + } + } + + await Event.toPromise(hub.onDidChangeConnections); + return await this.route(hub); + } +} diff --git a/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts b/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts index 4239a6d3a1c..2690300b83a 100644 --- a/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts +++ b/src/vs/base/parts/ipc/electron-browser/ipc.electron-browser.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IPCClient } from 'vs/base/parts/ipc/node/ipc'; +import { IPCClient } from 'vs/base/parts/ipc/common/ipc'; import { Protocol } from 'vs/base/parts/ipc/node/ipc.electron'; import { ipcRenderer } from 'electron'; import { IDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts index e25e7721ad4..c5fbbb4e65b 100644 --- a/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts +++ b/src/vs/base/parts/ipc/electron-main/ipc.electron-main.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { IPCServer, ClientConnectionEvent } from 'vs/base/parts/ipc/node/ipc'; +import { IPCServer, ClientConnectionEvent } from 'vs/base/parts/ipc/common/ipc'; import { Protocol } from 'vs/base/parts/ipc/node/ipc.electron'; import { ipcMain } from 'electron'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts index 961ab3e745c..8d77ae19373 100644 --- a/src/vs/base/parts/ipc/node/ipc.cp.ts +++ b/src/vs/base/parts/ipc/node/ipc.cp.ts @@ -9,11 +9,10 @@ import { Delayer, createCancelablePromise } from 'vs/base/common/async'; import { deepClone, assign } from 'vs/base/common/objects'; import { Emitter, Event } from 'vs/base/common/event'; import { createQueuedSender } from 'vs/base/node/processes'; -import { ChannelServer as IPCServer, ChannelClient as IPCClient, IChannelClient } from 'vs/base/parts/ipc/node/ipc'; +import { IChannel, ChannelServer as IPCServer, ChannelClient as IPCClient, IChannelClient } from 'vs/base/parts/ipc/common/ipc'; import { isRemoteConsoleLog, log } from 'vs/base/common/console'; import { CancellationToken } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; -import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { VSBuffer } from 'vs/base/common/buffer'; /** diff --git a/src/vs/base/parts/ipc/node/ipc.electron.ts b/src/vs/base/parts/ipc/node/ipc.electron.ts index a636f92cc54..2e971246b4f 100644 --- a/src/vs/base/parts/ipc/node/ipc.electron.ts +++ b/src/vs/base/parts/ipc/node/ipc.electron.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; import { VSBuffer } from 'vs/base/common/buffer'; diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index 46ebcdc0bd8..eaee449bc1a 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -5,7 +5,7 @@ import { Socket, Server as NetServer, createConnection, createServer } from 'net'; import { Event, Emitter } from 'vs/base/common/event'; -import { IMessagePassingProtocol, ClientConnectionEvent, IPCServer, IPCClient } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol, ClientConnectionEvent, IPCServer, IPCClient } from 'vs/base/parts/ipc/common/ipc'; import { join } from 'vs/base/common/path'; import { tmpdir } from 'os'; import { generateUuid } from 'vs/base/common/uuid'; diff --git a/src/vs/base/parts/ipc/node/ipc.ts b/src/vs/base/parts/ipc/node/ipc.ts deleted file mode 100644 index 65fafca96df..00000000000 --- a/src/vs/base/parts/ipc/node/ipc.ts +++ /dev/null @@ -1,748 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; -import { Event, Emitter, Relay } from 'vs/base/common/event'; -import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import * as errors from 'vs/base/common/errors'; -import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { VSBuffer } from 'vs/base/common/buffer'; - -export const enum RequestType { - Promise = 100, - PromiseCancel = 101, - EventListen = 102, - EventDispose = 103 -} - -type IRawPromiseRequest = { type: RequestType.Promise; id: number; channelName: string; name: string; arg: any; }; -type IRawPromiseCancelRequest = { type: RequestType.PromiseCancel, id: number }; -type IRawEventListenRequest = { type: RequestType.EventListen; id: number; channelName: string; name: string; arg: any; }; -type IRawEventDisposeRequest = { type: RequestType.EventDispose, id: number }; -type IRawRequest = IRawPromiseRequest | IRawPromiseCancelRequest | IRawEventListenRequest | IRawEventDisposeRequest; - -export const enum ResponseType { - Initialize = 200, - PromiseSuccess = 201, - PromiseError = 202, - PromiseErrorObj = 203, - EventFire = 204 -} - -type IRawInitializeResponse = { type: ResponseType.Initialize }; -type IRawPromiseSuccessResponse = { type: ResponseType.PromiseSuccess; id: number; data: any }; -type IRawPromiseErrorResponse = { type: ResponseType.PromiseError; id: number; data: { message: string, name: string, stack: string[] | undefined } }; -type IRawPromiseErrorObjResponse = { type: ResponseType.PromiseErrorObj; id: number; data: any }; -type IRawEventFireResponse = { type: ResponseType.EventFire; id: number; data: any }; -type IRawResponse = IRawInitializeResponse | IRawPromiseSuccessResponse | IRawPromiseErrorResponse | IRawPromiseErrorObjResponse | IRawEventFireResponse; - -interface IHandler { - (response: IRawResponse): void; -} - -export interface IMessagePassingProtocol { - send(buffer: VSBuffer): void; - onMessage: Event; -} - -enum State { - Uninitialized, - Idle -} - -/** - * An `IChannelServer` hosts a collection of channels. You are - * able to register channels onto it, provided a channel name. - */ -export interface IChannelServer { - registerChannel(channelName: string, channel: IServerChannel): void; -} - -/** - * An `IChannelClient` has access to a collection of channels. You - * are able to get those channels, given their channel name. - */ -export interface IChannelClient { - getChannel(channelName: string): T; -} - -export interface Client { - readonly ctx: TContext; -} - -export interface IConnectionHub { - readonly connections: Connection[]; - readonly onDidChangeConnections: Event>; -} - -/** - * An `IClientRouter` is responsible for routing calls to specific - * channels, in scenarios in which there are multiple possible - * channels (each from a separate client) to pick from. - */ -export interface IClientRouter { - routeCall(hub: IConnectionHub, command: string, arg?: any, cancellationToken?: CancellationToken): Promise>; - routeEvent(hub: IConnectionHub, event: string, arg?: any): Promise>; -} - -/** - * Similar to the `IChannelClient`, you can get channels from this - * collection of channels. The difference being that in the - * `IRoutingChannelClient`, there are multiple clients providing - * the same channel. You'll need to pass in an `IClientRouter` in - * order to pick the right one. - */ -export interface IRoutingChannelClient { - getChannel(channelName: string, router: IClientRouter): T; -} - -interface IReader { - read(bytes: number): VSBuffer; -} - -interface IWriter { - write(buffer: VSBuffer): void; -} - -class BufferReader implements IReader { - - private pos = 0; - - constructor(private buffer: VSBuffer) { } - - read(bytes: number): VSBuffer { - const result = this.buffer.slice(this.pos, this.pos + bytes); - this.pos += result.byteLength; - return result; - } -} - -class BufferWriter implements IWriter { - - private buffers: VSBuffer[] = []; - - get buffer(): VSBuffer { - return VSBuffer.concat(this.buffers); - } - - write(buffer: VSBuffer): void { - this.buffers.push(buffer); - } -} - -enum DataType { - Undefined = 0, - String = 1, - Buffer = 2, - VSBuffer = 3, - Array = 4, - Object = 5 -} - -function createSizeBuffer(size: number): VSBuffer { - const result = VSBuffer.alloc(4); - result.writeUint32BE(size, 0); - return result; -} - -function readSizeBuffer(reader: IReader): number { - return reader.read(4).readUint32BE(0); -} - -function createOneByteBuffer(value: number): VSBuffer { - const result = VSBuffer.alloc(1); - result.writeUint8(value, 0); - return result; -} - -const BufferPresets = { - Undefined: createOneByteBuffer(DataType.Undefined), - String: createOneByteBuffer(DataType.String), - Buffer: createOneByteBuffer(DataType.Buffer), - VSBuffer: createOneByteBuffer(DataType.VSBuffer), - Array: createOneByteBuffer(DataType.Array), - Object: createOneByteBuffer(DataType.Object), -}; - -function serialize(writer: IWriter, data: any): void { - if (typeof data === 'undefined') { - writer.write(BufferPresets.Undefined); - } else if (typeof data === 'string') { - const buffer = VSBuffer.fromString(data); - writer.write(BufferPresets.String); - writer.write(createSizeBuffer(buffer.byteLength)); - writer.write(buffer); - } else if (Buffer.isBuffer(data)) { - const buffer = VSBuffer.wrap(data); - writer.write(BufferPresets.Buffer); - writer.write(createSizeBuffer(buffer.byteLength)); - writer.write(buffer); - } else if (data instanceof VSBuffer) { - writer.write(BufferPresets.VSBuffer); - writer.write(createSizeBuffer(data.byteLength)); - writer.write(data); - } else if (Array.isArray(data)) { - writer.write(BufferPresets.Array); - writer.write(createSizeBuffer(data.length)); - - for (const el of data) { - serialize(writer, el); - } - } else { - const buffer = VSBuffer.fromString(JSON.stringify(data)); - writer.write(BufferPresets.Object); - writer.write(createSizeBuffer(buffer.byteLength)); - writer.write(buffer); - } -} - -function deserialize(reader: IReader): any { - const type = reader.read(1).readUint8(0); - - switch (type) { - case DataType.Undefined: return undefined; - case DataType.String: return reader.read(readSizeBuffer(reader)).toString(); - case DataType.Buffer: return reader.read(readSizeBuffer(reader)).toBuffer(); - case DataType.VSBuffer: return reader.read(readSizeBuffer(reader)); - case DataType.Array: { - const length = readSizeBuffer(reader); - const result: any[] = []; - - for (let i = 0; i < length; i++) { - result.push(deserialize(reader)); - } - - return result; - } - case DataType.Object: return JSON.parse(reader.read(readSizeBuffer(reader)).toString()); - } -} - -export class ChannelServer implements IChannelServer, IDisposable { - - private channels = new Map>(); - private activeRequests = new Map(); - private protocolListener: IDisposable | null; - - constructor(private protocol: IMessagePassingProtocol, private ctx: TContext) { - this.protocolListener = this.protocol.onMessage(msg => this.onRawMessage(msg)); - this.sendResponse({ type: ResponseType.Initialize }); - } - - registerChannel(channelName: string, channel: IServerChannel): void { - this.channels.set(channelName, channel); - } - - private sendResponse(response: IRawResponse): void { - switch (response.type) { - case ResponseType.Initialize: - return this.send([response.type]); - - case ResponseType.PromiseSuccess: - case ResponseType.PromiseError: - case ResponseType.EventFire: - case ResponseType.PromiseErrorObj: - return this.send([response.type, response.id], response.data); - } - } - - private send(header: any, body: any = undefined): void { - const writer = new BufferWriter(); - serialize(writer, header); - serialize(writer, body); - this.sendBuffer(writer.buffer); - } - - private sendBuffer(message: VSBuffer): void { - try { - this.protocol.send(message); - } catch (err) { - // noop - } - } - - private onRawMessage(message: VSBuffer): void { - const reader = new BufferReader(message); - const header = deserialize(reader); - const body = deserialize(reader); - const type = header[0] as RequestType; - - switch (type) { - case RequestType.Promise: - return this.onPromise({ type, id: header[1], channelName: header[2], name: header[3], arg: body }); - case RequestType.EventListen: - return this.onEventListen({ type, id: header[1], channelName: header[2], name: header[3], arg: body }); - case RequestType.PromiseCancel: - return this.disposeActiveRequest({ type, id: header[1] }); - case RequestType.EventDispose: - return this.disposeActiveRequest({ type, id: header[1] }); - } - } - - private onPromise(request: IRawPromiseRequest): void { - const channel = this.channels.get(request.channelName); - if (!channel) { - throw new Error('Unknown channel'); - } - const cancellationTokenSource = new CancellationTokenSource(); - let promise: Promise; - - try { - promise = channel.call(this.ctx, request.name, request.arg, cancellationTokenSource.token); - } catch (err) { - promise = Promise.reject(err); - } - - const id = request.id; - - promise.then(data => { - this.sendResponse({ id, data, type: ResponseType.PromiseSuccess }); - this.activeRequests.delete(request.id); - }, err => { - if (err instanceof Error) { - this.sendResponse({ - id, data: { - message: err.message, - name: err.name, - stack: err.stack ? (err.stack.split ? err.stack.split('\n') : err.stack) : undefined - }, type: ResponseType.PromiseError - }); - } else { - this.sendResponse({ id, data: err, type: ResponseType.PromiseErrorObj }); - } - - this.activeRequests.delete(request.id); - }); - - const disposable = toDisposable(() => cancellationTokenSource.cancel()); - this.activeRequests.set(request.id, disposable); - } - - private onEventListen(request: IRawEventListenRequest): void { - const channel = this.channels.get(request.channelName); - if (!channel) { - throw new Error('Unknown channel'); - } - - const id = request.id; - const event = channel.listen(this.ctx, request.name, request.arg); - const disposable = event(data => this.sendResponse({ id, data, type: ResponseType.EventFire })); - - this.activeRequests.set(request.id, disposable); - } - - private disposeActiveRequest(request: IRawRequest): void { - const disposable = this.activeRequests.get(request.id); - - if (disposable) { - disposable.dispose(); - this.activeRequests.delete(request.id); - } - } - - public dispose(): void { - if (this.protocolListener) { - this.protocolListener.dispose(); - this.protocolListener = null; - } - this.activeRequests.forEach(d => d.dispose()); - this.activeRequests.clear(); - } -} - -export class ChannelClient implements IChannelClient, IDisposable { - - private state: State = State.Uninitialized; - private activeRequests = new Set(); - private handlers = new Map(); - private lastRequestId: number = 0; - private protocolListener: IDisposable | null; - - private _onDidInitialize = new Emitter(); - readonly onDidInitialize = this._onDidInitialize.event; - - constructor(private protocol: IMessagePassingProtocol) { - this.protocolListener = this.protocol.onMessage(msg => this.onBuffer(msg)); - } - - getChannel(channelName: string): T { - const that = this; - - return { - call(command: string, arg?: any, cancellationToken?: CancellationToken) { - return that.requestPromise(channelName, command, arg, cancellationToken); - }, - listen(event: string, arg: any) { - return that.requestEvent(channelName, event, arg); - } - } as T; - } - - private requestPromise(channelName: string, name: string, arg?: any, cancellationToken = CancellationToken.None): Promise { - const id = this.lastRequestId++; - const type = RequestType.Promise; - const request: IRawRequest = { id, type, channelName, name, arg }; - - if (cancellationToken.isCancellationRequested) { - return Promise.reject(errors.canceled()); - } - - let disposable: IDisposable; - - const result = new Promise((c, e) => { - if (cancellationToken.isCancellationRequested) { - return e(errors.canceled()); - } - - let uninitializedPromise: CancelablePromise | null = createCancelablePromise(_ => this.whenInitialized()); - uninitializedPromise.then(() => { - uninitializedPromise = null; - - const handler: IHandler = response => { - switch (response.type) { - case ResponseType.PromiseSuccess: - this.handlers.delete(id); - c(response.data); - break; - - case ResponseType.PromiseError: - this.handlers.delete(id); - const error = new Error(response.data.message); - (error).stack = response.data.stack; - error.name = response.data.name; - e(error); - break; - - case ResponseType.PromiseErrorObj: - this.handlers.delete(id); - e(response.data); - break; - } - }; - - this.handlers.set(id, handler); - this.sendRequest(request); - }); - - const cancel = () => { - if (uninitializedPromise) { - uninitializedPromise.cancel(); - uninitializedPromise = null; - } else { - this.sendRequest({ id, type: RequestType.PromiseCancel }); - } - - e(errors.canceled()); - }; - - const cancellationTokenListener = cancellationToken.onCancellationRequested(cancel); - disposable = combinedDisposable([toDisposable(cancel), cancellationTokenListener]); - this.activeRequests.add(disposable); - }); - - return result.finally(() => this.activeRequests.delete(disposable)); - } - - private requestEvent(channelName: string, name: string, arg?: any): Event { - const id = this.lastRequestId++; - const type = RequestType.EventListen; - const request: IRawRequest = { id, type, channelName, name, arg }; - - let uninitializedPromise: CancelablePromise | null = null; - - const emitter = new Emitter({ - onFirstListenerAdd: () => { - uninitializedPromise = createCancelablePromise(_ => this.whenInitialized()); - uninitializedPromise.then(() => { - uninitializedPromise = null; - this.activeRequests.add(emitter); - this.sendRequest(request); - }); - }, - onLastListenerRemove: () => { - if (uninitializedPromise) { - uninitializedPromise.cancel(); - uninitializedPromise = null; - } else { - this.activeRequests.delete(emitter); - this.sendRequest({ id, type: RequestType.EventDispose }); - } - } - }); - - const handler: IHandler = (res: IRawEventFireResponse) => emitter.fire(res.data); - this.handlers.set(id, handler); - - return emitter.event; - } - - private sendRequest(request: IRawRequest): void { - switch (request.type) { - case RequestType.Promise: - case RequestType.EventListen: - return this.send([request.type, request.id, request.channelName, request.name], request.arg); - - case RequestType.PromiseCancel: - case RequestType.EventDispose: - return this.send([request.type, request.id]); - } - } - - private send(header: any, body: any = undefined): void { - const writer = new BufferWriter(); - serialize(writer, header); - serialize(writer, body); - this.sendBuffer(writer.buffer); - } - - private sendBuffer(message: VSBuffer): void { - try { - this.protocol.send(message); - } catch (err) { - // noop - } - } - - private onBuffer(message: VSBuffer): void { - const reader = new BufferReader(message); - const header = deserialize(reader); - const body = deserialize(reader); - const type: ResponseType = header[0]; - - switch (type) { - case ResponseType.Initialize: - return this.onResponse({ type: header[0] }); - - case ResponseType.PromiseSuccess: - case ResponseType.PromiseError: - case ResponseType.EventFire: - case ResponseType.PromiseErrorObj: - return this.onResponse({ type: header[0], id: header[1], data: body }); - } - } - - private onResponse(response: IRawResponse): void { - if (response.type === ResponseType.Initialize) { - this.state = State.Idle; - this._onDidInitialize.fire(); - return; - } - - const handler = this.handlers.get(response.id); - - if (handler) { - handler(response); - } - } - - private whenInitialized(): Promise { - if (this.state === State.Idle) { - return Promise.resolve(); - } else { - return Event.toPromise(this.onDidInitialize); - } - } - - dispose(): void { - if (this.protocolListener) { - this.protocolListener.dispose(); - this.protocolListener = null; - } - this.activeRequests.forEach(p => p.dispose()); - this.activeRequests.clear(); - } -} - -export interface ClientConnectionEvent { - protocol: IMessagePassingProtocol; - onDidClientDisconnect: Event; -} - -interface Connection extends Client { - readonly channelClient: ChannelClient; -} - -/** - * An `IPCServer` is both a channel server and a routing channel - * client. - * - * As the owner of a protocol, you should extend both this - * and the `IPCClient` classes to get IPC implementations - * for your protocol. - */ -export class IPCServer implements IChannelServer, IRoutingChannelClient, IConnectionHub, IDisposable { - - private channels = new Map>(); - private _connections = new Set>(); - - private _onDidChangeConnections = new Emitter>(); - readonly onDidChangeConnections: Event> = this._onDidChangeConnections.event; - - get connections(): Connection[] { - const result: Connection[] = []; - this._connections.forEach(ctx => result.push(ctx)); - return result; - } - - constructor(onDidClientConnect: Event) { - onDidClientConnect(({ protocol, onDidClientDisconnect }) => { - const onFirstMessage = Event.once(protocol.onMessage); - - onFirstMessage(msg => { - const reader = new BufferReader(msg); - const ctx = deserialize(reader) as TContext; - - const channelServer = new ChannelServer(protocol, ctx); - const channelClient = new ChannelClient(protocol); - - this.channels.forEach((channel, name) => channelServer.registerChannel(name, channel)); - - const connection: Connection = { channelClient, ctx }; - this._connections.add(connection); - this._onDidChangeConnections.fire(connection); - - onDidClientDisconnect(() => { - channelServer.dispose(); - channelClient.dispose(); - this._connections.delete(connection); - }); - }); - }); - } - - getChannel(channelName: string, router: IClientRouter): T { - const that = this; - - return { - call(command: string, arg?: any, cancellationToken?: CancellationToken) { - const channelPromise = router.routeCall(that, command, arg) - .then(connection => (connection as Connection).channelClient.getChannel(channelName)); - - return getDelayedChannel(channelPromise) - .call(command, arg, cancellationToken); - }, - listen(event: string, arg: any) { - const channelPromise = router.routeEvent(that, event, arg) - .then(connection => (connection as Connection).channelClient.getChannel(channelName)); - - return getDelayedChannel(channelPromise) - .listen(event, arg); - } - } as T; - } - - registerChannel(channelName: string, channel: IServerChannel): void { - this.channels.set(channelName, channel); - } - - dispose(): void { - this.channels.clear(); - this._connections.clear(); - this._onDidChangeConnections.dispose(); - } -} - -/** - * An `IPCClient` is both a channel client and a channel server. - * - * As the owner of a protocol, you should extend both this - * and the `IPCClient` classes to get IPC implementations - * for your protocol. - */ -export class IPCClient implements IChannelClient, IChannelServer, IDisposable { - - private channelClient: ChannelClient; - private channelServer: ChannelServer; - - constructor(protocol: IMessagePassingProtocol, ctx: TContext) { - const writer = new BufferWriter(); - serialize(writer, ctx); - protocol.send(writer.buffer); - - this.channelClient = new ChannelClient(protocol); - this.channelServer = new ChannelServer(protocol, ctx); - } - - getChannel(channelName: string): T { - return this.channelClient.getChannel(channelName) as T; - } - - registerChannel(channelName: string, channel: IServerChannel): void { - this.channelServer.registerChannel(channelName, channel); - } - - dispose(): void { - this.channelClient.dispose(); - this.channelServer.dispose(); - } -} - -export function getDelayedChannel(promise: Promise): T { - return { - call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { - return promise.then(c => c.call(command, arg, cancellationToken)); - }, - - listen(event: string, arg?: any): Event { - const relay = new Relay(); - promise.then(c => relay.input = c.listen(event, arg)); - return relay.event; - } - } as T; -} - -export function getNextTickChannel(channel: T): T { - let didTick = false; - - return { - call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise { - if (didTick) { - return channel.call(command, arg, cancellationToken); - } - - return timeout(0) - .then(() => didTick = true) - .then(() => channel.call(command, arg, cancellationToken)); - }, - listen(event: string, arg?: any): Event { - if (didTick) { - return channel.listen(event, arg); - } - - const relay = new Relay(); - - timeout(0) - .then(() => didTick = true) - .then(() => relay.input = channel.listen(event, arg)); - - return relay.event; - } - } as T; -} - -export class StaticRouter implements IClientRouter { - - constructor(private fn: (ctx: TContext) => boolean | Promise) { } - - routeCall(hub: IConnectionHub): Promise> { - return this.route(hub); - } - - routeEvent(hub: IConnectionHub): Promise> { - return this.route(hub); - } - - private async route(hub: IConnectionHub): Promise> { - for (const connection of hub.connections) { - if (await Promise.resolve(this.fn(connection.ctx))) { - return Promise.resolve(connection); - } - } - - await Event.toPromise(hub.onDidChangeConnections); - return await this.route(hub); - } -} diff --git a/src/vs/base/parts/ipc/test/node/ipc.test.ts b/src/vs/base/parts/ipc/test/node/ipc.test.ts index 5d6bedc2969..14f059f5e08 100644 --- a/src/vs/base/parts/ipc/test/node/ipc.test.ts +++ b/src/vs/base/parts/ipc/test/node/ipc.test.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient } from 'vs/base/parts/ipc/node/ipc'; +import { IChannel, IServerChannel, IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient } from 'vs/base/parts/ipc/common/ipc'; import { Emitter, Event } from 'vs/base/common/event'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 4bc05d5222d..23bbcf74ff2 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -16,7 +16,7 @@ import * as os from 'os'; import { debounce } from 'vs/base/common/decorators'; import * as platform from 'vs/base/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; -import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; +import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IWindowConfiguration, IWindowsService } from 'vs/platform/windows/common/windows'; diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 9419a7f4e5a..6fd824961a9 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -41,14 +41,13 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { DownloadService } from 'vs/platform/download/node/downloadService'; import { IDownloadService } from 'vs/platform/download/common/download'; -import { StaticRouter } from 'vs/base/parts/ipc/node/ipc'; +import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner'; import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner'; import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner'; import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; export interface ISharedProcessConfiguration { readonly machineId: string; diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index d1e457511ea..d61ebadb820 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -31,7 +31,7 @@ import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; -import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/node/ipc'; +import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import product from 'vs/platform/product/node/product'; import pkg from 'vs/platform/product/node/package'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 219f85f6240..8a202409c45 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -8,7 +8,7 @@ import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; import { serve as serveNet } from 'vs/base/parts/ipc/node/ipc.net'; import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IPCServer, StaticRouter } from 'vs/base/parts/ipc/node/ipc'; +import { IPCServer, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import { SimpleKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; import { OS } from 'vs/base/common/platform'; diff --git a/src/vs/platform/ipc/electron-browser/sharedProcessService.ts b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts index 0b4848204e9..229e2be7b8e 100644 --- a/src/vs/platform/ipc/electron-browser/sharedProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts @@ -7,8 +7,7 @@ import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/co import { Client, connect } from 'vs/base/parts/ipc/node/ipc.net'; import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; export const ISharedProcessService = createDecorator('sharedProcessService'); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index d8f845c65ca..205feb144c9 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -18,7 +18,7 @@ import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console'; import { findFreePort, randomPort } from 'vs/base/node/ports'; -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { PersistentProtocol, generateRandomPipeName } from 'vs/base/parts/ipc/node/ipc.net'; import { IBroadcast, IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts index b5252580378..6d1976eb9b2 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts @@ -7,7 +7,7 @@ import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ExtHostCustomersRegistry } from 'vs/workbench/api/common/extHostCustomers'; diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index 137f66c50cf..6885b43a09d 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -9,7 +9,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Counter } from 'vs/base/common/numbers'; import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri'; import { IURITransformer } from 'vs/base/common/uriIpc'; -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { IEnvironment, IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts index d336be5a923..b82f6cf0219 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts @@ -7,7 +7,7 @@ import * as nativeWatchdog from 'native-watchdog'; import * as net from 'net'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Event } from 'vs/base/common/event'; -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { PersistentProtocol, ProtocolConstants } from 'vs/base/parts/ipc/node/ipc.net'; import product from 'vs/platform/product/node/product'; import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; diff --git a/src/vs/workbench/services/extensions/node/rpcProtocol.ts b/src/vs/workbench/services/extensions/node/rpcProtocol.ts index 4215806ff3c..9995e048ec5 100644 --- a/src/vs/workbench/services/extensions/node/rpcProtocol.ts +++ b/src/vs/workbench/services/extensions/node/rpcProtocol.ts @@ -10,7 +10,7 @@ import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IURITransformer, transformIncomingURIs } from 'vs/base/common/uriIpc'; -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { LazyPromise } from 'vs/workbench/services/extensions/node/lazyPromise'; import { IRPCProtocol, ProxyIdentifier, getStringIdentifierForProxy } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { VSBuffer } from 'vs/base/common/buffer'; diff --git a/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts b/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts index 23bdfd4515a..eaf69c7e968 100644 --- a/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts +++ b/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; -import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { VSBuffer } from 'vs/base/common/buffer'; diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts index ca03fc923e8..33d36979e9d 100644 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getNextTickChannel } from 'vs/base/parts/ipc/node/ipc'; +import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; import { toFileChangesEvent, IRawFileChange } from 'vs/workbench/services/files/node/watcher/common'; import { WatcherChannelClient } from 'vs/workbench/services/files/node/watcher/nsfw/watcherIpc'; diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts b/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts index 7e3a3248307..8059d2cde4c 100644 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getNextTickChannel } from 'vs/base/parts/ipc/node/ipc'; +import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; import { toFileChangesEvent, IRawFileChange } from 'vs/workbench/services/files/node/watcher/common'; import { WatcherChannelClient } from 'vs/workbench/services/files/node/watcher/unix/watcherIpc'; diff --git a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts index 2fb8dd4d308..d9d8f3861dd 100644 --- a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/node/ipc.net'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { connectRemoteAgentManagement } from 'vs/platform/remote/node/remoteAgentConnection'; @@ -13,7 +13,6 @@ import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/servic import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { RemoteExtensionEnvironmentChannelClient } from 'vs/workbench/services/remote/node/remoteAgentEnvironmentChannel'; diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index c378fda6f10..4f1dc2ec4af 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -14,7 +14,7 @@ import { Schemas } from 'vs/base/common/network'; import { StopWatch } from 'vs/base/common/stopwatch'; import { URI as uri } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; -import { getNextTickChannel } from 'vs/base/parts/ipc/node/ipc'; +import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client, IIPCOptions } from 'vs/base/parts/ipc/node/ipc.cp'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';