web - best lifecycle support we can do currently

This commit is contained in:
Benjamin Pasero 2019-06-18 15:12:41 +02:00
parent 4118892ac5
commit 998a65e2ca
10 changed files with 91 additions and 67 deletions

View file

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { localize } from 'vs/nls';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export class BrowserLifecycleService extends AbstractLifecycleService {
_serviceBrand: ServiceIdentifier<ILifecycleService>;
constructor(
@ILogService readonly logService: ILogService
) {
super(logService);
this.registerListeners();
}
private registerListeners(): void {
window.onbeforeunload = () => this.beforeUnload();
}
private beforeUnload(): string | null {
let veto: boolean = false;
// Before Shutdown
this._onBeforeShutdown.fire({
veto(value) {
if (value === true) {
veto = true;
} else if (value instanceof Promise && !veto) {
console.warn(new Error('Long running onBeforeShutdown currently not supported'));
}
},
reason: ShutdownReason.QUIT
});
// Veto: signal back to browser by returning a non-falsify return value
if (veto) {
return localize('lifecycleVeto', "Changes that you made may not be saved. Please check press 'Cancel' and try again.");
}
// No Veto: continue with Will Shutdown
this._onWillShutdown.fire({
join() {
console.warn(new Error('Long running onWillShutdown currently not supported'));
},
reason: ShutdownReason.QUIT
});
return null;
}
}

View file

@ -9,10 +9,11 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { ILifecycleService, BeforeShutdownEvent, WillShutdownEvent, StartupKind, LifecyclePhase, LifecyclePhaseToString } from 'vs/platform/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { mark } from 'vs/base/common/performance';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export abstract class AbstractLifecycleService extends Disposable implements ILifecycleService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
protected readonly _onBeforeShutdown = this._register(new Emitter<BeforeShutdownEvent>());
get onBeforeShutdown(): Event<BeforeShutdownEvent> { return this._onBeforeShutdown.event; }

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
import { ShutdownReason, StartupKind, handleVetos, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ipcRenderer as ipc } from 'electron';
import { IWindowService } from 'vs/platform/windows/common/windows';
@ -12,12 +12,13 @@ import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { onUnexpectedError } from 'vs/base/common/errors';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export class LifecycleService extends AbstractLifecycleService {
private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason';
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
private shutdownReason: ShutdownReason;

View file

@ -131,7 +131,7 @@ export const enum LifecycleMainPhase {
export class LifecycleService extends Disposable implements ILifecycleService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted

View file

@ -75,7 +75,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
}));
this._register(lifecycleService.onBeforeShutdown(e => {
e.veto(this._onBeforeShutdown());
this._onBeforeShutdown();
e.veto(false); // Don't veto shutdown
}, this));
}
@ -217,13 +218,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
return `mainThreadWebview-${viewType}`;
}
private _onBeforeShutdown(): boolean {
private _onBeforeShutdown(): void {
this._webviews.forEach((webview) => {
if (!webview.isDisposed() && webview.state && this._revivers.has(webview.state.viewType)) {
webview.state.state = webview.webviewState;
}
});
return false; // Don't veto shutdown
}
private createWebviewEventDelegate(handle: WebviewPanelHandle) {

View file

@ -21,9 +21,8 @@ import { IPager } from 'vs/base/common/paging';
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { ILogService, LogLevel, ConsoleLogService } from 'vs/platform/log/common/log';
import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { LogLevel, ConsoleLogService } from 'vs/platform/log/common/log';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IProductService } from 'vs/platform/product/common/product';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { IStorageService, IWorkspaceStorageChangeEvent, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage';
@ -518,55 +517,6 @@ registerSingleton(IExtensionUrlHandler, SimpleExtensionURLHandler, true);
//#endregion
//#region Lifecycle
export class SimpleLifecycleService extends AbstractLifecycleService {
_serviceBrand: any;
constructor(
@ILogService readonly logService: ILogService
) {
super(logService);
this.registerListeners();
}
private registerListeners(): void {
window.onbeforeunload = () => this.beforeUnload();
}
private beforeUnload(): string {
// Before Shutdown
this._onBeforeShutdown.fire({
veto(value) {
if (value === true) {
console.warn(new Error('Preventing onBeforeUnload currently not supported'));
} else if (value instanceof Promise) {
console.warn(new Error('Long running onBeforeShutdown currently not supported'));
}
},
reason: ShutdownReason.QUIT
});
// Will Shutdown
this._onWillShutdown.fire({
join() {
console.warn(new Error('Long running onWillShutdown currently not supported'));
},
reason: ShutdownReason.QUIT
});
// @ts-ignore
return null;
}
}
registerSingleton(ILifecycleService, SimpleLifecycleService);
//#endregion
//#region Log
export class SimpleLogService extends ConsoleLogService { }

View file

@ -6,6 +6,7 @@
import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService';
import { ITextFileService, IResourceEncodings, IResourceEncoding } from 'vs/workbench/services/textfile/common/textfiles';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
export class BrowserTextFileService extends TextFileService {
@ -14,6 +15,19 @@ export class BrowserTextFileService extends TextFileService {
return { encoding: 'utf8', hasBOM: false };
}
};
protected beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
const veto = super.beforeShutdown(reason);
// Web: there is no support for long running unload handlers. As such
// we need to return a direct boolean veto when we detect that there
// are dirty files around.
if (veto instanceof Promise) {
return this.getDirty().length > 0;
}
return veto;
}
}
registerSingleton(ITextFileService, BrowserTextFileService);

View file

@ -119,7 +119,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer
}));
}
private beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
protected beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
// Dirty files need treatment on shutdown
const dirty = this.getDirty();

View file

@ -57,14 +57,16 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
@ILifecycleService readonly lifecycleService: ILifecycleService,
@ILabelService readonly labelService: ILabelService
) {
this.registerListeners();
}
lifecycleService.onBeforeShutdown(async e => {
private registerListeners(): void {
this.lifecycleService.onBeforeShutdown(async e => {
const saveOperation = this.saveUntitedBeforeShutdown(e.reason);
if (saveOperation) {
e.veto(saveOperation);
}
});
}
private async saveUntitedBeforeShutdown(reason: ShutdownReason): Promise<boolean> {

View file

@ -68,8 +68,8 @@ import { ContextViewService } from 'vs/platform/contextview/browser/contextViewS
// import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
// import { IRequestService } from 'vs/platform/request/node/request';
// import { RequestService } from 'vs/platform/request/electron-browser/requestService';
// import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
// import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
// import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
// import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService';
// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
@ -152,7 +152,7 @@ registerSingleton(IAccessibilityService, BrowserAccessibilityService, true);
registerSingleton(IContextViewService, ContextViewService, true);
// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true);
// registerSingleton(IRequestService, RequestService, true);
// registerSingleton(ILifecycleService, LifecycleService);
registerSingleton(ILifecycleService, BrowserLifecycleService);
// registerSingleton(ILocalizationsService, LocalizationsService);
// registerSingleton(ISharedProcessService, SharedProcessService, true);
// registerSingleton(IProductService, ProductService, true);
@ -238,7 +238,6 @@ import 'vs/workbench/contrib/debug/browser/repl';
import 'vs/workbench/contrib/debug/browser/debugViewlet';
import 'vs/workbench/contrib/debug/browser/debugHelperService';
// Markers
import 'vs/workbench/contrib/markers/browser/markers.contribution';
@ -288,7 +287,6 @@ import { TaskService } from 'vs/workbench/contrib/tasks/browser/taskService';
import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService';
registerSingleton(ITaskService, TaskService, true);
// Remote
import 'vs/workbench/contrib/remote/common/remote.contribution';
// import 'vs/workbench/contrib/remote/electron-browser/remote.contribution';