mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 1b314ab317fbff7d799b21754326b7d849889ceb
This commit is contained in:
@@ -9,7 +9,6 @@ import { isUNC } from 'vs/base/common/extpath';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { sep } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { getWebviewContentMimeType } from 'vs/platform/webview/common/mimeTypes';
|
||||
@@ -35,6 +34,10 @@ export namespace WebviewResourceResponse {
|
||||
export type StreamResponse = StreamSuccess | typeof Failed | typeof AccessDenied;
|
||||
}
|
||||
|
||||
interface FileReader {
|
||||
readFileStream(resource: URI): Promise<VSBufferReadableStream>;
|
||||
}
|
||||
|
||||
export async function loadLocalResource(
|
||||
requestUri: URI,
|
||||
options: {
|
||||
@@ -43,7 +46,7 @@ export async function loadLocalResource(
|
||||
remoteConnectionData?: IRemoteConnectionData | null;
|
||||
rewriteUri?: (uri: URI) => URI,
|
||||
},
|
||||
fileService: IFileService,
|
||||
fileReader: FileReader,
|
||||
requestService: IRequestService,
|
||||
): Promise<WebviewResourceResponse.StreamResponse> {
|
||||
let resourceToLoad = getResourceToLoad(requestUri, options.roots);
|
||||
@@ -67,8 +70,8 @@ export async function loadLocalResource(
|
||||
}
|
||||
|
||||
try {
|
||||
const contents = await fileService.readFileStream(resourceToLoad);
|
||||
return new WebviewResourceResponse.StreamSuccess(contents.value, mime);
|
||||
const contents = await fileReader.readFileStream(resourceToLoad);
|
||||
return new WebviewResourceResponse.StreamSuccess(contents, mime);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return WebviewResourceResponse.Failed;
|
||||
@@ -96,8 +99,14 @@ function normalizeRequestPath(requestUri: URI) {
|
||||
//
|
||||
// vscode-webview-resource://id/scheme//authority?/path
|
||||
//
|
||||
const resourceUri = URI.parse(requestUri.path.replace(/^\/([a-z0-9\-]+)\/{1,2}/i, '$1://'));
|
||||
|
||||
const resourceUri = URI.parse(requestUri.path.replace(/^\/([a-z0-9\-]+)(\/{1,2})/i, (_: string, scheme: string, sep: string) => {
|
||||
if (sep.length === 1) {
|
||||
return `${scheme}:///`; // Add empty authority.
|
||||
} else {
|
||||
return `${scheme}://`; // Url has own authority.
|
||||
}
|
||||
}));
|
||||
console.log(requestUri, resourceUri);
|
||||
return resourceUri.with({
|
||||
query: requestUri.query,
|
||||
fragment: requestUri.fragment
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { UriComponents } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
@@ -13,10 +14,12 @@ export const IWebviewManagerService = createDecorator<IWebviewManagerService>('w
|
||||
export interface IWebviewManagerService {
|
||||
_serviceBrand: unknown;
|
||||
|
||||
registerWebview(id: string, webContentsId: number | undefined, metadata: RegisterWebviewMetadata): Promise<void>;
|
||||
registerWebview(id: string, webContentsId: number | undefined, windowId: number, metadata: RegisterWebviewMetadata): Promise<void>;
|
||||
unregisterWebview(id: string): Promise<void>;
|
||||
updateWebviewMetadata(id: string, metadataDelta: Partial<RegisterWebviewMetadata>): Promise<void>;
|
||||
|
||||
didLoadResource(requestId: number, content: VSBuffer | undefined): void;
|
||||
|
||||
setIgnoreMenuShortcuts(webContentsId: number, enabled: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { webContents } from 'electron';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
@@ -12,6 +13,7 @@ import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { IWebviewManagerService, RegisterWebviewMetadata } from 'vs/platform/webview/common/webviewManagerService';
|
||||
import { WebviewPortMappingProvider } from 'vs/platform/webview/electron-main/webviewPortMappingProvider';
|
||||
import { WebviewProtocolProvider } from 'vs/platform/webview/electron-main/webviewProtocolProvider';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
|
||||
export class WebviewMainService extends Disposable implements IWebviewManagerService {
|
||||
|
||||
@@ -24,17 +26,19 @@ export class WebviewMainService extends Disposable implements IWebviewManagerSer
|
||||
@IFileService fileService: IFileService,
|
||||
@IRequestService requestService: IRequestService,
|
||||
@ITunnelService tunnelService: ITunnelService,
|
||||
@IWindowsMainService windowsMainService: IWindowsMainService,
|
||||
) {
|
||||
super();
|
||||
this.protocolProvider = this._register(new WebviewProtocolProvider(fileService, requestService));
|
||||
this.protocolProvider = this._register(new WebviewProtocolProvider(fileService, requestService, windowsMainService));
|
||||
this.portMappingProvider = this._register(new WebviewPortMappingProvider(tunnelService));
|
||||
}
|
||||
|
||||
public async registerWebview(id: string, webContentsId: number | undefined, metadata: RegisterWebviewMetadata): Promise<void> {
|
||||
public async registerWebview(id: string, webContentsId: number | undefined, windowId: number, metadata: RegisterWebviewMetadata): Promise<void> {
|
||||
const extensionLocation = metadata.extensionLocation ? URI.from(metadata.extensionLocation) : undefined;
|
||||
|
||||
this.protocolProvider.registerWebview(id, {
|
||||
...metadata,
|
||||
windowId: windowId,
|
||||
extensionLocation,
|
||||
localResourceRoots: metadata.localResourceRoots.map(x => URI.from(x))
|
||||
});
|
||||
@@ -75,4 +79,8 @@ export class WebviewMainService extends Disposable implements IWebviewManagerSer
|
||||
contents.setIgnoreMenuShortcuts(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
public async didLoadResource(requestId: number, content: VSBuffer | undefined): Promise<void> {
|
||||
this.protocolProvider.didLoadResource(requestId, content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,21 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { session, protocol } from 'electron';
|
||||
import { protocol, session } from 'electron';
|
||||
import { Readable } from 'stream';
|
||||
import { VSBufferReadableStream } from 'vs/base/common/buffer';
|
||||
import { bufferToStream, VSBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
|
||||
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { loadLocalResource, webviewPartitionId, WebviewResourceResponse } from 'vs/platform/webview/common/resourceLoader';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
|
||||
interface WebviewMetadata {
|
||||
readonly windowId: number;
|
||||
readonly extensionLocation: URI | undefined;
|
||||
readonly localResourceRoots: readonly URI[];
|
||||
readonly remoteConnectionData: IRemoteConnectionData | null;
|
||||
@@ -32,9 +34,13 @@ export class WebviewProtocolProvider extends Disposable {
|
||||
|
||||
private readonly webviewMetadata = new Map<string, WebviewMetadata>();
|
||||
|
||||
private requestIdPool = 1;
|
||||
private readonly pendingResourceReads = new Map<number, { resolve: (content: VSBuffer | undefined) => void }>();
|
||||
|
||||
constructor(
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@IWindowsMainService readonly windowsMainService: IWindowsMainService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -156,8 +162,7 @@ export class WebviewProtocolProvider extends Disposable {
|
||||
rewriteUri = (uri) => {
|
||||
if (metadata.remoteConnectionData) {
|
||||
if (uri.scheme === Schemas.vscodeRemote || (metadata.extensionLocation?.scheme === REMOTE_HOST_SCHEME)) {
|
||||
const scheme = metadata.remoteConnectionData.host === 'localhost' || metadata.remoteConnectionData.host === '127.0.0.1' ? 'http' : 'https';
|
||||
return URI.parse(`${scheme}://${metadata.remoteConnectionData.host}:${metadata.remoteConnectionData.port}`).with({
|
||||
return URI.parse(`http://${metadata.remoteConnectionData.host}:${metadata.remoteConnectionData.port}`).with({
|
||||
path: '/vscode-remote-resource',
|
||||
query: `tkn=${metadata.remoteConnectionData.connectionToken}&path=${encodeURIComponent(uri.path)}`,
|
||||
});
|
||||
@@ -167,12 +172,42 @@ export class WebviewProtocolProvider extends Disposable {
|
||||
};
|
||||
}
|
||||
|
||||
const fileService = {
|
||||
readFileStream: async (resource: URI): Promise<VSBufferReadableStream> => {
|
||||
if (uri.scheme === Schemas.file) {
|
||||
return (await this.fileService.readFileStream(resource)).value;
|
||||
}
|
||||
|
||||
// Unknown uri scheme. Try delegating the file read back to the renderer
|
||||
// process which should have a file system provider registered for the uri.
|
||||
|
||||
const window = this.windowsMainService.getWindowById(metadata.windowId);
|
||||
if (!window) {
|
||||
throw new FileOperationError('Could not find window for resource', FileOperationResult.FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
const requestId = this.requestIdPool++;
|
||||
const p = new Promise<VSBuffer | undefined>(resolve => {
|
||||
this.pendingResourceReads.set(requestId, { resolve });
|
||||
});
|
||||
|
||||
window.send(`vscode:loadWebviewResource-${id}`, requestId, uri);
|
||||
|
||||
const result = await p;
|
||||
if (!result) {
|
||||
throw new FileOperationError('Could not read file', FileOperationResult.FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
return bufferToStream(result);
|
||||
}
|
||||
};
|
||||
|
||||
const result = await loadLocalResource(uri, {
|
||||
extensionLocation: metadata.extensionLocation,
|
||||
roots: metadata.localResourceRoots,
|
||||
remoteConnectionData: metadata.remoteConnectionData,
|
||||
rewriteUri,
|
||||
}, this.fileService, this.requestService);
|
||||
}, fileService, this.requestService);
|
||||
|
||||
if (result.type === WebviewResourceResponse.Type.Success) {
|
||||
return callback({
|
||||
@@ -196,4 +231,13 @@ export class WebviewProtocolProvider extends Disposable {
|
||||
|
||||
return callback({ data: null, statusCode: 404 });
|
||||
}
|
||||
|
||||
public didLoadResource(requestId: number, content: VSBuffer | undefined) {
|
||||
const pendingRead = this.pendingResourceReads.get(requestId);
|
||||
if (!pendingRead) {
|
||||
throw new Error('Unknown request');
|
||||
}
|
||||
this.pendingResourceReads.delete(requestId);
|
||||
pendingRead.resolve(content);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user