UNPKG

@sussudio/platform

Version:

Internal APIs for VS Code's service injection the base services.

195 lines (194 loc) 7.09 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc, d; if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); }; }; import { spawn } from 'child_process'; import { realpath, watch } from 'fs'; import { timeout } from '@sussudio/base/common/async.mjs'; import { Emitter, Event } from '@sussudio/base/common/event.mjs'; import * as path from '@sussudio/base/common/path.mjs'; import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.mjs'; import { ILifecycleMainService } from '../../lifecycle/electron-main/lifecycleMainService.mjs'; import { ILogService } from '../../log/common/log.mjs'; import { ITelemetryService } from '../../telemetry/common/telemetry.mjs'; import { State } from '../common/update.mjs'; let AbstractUpdateService = class AbstractUpdateService { lifecycleMainService; logService; _state = State.Uninitialized; _onStateChange = new Emitter(); onStateChange = this._onStateChange.event; get state() { return this._state; } setState(state) { this.logService.info('update#setState', state.type); this._state = state; this._onStateChange.fire(state); } constructor(lifecycleMainService, environmentMainService, logService) { this.lifecycleMainService = lifecycleMainService; this.logService = logService; if (environmentMainService.disableUpdates) { this.logService.info('update#ctor - updates are disabled'); return; } this.setState(State.Idle(this.getUpdateType())); // Start checking for updates after 30 seconds this.scheduleCheckForUpdates(30 * 1000).then(undefined, (err) => this.logService.error(err)); } scheduleCheckForUpdates(delay = 60 * 60 * 1000) { return timeout(delay) .then(() => this.checkForUpdates(false)) .then(() => { // Check again after 1 hour return this.scheduleCheckForUpdates(60 * 60 * 1000); }); } async checkForUpdates(explicit) { this.logService.trace('update#checkForUpdates, state = ', this.state.type); if (this.state.type !== 'idle' /* StateType.Idle */) { return; } this.doCheckForUpdates(explicit); } async downloadUpdate() { this.logService.trace('update#downloadUpdate, state = ', this.state.type); if (this.state.type !== 'available for download' /* StateType.AvailableForDownload */) { return; } await this.doDownloadUpdate(this.state); } doDownloadUpdate(state) { return Promise.resolve(undefined); } async applyUpdate() { this.logService.trace('update#applyUpdate, state = ', this.state.type); if (this.state.type !== 'downloaded' /* StateType.Downloaded */) { return; } await this.doApplyUpdate(); } doApplyUpdate() { return Promise.resolve(undefined); } quitAndInstall() { this.logService.trace('update#quitAndInstall, state = ', this.state.type); if (this.state.type !== 'ready' /* StateType.Ready */) { return Promise.resolve(undefined); } this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); this.lifecycleMainService.quit(true /* will restart */).then((vetod) => { this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); if (vetod) { return; } this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()'); this.doQuitAndInstall(); }); return Promise.resolve(undefined); } getUpdateType() { return 2 /* UpdateType.Snap */; } doQuitAndInstall() { // noop } async _applySpecificUpdate(packagePath) { // noop } }; AbstractUpdateService = __decorate( [__param(0, ILifecycleMainService), __param(1, IEnvironmentMainService), __param(2, ILogService)], AbstractUpdateService, ); let SnapUpdateService = class SnapUpdateService extends AbstractUpdateService { snap; snapRevision; telemetryService; constructor(snap, snapRevision, lifecycleMainService, environmentMainService, logService, telemetryService) { super(lifecycleMainService, environmentMainService, logService); this.snap = snap; this.snapRevision = snapRevision; this.telemetryService = telemetryService; const watcher = watch(path.dirname(this.snap)); const onChange = Event.fromNodeEventEmitter(watcher, 'change', (_, fileName) => fileName); const onCurrentChange = Event.filter(onChange, (n) => n === 'current'); const onDebouncedCurrentChange = Event.debounce(onCurrentChange, (_, e) => e, 2000); const listener = onDebouncedCurrentChange(() => this.checkForUpdates(false)); lifecycleMainService.onWillShutdown(() => { listener.dispose(); watcher.close(); }); } doCheckForUpdates() { this.setState(State.CheckingForUpdates(false)); this.isUpdateAvailable().then( (result) => { if (result) { this.setState(State.Ready({ version: 'something', productVersion: 'something' })); } else { this.telemetryService.publicLog2('update:notAvailable', { explicit: false }); this.setState(State.Idle(2 /* UpdateType.Snap */)); } }, (err) => { this.logService.error(err); this.telemetryService.publicLog2('update:notAvailable', { explicit: false }); this.setState(State.Idle(2 /* UpdateType.Snap */, err.message || err)); }, ); } doQuitAndInstall() { this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()'); // Allow 3 seconds for VS Code to close spawn('sleep 3 && ' + path.basename(process.argv[0]), { shell: true, detached: true, stdio: 'ignore', }); } async isUpdateAvailable() { const resolvedCurrentSnapPath = await new Promise((c, e) => realpath(`${path.dirname(this.snap)}/current`, (err, r) => (err ? e(err) : c(r))), ); const currentRevision = path.basename(resolvedCurrentSnapPath); return this.snapRevision !== currentRevision; } isLatestVersion() { return this.isUpdateAvailable().then(undefined, (err) => { this.logService.error('update#checkForSnapUpdate(): Could not get realpath of application.'); return undefined; }); } }; SnapUpdateService = __decorate( [ __param(2, ILifecycleMainService), __param(3, IEnvironmentMainService), __param(4, ILogService), __param(5, ITelemetryService), ], SnapUpdateService, ); export { SnapUpdateService };