Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/power/vscode-node/powerService.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as vscode from 'vscode';
7
import { ILogService } from '../../../platform/log/common/logService';
8
import { Emitter } from '../../../util/vs/base/common/event';
9
import { Disposable, IDisposable, toDisposable } from '../../../util/vs/base/common/lifecycle';
10
import { IPowerService } from '../common/powerService';
11
12
const RELEASE_DELAY_MS = 2 * 60 * 1000; // 2 minutes
13
14
export class PowerService extends Disposable implements IPowerService {
15
declare readonly _serviceBrand: undefined;
16
17
private _activeCount = 0;
18
private _blocker: (vscode.Disposable & { readonly id: number }) | undefined;
19
private _releaseTimer: ReturnType<typeof setTimeout> | undefined;
20
21
private readonly _onDidSuspend = this._register(new Emitter<void>());
22
readonly onDidSuspend = this._onDidSuspend.event;
23
24
private readonly _onDidResume = this._register(new Emitter<void>());
25
readonly onDidResume = this._onDidResume.event;
26
27
constructor(
28
@ILogService private readonly _logService: ILogService,
29
) {
30
super();
31
32
if (typeof vscode.env.power?.onDidSuspend === 'function') {
33
this._register(vscode.env.power.onDidSuspend(() => this._onDidSuspend.fire()));
34
this._register(vscode.env.power.onDidResume(() => this._onDidResume.fire()));
35
}
36
}
37
38
acquirePowerSaveBlocker(): IDisposable {
39
this._activeCount++;
40
this._logService.debug(`[PowerService] Acquired power save blocker, active count: ${this._activeCount}`);
41
42
// Clear any pending release timer
43
if (this._releaseTimer !== undefined) {
44
clearTimeout(this._releaseTimer);
45
this._releaseTimer = undefined;
46
}
47
48
// Start the blocker if this is the first acquisition
49
if (this._activeCount === 1) {
50
this._startBlocker();
51
}
52
53
let disposed = false;
54
return toDisposable(() => {
55
if (disposed) {
56
return;
57
}
58
disposed = true;
59
this._release();
60
});
61
}
62
63
private async _startBlocker(): Promise<void> {
64
if (this._blocker) {
65
return;
66
}
67
68
try {
69
// Check if the API is available (proposed API, desktop only)
70
if (typeof vscode.env.power?.startPowerSaveBlocker !== 'function') {
71
this._logService.debug('[PowerService] Power save blocker API not available');
72
return;
73
}
74
75
this._blocker = await vscode.env.power.startPowerSaveBlocker('prevent-app-suspension');
76
this._logService.debug(`[PowerService] Started power save blocker, id: ${this._blocker.id}`);
77
} catch (err) {
78
this._logService.warn(`[PowerService] Failed to start power save blocker: ${err}`);
79
}
80
}
81
82
private _release(): void {
83
this._activeCount--;
84
this._logService.debug(`[PowerService] Released power save blocker acquisition, active count: ${this._activeCount}`);
85
86
if (this._activeCount <= 0) {
87
this._activeCount = 0;
88
this._scheduleStopBlocker();
89
}
90
}
91
92
private _scheduleStopBlocker(): void {
93
if (this._releaseTimer !== undefined) {
94
return; // Already scheduled
95
}
96
97
this._logService.debug(`[PowerService] Scheduling power save blocker release in ${RELEASE_DELAY_MS}ms`);
98
this._releaseTimer = setTimeout(() => {
99
this._releaseTimer = undefined;
100
this._stopBlocker();
101
}, RELEASE_DELAY_MS);
102
}
103
104
private _stopBlocker(): void {
105
if (!this._blocker) {
106
return;
107
}
108
109
// Don't stop if new acquisitions came in
110
if (this._activeCount > 0) {
111
return;
112
}
113
114
this._logService.debug(`[PowerService] Stopping power save blocker, id: ${this._blocker.id}`);
115
this._blocker.dispose();
116
this._blocker = undefined;
117
}
118
119
override dispose(): void {
120
if (this._releaseTimer !== undefined) {
121
clearTimeout(this._releaseTimer);
122
this._releaseTimer = undefined;
123
}
124
if (this._blocker) {
125
this._blocker.dispose();
126
this._blocker = undefined;
127
}
128
super.dispose();
129
}
130
}
131
132