mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
protocol links - add more logging (#171053)
* protocol links - add more logging * more logging
This commit is contained in:
parent
2dcfd9dc83
commit
545e47e7cc
|
@ -821,24 +821,32 @@ export class CodeApplication extends Disposable {
|
|||
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
|
||||
const urlService = accessor.get(IURLService);
|
||||
const nativeHostMainService = accessor.get(INativeHostMainService);
|
||||
const logService = this.logService;
|
||||
|
||||
// Signal phase: ready (services set)
|
||||
this.lifecycleMainService.phase = LifecycleMainPhase.Ready;
|
||||
|
||||
// Check for initial URLs to handle from protocol link invocations
|
||||
const protocolLinksFromCommandLine = this.environmentMainService.args['open-url'] ? this.environmentMainService.args._urls || [] : []; // Windows/Linux: protocol handler invokes CLI with --open-url
|
||||
if (protocolLinksFromCommandLine.length) {
|
||||
logService.trace('app#openFirstWindow() protocol links from command line:', protocolLinksFromCommandLine);
|
||||
}
|
||||
|
||||
const protocolLinksFromEvent = ((<any>global).getOpenUrls() || []) as string[]; // macOS: open-url events
|
||||
if (protocolLinksFromEvent.length) {
|
||||
logService.trace(`app#openFirstWindow() protocol links from macOS 'open-url' event:`, protocolLinksFromEvent);
|
||||
}
|
||||
|
||||
const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = [];
|
||||
const pendingProtocolLinksToHandle = [
|
||||
|
||||
// Windows/Linux: protocol handler invokes CLI with --open-url
|
||||
...this.environmentMainService.args['open-url'] ? this.environmentMainService.args._urls || [] : [],
|
||||
|
||||
// macOS: open-url events
|
||||
...((<any>global).getOpenUrls() || []) as string[]
|
||||
|
||||
...protocolLinksFromCommandLine,
|
||||
...protocolLinksFromEvent
|
||||
].map(url => {
|
||||
try {
|
||||
return { uri: URI.parse(url), url };
|
||||
} catch {
|
||||
logService.trace('app#openFirstWindow() protocol link failed to parse:', url);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}).filter((obj): obj is { uri: URI; url: string } => {
|
||||
|
@ -848,6 +856,8 @@ export class CodeApplication extends Disposable {
|
|||
|
||||
// If URI should be blocked, filter it out
|
||||
if (this.shouldBlockURI(obj.uri)) {
|
||||
logService.trace('app#openFirstWindow() protocol link was blocked:', obj.uri.toString(true));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -856,11 +866,15 @@ export class CodeApplication extends Disposable {
|
|||
// previous workspace too.
|
||||
const windowOpenable = this.getWindowOpenableFromProtocolLink(obj.uri);
|
||||
if (windowOpenable) {
|
||||
logService.trace('app#openFirstWindow() protocol link will be handled as window to open:', obj.uri.toString(true), windowOpenable);
|
||||
|
||||
pendingWindowOpenablesFromProtocolLinks.push(windowOpenable);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
logService.trace('app#openFirstWindow() protocol link will be passed to active window for handling:', obj.uri.toString(true));
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -870,11 +884,11 @@ export class CodeApplication extends Disposable {
|
|||
const app = this;
|
||||
const environmentService = this.environmentMainService;
|
||||
const productService = this.productService;
|
||||
const logService = this.logService;
|
||||
urlService.registerHandler({
|
||||
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
||||
logService.trace('app#handleURL: ', uri.toString(true), options);
|
||||
logService.trace('app#handleURL():', uri.toString(true), options);
|
||||
|
||||
// Support 'workspace' URLs (https://github.com/microsoft/vscode/issues/124263)
|
||||
if (uri.scheme === productService.urlProtocol && uri.path === 'workspace') {
|
||||
uri = uri.with({
|
||||
authority: 'file',
|
||||
|
@ -885,6 +899,8 @@ export class CodeApplication extends Disposable {
|
|||
|
||||
// If URI should be blocked, behave as if it's handled
|
||||
if (app.shouldBlockURI(uri)) {
|
||||
logService.trace('app#handleURL() protocol link was blocked:', uri.toString(true));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -893,26 +909,37 @@ export class CodeApplication extends Disposable {
|
|||
// We should handle the URI in a new window if the URL contains `windowId=_blank`
|
||||
const params = new URLSearchParams(uri.query);
|
||||
if (params.get('windowId') === '_blank') {
|
||||
logService.trace(`app#handleURL() found 'windowId=_blank' as parameter, setting shouldOpenInNewWindow=true:`, uri.toString(true));
|
||||
|
||||
params.delete('windowId');
|
||||
uri = uri.with({ query: params.toString() });
|
||||
|
||||
shouldOpenInNewWindow = true;
|
||||
}
|
||||
|
||||
// or if no window is open (macOS only)
|
||||
shouldOpenInNewWindow ||= isMacintosh && windowsMainService.getWindowCount() === 0;
|
||||
else if (isMacintosh && windowsMainService.getWindowCount() === 0) {
|
||||
logService.trace(`app#handleURL() running on macOS with no window open, setting shouldOpenInNewWindow=true:`, uri.toString(true));
|
||||
|
||||
shouldOpenInNewWindow = true;
|
||||
}
|
||||
|
||||
// Pass along whether the application is being opened via a Continue On flow
|
||||
const continueOn = params.get('continueOn');
|
||||
if (continueOn !== null) {
|
||||
environmentService.continueOn = continueOn ?? undefined;
|
||||
logService.trace(`app#handleURL() found 'continueOn' as parameter:`, uri.toString(true));
|
||||
|
||||
params.delete('continueOn');
|
||||
uri = uri.with({ query: params.toString() });
|
||||
|
||||
environmentService.continueOn = continueOn ?? undefined;
|
||||
}
|
||||
|
||||
// Check for URIs to open in window
|
||||
// Check if the protocol link is a window openable to open...
|
||||
const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri);
|
||||
logService.trace('app#handleURL: windowOpenableFromProtocolLink = ', windowOpenableFromProtocolLink);
|
||||
if (windowOpenableFromProtocolLink) {
|
||||
logService.trace('app#handleURL() opening protocol link as window:', windowOpenableFromProtocolLink, uri.toString(true));
|
||||
|
||||
const [window] = await windowsMainService.open({
|
||||
context: OpenContext.API,
|
||||
cli: { ...environmentService.args },
|
||||
|
@ -927,7 +954,10 @@ export class CodeApplication extends Disposable {
|
|||
return true;
|
||||
}
|
||||
|
||||
// ...or if we should open in a new window and then handle it within that window
|
||||
if (shouldOpenInNewWindow) {
|
||||
logService.trace('app#handleURL() opening empty window and passing in protocol link:', uri.toString(true));
|
||||
|
||||
const [window] = await windowsMainService.open({
|
||||
context: OpenContext.API,
|
||||
cli: { ...environmentService.args },
|
||||
|
@ -958,7 +988,7 @@ export class CodeApplication extends Disposable {
|
|||
urlService.registerHandler(new URLHandlerChannelClient(urlHandlerChannel));
|
||||
|
||||
// Watch Electron URLs and forward them to the UrlService
|
||||
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService, this.productService));
|
||||
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService, this.productService, this.logService));
|
||||
|
||||
// Open our first window
|
||||
const args = this.environmentMainService.args;
|
||||
|
|
|
@ -10,18 +10,11 @@ import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecyc
|
|||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
|
||||
function uriFromRawUrl(url: string): URI | null {
|
||||
try {
|
||||
return URI.parse(url);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener for URLs that are opened from the OS and handled by VSCode.
|
||||
* Depending on the platform, this works differently:
|
||||
|
@ -37,15 +30,17 @@ export class ElectronURLListener {
|
|||
private uris: { uri: URI; url: string }[] = [];
|
||||
private retryCount = 0;
|
||||
private flushDisposable: IDisposable = Disposable.None;
|
||||
private disposables = new DisposableStore();
|
||||
private readonly disposables = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
initialUrisToHandle: { uri: URI; url: string }[],
|
||||
private readonly urlService: IURLService,
|
||||
windowsMainService: IWindowsMainService,
|
||||
environmentMainService: IEnvironmentMainService,
|
||||
productService: IProductService
|
||||
productService: IProductService,
|
||||
private readonly logService: ILogService
|
||||
) {
|
||||
logService.trace('ElectronURLListener initialUrisToHandle:', initialUrisToHandle.map(initialUri => initialUri.url));
|
||||
|
||||
// the initial set of URIs we need to handle once the window is ready
|
||||
this.uris = initialUrisToHandle;
|
||||
|
@ -62,12 +57,12 @@ export class ElectronURLListener {
|
|||
Event.fromNodeEventEmitter(app, 'open-url', (event: ElectronEvent, url: string) => ({ event, url })),
|
||||
({ event, url }) => {
|
||||
event.preventDefault(); // always prevent default and return the url as string
|
||||
|
||||
return url;
|
||||
});
|
||||
|
||||
this.disposables.add(onOpenElectronUrl(url => {
|
||||
const uri = uriFromRawUrl(url);
|
||||
|
||||
const uri = this.uriFromRawUrl(url);
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
|
@ -77,27 +72,46 @@ export class ElectronURLListener {
|
|||
|
||||
// Send initial links to the window once it has loaded
|
||||
const isWindowReady = windowsMainService.getWindows()
|
||||
.filter(w => w.isReady)
|
||||
.filter(window => window.isReady)
|
||||
.length > 0;
|
||||
|
||||
if (isWindowReady) {
|
||||
logService.trace('ElectronURLListener: window is ready to handle URLs');
|
||||
|
||||
this.flush();
|
||||
} else {
|
||||
logService.trace('ElectronURLListener: waiting for window to be ready to handle URLs...');
|
||||
|
||||
Event.once(windowsMainService.onDidSignalReadyWindow)(this.flush, this, this.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
private uriFromRawUrl(url: string): URI | undefined {
|
||||
try {
|
||||
return URI.parse(url);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async flush(): Promise<void> {
|
||||
if (this.retryCount++ > 10) {
|
||||
this.logService.trace('ElectronURLListener#flush(): giving up after 10 retries');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logService.trace('ElectronURLListener#flush(): flushing URLs');
|
||||
|
||||
const uris: { uri: URI; url: string }[] = [];
|
||||
|
||||
for (const obj of this.uris) {
|
||||
const handled = await this.urlService.open(obj.uri, { originalUrl: obj.url });
|
||||
if (handled) {
|
||||
this.logService.trace('ElectronURLListener#flush(): URL was handled', obj.url);
|
||||
} else {
|
||||
this.logService.trace('ElectronURLListener#flush(): URL was not yet handled', obj.url);
|
||||
|
||||
if (!handled) {
|
||||
uris.push(obj);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue