mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 10:52:40 +08:00
feat(core): bettery save mode (#12996)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced a battery save mode that can pause background sync and processing to conserve energy. * Battery save mode is automatically enabled when the app window loses focus and disabled when the window regains focus or is interacted with. * Available in both web and desktop (Electron) versions. * **Improvements** * Added user activity detection to optimize background operations for better battery efficiency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -159,6 +159,14 @@ export class IndexerSyncImpl implements IndexerSync {
|
||||
this.remote = Object.values(this.peers.remotes).find(remote => !!remote);
|
||||
}
|
||||
|
||||
enableBatterySaveMode() {
|
||||
this.status.enableBatterySaveMode();
|
||||
}
|
||||
|
||||
disableBatterySaveMode() {
|
||||
this.status.disableBatterySaveMode();
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.abort) {
|
||||
this.abort.abort(MANUALLY_STOP);
|
||||
@@ -611,6 +619,10 @@ class IndexerSyncStatus {
|
||||
currentJob: string | null = null;
|
||||
errorMessage: string | null = null;
|
||||
statusUpdatedSubject$ = new Subject<string | true>();
|
||||
batterySaveMode: {
|
||||
promise: Promise<void>;
|
||||
resolve: () => void;
|
||||
} | null = null;
|
||||
|
||||
state$ = new Observable<IndexerSyncState>(subscribe => {
|
||||
const next = () => {
|
||||
@@ -685,6 +697,9 @@ class IndexerSyncStatus {
|
||||
}
|
||||
|
||||
async acceptJob(abort?: AbortSignal) {
|
||||
if (this.batterySaveMode) {
|
||||
await this.batterySaveMode.promise;
|
||||
}
|
||||
const job = await this.jobs.asyncPop(abort);
|
||||
this.currentJob = job;
|
||||
this.statusUpdatedSubject$.next(job);
|
||||
@@ -709,6 +724,18 @@ class IndexerSyncStatus {
|
||||
};
|
||||
}
|
||||
|
||||
enableBatterySaveMode() {
|
||||
if (this.batterySaveMode) {
|
||||
return;
|
||||
}
|
||||
this.batterySaveMode = Promise.withResolvers();
|
||||
}
|
||||
|
||||
disableBatterySaveMode() {
|
||||
this.batterySaveMode?.resolve();
|
||||
this.batterySaveMode = null;
|
||||
}
|
||||
|
||||
reset() {
|
||||
// reset all state, except prioritySettings
|
||||
this.isReadonly = false;
|
||||
|
||||
@@ -86,6 +86,21 @@ export class StoreManagerClient {
|
||||
connection.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
enableBatterySaveMode() {
|
||||
this.connections.forEach(connection => {
|
||||
connection.store.enableBatterySaveMode().catch(err => {
|
||||
console.error('error enabling battery save mode', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
disableBatterySaveMode() {
|
||||
this.connections.forEach(connection => {
|
||||
connection.store.disableBatterySaveMode().catch(err => {
|
||||
console.error('error disabling battery save mode', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class StoreClient {
|
||||
@@ -113,6 +128,13 @@ export class StoreClient {
|
||||
readonly blobFrontend: BlobFrontend;
|
||||
readonly awarenessFrontend: AwarenessFrontend;
|
||||
readonly indexerFrontend: IndexerFrontend;
|
||||
|
||||
enableBatterySaveMode(): Promise<void> {
|
||||
return this.client.call('sync.enableBatterySaveMode');
|
||||
}
|
||||
disableBatterySaveMode(): Promise<void> {
|
||||
return this.client.call('sync.disableBatterySaveMode');
|
||||
}
|
||||
}
|
||||
|
||||
class WorkerDocStorage implements DocStorage {
|
||||
|
||||
@@ -134,6 +134,35 @@ class StoreConsumer {
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ENABLE_BATTERY_SAVE_MODE_DELAY = 1000;
|
||||
private enableBatterySaveModeTimeout: NodeJS.Timeout | null = null;
|
||||
private enabledBatterySaveMode = false;
|
||||
|
||||
enableBatterySaveMode() {
|
||||
if (this.enableBatterySaveModeTimeout || this.enabledBatterySaveMode) {
|
||||
return;
|
||||
}
|
||||
this.enableBatterySaveModeTimeout = setTimeout(() => {
|
||||
if (!this.enabledBatterySaveMode) {
|
||||
this.indexerSync.enableBatterySaveMode();
|
||||
this.enabledBatterySaveMode = true;
|
||||
console.log('[BatterySaveMode] enabled');
|
||||
}
|
||||
}, this.ENABLE_BATTERY_SAVE_MODE_DELAY);
|
||||
}
|
||||
|
||||
disableBatterySaveMode() {
|
||||
if (this.enableBatterySaveModeTimeout) {
|
||||
clearTimeout(this.enableBatterySaveModeTimeout);
|
||||
this.enableBatterySaveModeTimeout = null;
|
||||
}
|
||||
if (this.enabledBatterySaveMode) {
|
||||
this.indexerSync.disableBatterySaveMode();
|
||||
this.enabledBatterySaveMode = false;
|
||||
console.log('[BatterySaveMode] disabled');
|
||||
}
|
||||
}
|
||||
|
||||
private registerHandlers(consumer: OpConsumer<WorkerOps>) {
|
||||
const collectJobs = new Map<
|
||||
string,
|
||||
@@ -285,6 +314,8 @@ class StoreConsumer {
|
||||
this.indexerSync.search$(table, query, options),
|
||||
'indexerSync.subscribeAggregate': ({ table, query, field, options }) =>
|
||||
this.indexerSync.aggregate$(table, query, field, options),
|
||||
'sync.enableBatterySaveMode': () => this.enableBatterySaveMode(),
|
||||
'sync.disableBatterySaveMode': () => this.disableBatterySaveMode(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,10 @@ interface GroupedWorkerOps {
|
||||
AggregateResult<any, any>,
|
||||
];
|
||||
};
|
||||
sync: {
|
||||
enableBatterySaveMode: [void, void];
|
||||
disableBatterySaveMode: [void, void];
|
||||
};
|
||||
}
|
||||
|
||||
type Values<T> = T extends { [k in keyof T]: any } ? T[keyof T] : never;
|
||||
|
||||
Reference in New Issue
Block a user