chore(vscode): update to 1.54.2
This commit is contained in:
@@ -1023,146 +1023,141 @@ export class StaticRouter<TContext = string> implements IClientRouter<TContext>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#region createChannelReceiver / createChannelSender
|
||||
|
||||
/**
|
||||
* Use both `createChannelReceiver` and `createChannelSender`
|
||||
* for automated process <=> process communication over methods
|
||||
* and events. You do not need to spell out each method on both
|
||||
* sides, a proxy will take care of this.
|
||||
* Use ProxyChannels to automatically wrapping and unwrapping
|
||||
* services to/from IPC channels, instead of manually wrapping
|
||||
* each service method and event.
|
||||
*
|
||||
* Rules:
|
||||
* - if marshalling is enabled, only `URI` and `RegExp` is converted
|
||||
* Restrictions:
|
||||
* - If marshalling is enabled, only `URI` and `RegExp` is converted
|
||||
* automatically for you
|
||||
* - events must follow the naming convention `onUppercase`
|
||||
* - Events must follow the naming convention `onUpperCase`
|
||||
* - `CancellationToken` is currently not supported
|
||||
* - if a context is provided, you can use `AddFirstParameterToFunctions`
|
||||
* - If a context is provided, you can use `AddFirstParameterToFunctions`
|
||||
* utility to signal this in the receiving side type
|
||||
*/
|
||||
export namespace ProxyChannel {
|
||||
|
||||
export interface IBaseChannelOptions {
|
||||
export interface IProxyOptions {
|
||||
|
||||
/**
|
||||
* Disables automatic marshalling of `URI`.
|
||||
* If marshalling is disabled, `UriComponents`
|
||||
* must be used instead.
|
||||
*/
|
||||
disableMarshalling?: boolean;
|
||||
}
|
||||
|
||||
export interface IChannelReceiverOptions extends IBaseChannelOptions { }
|
||||
|
||||
export function createChannelReceiver(service: unknown, options?: IChannelReceiverOptions): IServerChannel {
|
||||
const handler = service as { [key: string]: unknown };
|
||||
const disableMarshalling = options && options.disableMarshalling;
|
||||
|
||||
// Buffer any event that should be supported by
|
||||
// iterating over all property keys and finding them
|
||||
const mapEventNameToEvent = new Map<string, Event<unknown>>();
|
||||
for (const key in handler) {
|
||||
if (propertyIsEvent(key)) {
|
||||
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true));
|
||||
}
|
||||
/**
|
||||
* Disables automatic marshalling of `URI`.
|
||||
* If marshalling is disabled, `UriComponents`
|
||||
* must be used instead.
|
||||
*/
|
||||
disableMarshalling?: boolean;
|
||||
}
|
||||
|
||||
return new class implements IServerChannel {
|
||||
export interface ICreateServiceChannelOptions extends IProxyOptions { }
|
||||
|
||||
listen<T>(_: unknown, event: string): Event<T> {
|
||||
const eventImpl = mapEventNameToEvent.get(event);
|
||||
if (eventImpl) {
|
||||
return eventImpl as Event<T>;
|
||||
export function fromService(service: unknown, options?: ICreateServiceChannelOptions): IServerChannel {
|
||||
const handler = service as { [key: string]: unknown };
|
||||
const disableMarshalling = options && options.disableMarshalling;
|
||||
|
||||
// Buffer any event that should be supported by
|
||||
// iterating over all property keys and finding them
|
||||
const mapEventNameToEvent = new Map<string, Event<unknown>>();
|
||||
for (const key in handler) {
|
||||
if (propertyIsEvent(key)) {
|
||||
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true));
|
||||
}
|
||||
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(_: unknown, command: string, args?: any[]): Promise<any> {
|
||||
const target = handler[command];
|
||||
if (typeof target === 'function') {
|
||||
return new class implements IServerChannel {
|
||||
|
||||
// Revive unless marshalling disabled
|
||||
if (!disableMarshalling && Array.isArray(args)) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = revive(args[i]);
|
||||
}
|
||||
listen<T>(_: unknown, event: string): Event<T> {
|
||||
const eventImpl = mapEventNameToEvent.get(event);
|
||||
if (eventImpl) {
|
||||
return eventImpl as Event<T>;
|
||||
}
|
||||
|
||||
return target.apply(handler, args);
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
throw new Error(`Method not found: ${command}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export interface IChannelSenderOptions extends IBaseChannelOptions {
|
||||
|
||||
/**
|
||||
* If provided, will add the value of `context`
|
||||
* to each method call to the target.
|
||||
*/
|
||||
context?: unknown;
|
||||
|
||||
/**
|
||||
* If provided, will not proxy any of the properties
|
||||
* that are part of the Map but rather return that value.
|
||||
*/
|
||||
properties?: Map<string, unknown>;
|
||||
}
|
||||
|
||||
export function createChannelSender<T>(channel: IChannel, options?: IChannelSenderOptions): T {
|
||||
const disableMarshalling = options && options.disableMarshalling;
|
||||
|
||||
return new Proxy({}, {
|
||||
get(_target: T, propKey: PropertyKey) {
|
||||
if (typeof propKey === 'string') {
|
||||
|
||||
// Check for predefined values
|
||||
if (options?.properties?.has(propKey)) {
|
||||
return options.properties.get(propKey);
|
||||
}
|
||||
|
||||
// Event
|
||||
if (propertyIsEvent(propKey)) {
|
||||
return channel.listen(propKey);
|
||||
}
|
||||
|
||||
// Function
|
||||
return async function (...args: any[]) {
|
||||
|
||||
// Add context if any
|
||||
let methodArgs: any[];
|
||||
if (options && !isUndefinedOrNull(options.context)) {
|
||||
methodArgs = [options.context, ...args];
|
||||
} else {
|
||||
methodArgs = args;
|
||||
}
|
||||
|
||||
const result = await channel.call(propKey, methodArgs);
|
||||
call(_: unknown, command: string, args?: any[]): Promise<any> {
|
||||
const target = handler[command];
|
||||
if (typeof target === 'function') {
|
||||
|
||||
// Revive unless marshalling disabled
|
||||
if (!disableMarshalling) {
|
||||
return revive(result);
|
||||
if (!disableMarshalling && Array.isArray(args)) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = revive(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
return target.apply(handler, args);
|
||||
}
|
||||
|
||||
throw new Error(`Method not found: ${command}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Property not found: ${String(propKey)}`);
|
||||
}
|
||||
}) as T;
|
||||
export interface ICreateProxyServiceOptions extends IProxyOptions {
|
||||
|
||||
/**
|
||||
* If provided, will add the value of `context`
|
||||
* to each method call to the target.
|
||||
*/
|
||||
context?: unknown;
|
||||
|
||||
/**
|
||||
* If provided, will not proxy any of the properties
|
||||
* that are part of the Map but rather return that value.
|
||||
*/
|
||||
properties?: Map<string, unknown>;
|
||||
}
|
||||
|
||||
export function toService<T>(channel: IChannel, options?: ICreateProxyServiceOptions): T {
|
||||
const disableMarshalling = options && options.disableMarshalling;
|
||||
|
||||
return new Proxy({}, {
|
||||
get(_target: T, propKey: PropertyKey) {
|
||||
if (typeof propKey === 'string') {
|
||||
|
||||
// Check for predefined values
|
||||
if (options?.properties?.has(propKey)) {
|
||||
return options.properties.get(propKey);
|
||||
}
|
||||
|
||||
// Event
|
||||
if (propertyIsEvent(propKey)) {
|
||||
return channel.listen(propKey);
|
||||
}
|
||||
|
||||
// Function
|
||||
return async function (...args: any[]) {
|
||||
|
||||
// Add context if any
|
||||
let methodArgs: any[];
|
||||
if (options && !isUndefinedOrNull(options.context)) {
|
||||
methodArgs = [options.context, ...args];
|
||||
} else {
|
||||
methodArgs = args;
|
||||
}
|
||||
|
||||
const result = await channel.call(propKey, methodArgs);
|
||||
|
||||
// Revive unless marshalling disabled
|
||||
if (!disableMarshalling) {
|
||||
return revive(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Property not found: ${String(propKey)}`);
|
||||
}
|
||||
}) as T;
|
||||
}
|
||||
|
||||
function propertyIsEvent(name: string): boolean {
|
||||
// Assume a property is an event if it has a form of "onSomething"
|
||||
return name[0] === 'o' && name[1] === 'n' && strings.isUpperAsciiLetter(name.charCodeAt(2));
|
||||
}
|
||||
}
|
||||
|
||||
function propertyIsEvent(name: string): boolean {
|
||||
// Assume a property is an event if it has a form of "onSomething"
|
||||
return name[0] === 'o' && name[1] === 'n' && strings.isUpperAsciiLetter(name.charCodeAt(2));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
const colorTables = [
|
||||
['#2977B1', '#FC802D', '#34A13A', '#D3282F', '#9366BA'],
|
||||
['#8B564C', '#E177C0', '#7F7F7F', '#BBBE3D', '#2EBECD']
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ClientConnectionEvent, IPCServer } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Protocol as MessagePortProtocol } from 'vs/base/parts/ipc/common/ipc.mp';
|
||||
@@ -39,6 +39,9 @@ export class Server extends IPCServer {
|
||||
};
|
||||
|
||||
// Send one port back to the requestor
|
||||
// Note: we intentionally use `electron` APIs here because
|
||||
// transferables like the `MessagePort` cannot be transfered
|
||||
// over preload scripts when `contextIsolation: true`
|
||||
ipcRenderer.postMessage('vscode:createMessageChannelResult', nonce, [outgoingPort]);
|
||||
|
||||
return result;
|
||||
@@ -71,10 +71,8 @@ export interface IIPCOptions {
|
||||
debugBrk?: number;
|
||||
|
||||
/**
|
||||
* See https://github.com/microsoft/vscode/issues/27665
|
||||
* Allows to pass in fresh execArgv to the forked process such that it doesn't inherit them from `process.execArgv`.
|
||||
* e.g. Launching the extension host process with `--inspect-brk=xxx` and then forking a process from the extension host
|
||||
* results in the forked process inheriting `--inspect-brk=xxx`.
|
||||
* If set, starts the fork with empty execArgv. If not set, execArgv from the parent proces are inherited,
|
||||
* except --inspect= and --inspect-brk= which are filtered as they would result in a port conflict.
|
||||
*/
|
||||
freshExecArgv?: boolean;
|
||||
|
||||
@@ -198,6 +196,12 @@ export class Client implements IChannelClient, IDisposable {
|
||||
forkOpts.execArgv = ['--nolazy', '--inspect-brk=' + this.options.debugBrk];
|
||||
}
|
||||
|
||||
if (forkOpts.execArgv === undefined) {
|
||||
// if not set, the forked process inherits the execArgv of the parent process
|
||||
// --inspect and --inspect-brk can not be inherited as the port would conflict
|
||||
forkOpts.execArgv = process.execArgv.filter(a => !/^--inspect(-brk)?=/.test(a)); // remove
|
||||
}
|
||||
|
||||
if (isMacintosh && forkOpts.env) {
|
||||
// Unset `DYLD_LIBRARY_PATH`, as it leads to process crashes
|
||||
// See https://github.com/microsoft/vscode/issues/105848
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IChannel, IServerChannel, IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient, createChannelReceiver, createChannelSender } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IChannel, IServerChannel, IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient, ProxyChannel } 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';
|
||||
@@ -332,10 +332,10 @@ suite('Base IPC', function () {
|
||||
const testServer = new TestIPCServer();
|
||||
server = testServer;
|
||||
|
||||
server.registerChannel(TestChannelId, createChannelReceiver(service));
|
||||
server.registerChannel(TestChannelId, ProxyChannel.fromService(service));
|
||||
|
||||
client = testServer.createConnection('client1');
|
||||
ipcService = createChannelSender(client.getChannel(TestChannelId));
|
||||
ipcService = ProxyChannel.toService(client.getChannel(TestChannelId));
|
||||
});
|
||||
|
||||
teardown(function () {
|
||||
@@ -398,10 +398,10 @@ suite('Base IPC', function () {
|
||||
const testServer = new TestIPCServer();
|
||||
server = testServer;
|
||||
|
||||
server.registerChannel(TestChannelId, createChannelReceiver(service));
|
||||
server.registerChannel(TestChannelId, ProxyChannel.fromService(service));
|
||||
|
||||
client = testServer.createConnection('client1');
|
||||
ipcService = createChannelSender(client.getChannel(TestChannelId), { context: 'Super Context' });
|
||||
ipcService = ProxyChannel.toService(client.getChannel(TestChannelId), { context: 'Super Context' });
|
||||
});
|
||||
|
||||
teardown(function () {
|
||||
|
||||
@@ -11,7 +11,7 @@ suite('IPC, MessagePorts', () => {
|
||||
test('message port close event', async () => {
|
||||
const { port1, port2 } = new MessageChannel();
|
||||
|
||||
new MessagePortClient(port1, 'client1');
|
||||
const client1 = new MessagePortClient(port1, 'client1');
|
||||
const client2 = new MessagePortClient(port2, 'client2');
|
||||
|
||||
// This test ensures that Electron's API for the close event
|
||||
@@ -24,5 +24,7 @@ suite('IPC, MessagePorts', () => {
|
||||
client2.dispose();
|
||||
|
||||
assert.ok(await whenClosed);
|
||||
|
||||
client1.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ export interface IQuickInputStyles {
|
||||
countBadge: ICountBadgetyles;
|
||||
button: IButtonStyles;
|
||||
progressBar: IProgressBarStyles;
|
||||
list: IListStyles & { listInactiveFocusForeground?: Color; pickerGroupBorder?: Color; pickerGroupForeground?: Color; };
|
||||
list: IListStyles & { pickerGroupBorder?: Color; pickerGroupForeground?: Color; };
|
||||
}
|
||||
|
||||
export interface IQuickInputWidgetStyles {
|
||||
@@ -1706,10 +1706,6 @@ export class QuickInputController extends Disposable {
|
||||
this.ui.list.style(this.styles.list);
|
||||
|
||||
const content: string[] = [];
|
||||
if (this.styles.list.listInactiveFocusForeground) {
|
||||
content.push(`.monaco-list .monaco-list-row.focused { color: ${this.styles.list.listInactiveFocusForeground}; }`);
|
||||
content.push(`.monaco-list .monaco-list-row.focused:hover { color: ${this.styles.list.listInactiveFocusForeground}; }`); // overwrite :hover style in this case!
|
||||
}
|
||||
if (this.styles.list.pickerGroupBorder) {
|
||||
content.push(`.quick-input-list .quick-input-list-entry { border-top-color: ${this.styles.list.pickerGroupBorder}; }`);
|
||||
}
|
||||
|
||||
@@ -35,17 +35,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {any} message
|
||||
* @param {MessagePort[]} transfer
|
||||
*/
|
||||
postMessage(channel, message, transfer) {
|
||||
if (validateIPC(channel)) {
|
||||
ipcRenderer.postMessage(channel, message, transfer);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {any[]} args
|
||||
@@ -88,6 +77,33 @@
|
||||
}
|
||||
},
|
||||
|
||||
ipcMessagePort: {
|
||||
|
||||
/**
|
||||
* @param {string} channelRequest
|
||||
* @param {string} channelResponse
|
||||
* @param {string} requestNonce
|
||||
*/
|
||||
connect(channelRequest, channelResponse, requestNonce) {
|
||||
if (validateIPC(channelRequest) && validateIPC(channelResponse)) {
|
||||
const responseListener = (/** @type {import('electron').IpcRendererEvent} */ e, /** @type {string} */ responseNonce) => {
|
||||
// validate that the nonce from the response is the same
|
||||
// as when requested. and if so, use `postMessage` to
|
||||
// send the `MessagePort` safely over, even when context
|
||||
// isolation is enabled
|
||||
if (requestNonce === responseNonce) {
|
||||
ipcRenderer.off(channelResponse, responseListener);
|
||||
window.postMessage(requestNonce, '*', e.ports);
|
||||
}
|
||||
};
|
||||
|
||||
// request message port from main and await result
|
||||
ipcRenderer.on(channelResponse, responseListener);
|
||||
ipcRenderer.send(channelRequest, requestNonce);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Support for subset of methods of Electron's `webFrame` type.
|
||||
*/
|
||||
|
||||
@@ -15,10 +15,12 @@ export interface IpcRendererEvent extends Event {
|
||||
|
||||
// Docs: https://electronjs.org/docs/api/structures/ipc-renderer-event
|
||||
|
||||
/**
|
||||
* A list of MessagePorts that were transferred with this message
|
||||
*/
|
||||
ports: MessagePort[];
|
||||
// Note: API with `Transferable` intentionally commented out because you
|
||||
// cannot transfer these when `contextIsolation: true`.
|
||||
// /**
|
||||
// * A list of MessagePorts that were transferred with this message
|
||||
// */
|
||||
// ports: MessagePort[];
|
||||
/**
|
||||
* The `IpcRenderer` instance that emitted the event originally
|
||||
*/
|
||||
@@ -93,20 +95,23 @@ export interface IpcRenderer {
|
||||
* If you do not need a response to the message, consider using `ipcRenderer.send`.
|
||||
*/
|
||||
invoke(channel: string, ...args: any[]): Promise<any>;
|
||||
/**
|
||||
* Send a message to the main process, optionally transferring ownership of zero or
|
||||
* more `MessagePort` objects.
|
||||
*
|
||||
* The transferred `MessagePort` objects will be available in the main process as
|
||||
* `MessagePortMain` objects by accessing the `ports` property of the emitted
|
||||
* event.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* For more information on using `MessagePort` and `MessageChannel`, see the MDN
|
||||
* documentation.
|
||||
*/
|
||||
postMessage(channel: string, message: any, transfer?: MessagePort[]): void;
|
||||
|
||||
// Note: API with `Transferable` intentionally commented out because you
|
||||
// cannot transfer these when `contextIsolation: true`.
|
||||
// /**
|
||||
// * Send a message to the main process, optionally transferring ownership of zero or
|
||||
// * more `MessagePort` objects.
|
||||
// *
|
||||
// * The transferred `MessagePort` objects will be available in the main process as
|
||||
// * `MessagePortMain` objects by accessing the `ports` property of the emitted
|
||||
// * event.
|
||||
// *
|
||||
// * For example:
|
||||
// *
|
||||
// * For more information on using `MessagePort` and `MessageChannel`, see the MDN
|
||||
// * documentation.
|
||||
// */
|
||||
// postMessage(channel: string, message: any): void;
|
||||
}
|
||||
|
||||
export interface WebFrame {
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { globals, INodeProcess, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { globals, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ProcessMemoryInfo, CrashReporter, IpcRenderer, WebFrame } from 'vs/base/parts/sandbox/electron-sandbox/electronTypes';
|
||||
|
||||
export interface ISandboxNodeProcess extends INodeProcess {
|
||||
/**
|
||||
* In sandboxed renderers we cannot expose all of the `process` global of node.js
|
||||
*/
|
||||
export interface IPartialNodeProcess {
|
||||
|
||||
/**
|
||||
* The process.platform property returns a string identifying the operating system platform
|
||||
@@ -40,24 +43,6 @@ export interface ISandboxNodeProcess extends INodeProcess {
|
||||
*/
|
||||
readonly execPath: string;
|
||||
|
||||
/**
|
||||
* Resolve the true process environment to use and apply it to `process.env`.
|
||||
*
|
||||
* There are different layers of environment that will apply:
|
||||
* - `process.env`: this is the actual environment of the process before this method
|
||||
* - `shellEnv` : if the program was not started from a terminal, we resolve all shell
|
||||
* variables to get the same experience as if the program was started from
|
||||
* a terminal (Linux, macOS)
|
||||
* - `userEnv` : this is instance specific environment, e.g. if the user started the program
|
||||
* from a terminal and changed certain variables
|
||||
*
|
||||
* The order of overwrites is `process.env` < `shellEnv` < `userEnv`.
|
||||
*
|
||||
* It is critical that every process awaits this method early on startup to get the right
|
||||
* set of environment in `process.env`.
|
||||
*/
|
||||
resolveEnv(userEnv: IProcessEnvironment): Promise<void>;
|
||||
|
||||
/**
|
||||
* A listener on the process. Only a small subset of listener types are allowed.
|
||||
*/
|
||||
@@ -79,6 +64,28 @@ export interface ISandboxNodeProcess extends INodeProcess {
|
||||
getProcessMemoryInfo: () => Promise<ProcessMemoryInfo>;
|
||||
}
|
||||
|
||||
export interface ISandboxNodeProcess extends IPartialNodeProcess {
|
||||
|
||||
/**
|
||||
* A custom method we add to `process`: Resolve the true process environment to use and
|
||||
* apply it to `process.env`.
|
||||
*
|
||||
* There are different layers of environment that will apply:
|
||||
* - `process.env`: this is the actual environment of the process before this method
|
||||
* - `shellEnv` : if the program was not started from a terminal, we resolve all shell
|
||||
* variables to get the same experience as if the program was started from
|
||||
* a terminal (Linux, macOS)
|
||||
* - `userEnv` : this is instance specific environment, e.g. if the user started the program
|
||||
* from a terminal and changed certain variables
|
||||
*
|
||||
* The order of overwrites is `process.env` < `shellEnv` < `userEnv`.
|
||||
*
|
||||
* It is critical that every process awaits this method early on startup to get the right
|
||||
* set of environment in `process.env`.
|
||||
*/
|
||||
resolveEnv(userEnv: IProcessEnvironment): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ISandboxContext {
|
||||
|
||||
/**
|
||||
@@ -87,7 +94,23 @@ export interface ISandboxContext {
|
||||
sandbox: boolean;
|
||||
}
|
||||
|
||||
export interface IpcMessagePort {
|
||||
|
||||
/**
|
||||
* Establish a connection via `MessagePort` to a target. The main process
|
||||
* will need to transfer the port over to the `channelResponse` after listening
|
||||
* to `channelRequest` with a payload of `requestNonce` so that the
|
||||
* source can correlate the response.
|
||||
*
|
||||
* The source should install a `window.on('message')` listener, ensuring `e.data`
|
||||
* matches `requestNonce`, `e.source` matches `window` and then receiving the
|
||||
* `MessagePort` via `e.ports[0]`.
|
||||
*/
|
||||
connect(channelRequest: string, channelResponse: string, requestNonce: string): void;
|
||||
}
|
||||
|
||||
export const ipcRenderer: IpcRenderer = globals.vscode.ipcRenderer;
|
||||
export const ipcMessagePort: IpcMessagePort = globals.vscode.ipcMessagePort;
|
||||
export const webFrame: WebFrame = globals.vscode.webFrame;
|
||||
export const crashReporter: CrashReporter = globals.vscode.crashReporter;
|
||||
export const process: ISandboxNodeProcess = globals.vscode.process;
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ipcRenderer, crashReporter, webFrame } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { ipcRenderer, crashReporter, webFrame, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
|
||||
suite('Sandbox', () => {
|
||||
test('globals', () => {
|
||||
assert.ok(ipcRenderer);
|
||||
assert.ok(crashReporter);
|
||||
assert.ok(webFrame);
|
||||
assert.ok(typeof ipcRenderer.invoke === 'function');
|
||||
assert.ok(typeof crashReporter.addExtraParameter === 'function');
|
||||
assert.ok(typeof webFrame.setZoomLevel === 'function');
|
||||
assert.ok(typeof process.platform === 'string');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,11 +84,13 @@ export class Storage extends Disposable implements IStorage {
|
||||
|
||||
private cache = new Map<string, string>();
|
||||
|
||||
private readonly flushDelayer = this._register(new ThrottledDelayer<void>(Storage.DEFAULT_FLUSH_DELAY));
|
||||
private readonly flushDelayer = new ThrottledDelayer<void>(Storage.DEFAULT_FLUSH_DELAY);
|
||||
|
||||
private pendingDeletes = new Set<string>();
|
||||
private pendingInserts = new Map<string, string>();
|
||||
|
||||
private pendingClose: Promise<void> | undefined = undefined;
|
||||
|
||||
private readonly whenFlushedCallbacks: Function[] = [];
|
||||
|
||||
constructor(
|
||||
@@ -256,10 +258,15 @@ export class Storage extends Disposable implements IStorage {
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
if (this.state === StorageState.Closed) {
|
||||
return; // return if already closed
|
||||
if (!this.pendingClose) {
|
||||
this.pendingClose = this.doClose();
|
||||
}
|
||||
|
||||
return this.pendingClose;
|
||||
}
|
||||
|
||||
private async doClose(): Promise<void> {
|
||||
|
||||
// Update state
|
||||
this.state = StorageState.Closed;
|
||||
|
||||
@@ -312,6 +319,13 @@ export class Storage extends Disposable implements IStorage {
|
||||
|
||||
return new Promise(resolve => this.whenFlushedCallbacks.push(resolve));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.flushDelayer.cancel(); // workaround https://github.com/microsoft/vscode/issues/116777
|
||||
this.flushDelayer.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class InMemoryStorageDatabase implements IStorageDatabase {
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type { Database, Statement } from 'vscode-sqlite3';
|
||||
import { promises } from 'fs';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { mapToString, setToString } from 'vs/base/common/map';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { copy, renameIgnoreError, unlink } from 'vs/base/node/pfs';
|
||||
import { copy } from 'vs/base/node/pfs';
|
||||
import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage';
|
||||
|
||||
interface IDatabaseConnection {
|
||||
@@ -186,7 +187,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
|
||||
// Delete the existing DB. If the path does not exist or fails to
|
||||
// be deleted, we do not try to recover anymore because we assume
|
||||
// that the path is no longer writeable for us.
|
||||
return unlink(this.path).then(() => {
|
||||
return promises.unlink(this.path).then(() => {
|
||||
|
||||
// Re-open the DB fresh
|
||||
return this.doConnect(this.path).then(recoveryConnection => {
|
||||
@@ -216,7 +217,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
|
||||
private backup(): Promise<void> {
|
||||
const backupPath = this.toBackupPath(this.path);
|
||||
|
||||
return copy(this.path, backupPath);
|
||||
return copy(this.path, backupPath, { preserveSymlinks: false });
|
||||
}
|
||||
|
||||
private toBackupPath(path: string): string {
|
||||
@@ -272,8 +273,12 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
|
||||
// folder is really not writeable for us.
|
||||
//
|
||||
try {
|
||||
await unlink(path);
|
||||
await renameIgnoreError(this.toBackupPath(path), path);
|
||||
await promises.unlink(path);
|
||||
try {
|
||||
await promises.rename(this.toBackupPath(path), path);
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return await this.doConnect(path);
|
||||
} catch (error) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user