mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-28 14:27:08 +00:00
Add sleep preferences for finite synchronisation
This commit is contained in:
@@ -91,6 +91,7 @@ export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceCont
|
||||
appLifecycleService: appLifecycle,
|
||||
databaseEventService: databaseEvents,
|
||||
activityRunner: screenWakeLock,
|
||||
isMobile: () => API.isMobile(),
|
||||
});
|
||||
const replication = new ObsidianReplicationService(context, {
|
||||
APIService: API,
|
||||
|
||||
@@ -11,17 +11,53 @@ import type { ObsidianServiceContext } from "@/modules/services/ObsidianServiceC
|
||||
import { KeyValueDBService } from "@vrtmrz/livesync-commonlib/compat/services/base/KeyValueDBService";
|
||||
import { ControlService } from "@vrtmrz/livesync-commonlib/compat/services/base/ControlService";
|
||||
import { reactiveSource } from "octagonal-wheels/dataobject/reactive";
|
||||
import type { ReplicatorServiceDependencies } from "@vrtmrz/livesync-commonlib/compat/services/base/ReplicatorService";
|
||||
import type { ObsidianLiveSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
|
||||
type ActivityOptions = {
|
||||
label?: string;
|
||||
};
|
||||
|
||||
type ObsidianReplicatorServiceDependencies = ReplicatorServiceDependencies & {
|
||||
isMobile: () => boolean;
|
||||
};
|
||||
|
||||
type SleepPreferenceSettings = Pick<
|
||||
ObsidianLiveSyncSettings,
|
||||
"allowSleepDuringSynchronisation" | "allowSleepDuringSynchronisationOnDesktop"
|
||||
>;
|
||||
|
||||
export function shouldAllowSleepDuringSynchronisation(settings: SleepPreferenceSettings, isMobile: boolean): boolean {
|
||||
return settings.allowSleepDuringSynchronisation || (!isMobile && settings.allowSleepDuringSynchronisationOnDesktop);
|
||||
}
|
||||
|
||||
function withSleepPreference(dependencies: ObsidianReplicatorServiceDependencies): ReplicatorServiceDependencies {
|
||||
const activityRunner = dependencies.activityRunner;
|
||||
if (!activityRunner) return dependencies;
|
||||
return {
|
||||
...dependencies,
|
||||
activityRunner: {
|
||||
async run<T>(task: () => T | PromiseLike<T>, options?: ActivityOptions): Promise<T> {
|
||||
const allowSleep = shouldAllowSleepDuringSynchronisation(
|
||||
dependencies.settingService.currentSettings(),
|
||||
dependencies.isMobile()
|
||||
);
|
||||
return allowSleep ? await task() : await activityRunner.run(task, options);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export class ObsidianDatabaseEventService extends InjectableDatabaseEventService<ObsidianServiceContext> {}
|
||||
|
||||
// InjectableReplicatorService
|
||||
export class ObsidianReplicatorService extends InjectableReplicatorService<ObsidianServiceContext> {
|
||||
readonly boundedLocalApplicationActivityCount = reactiveSource(0);
|
||||
|
||||
constructor(context: ObsidianServiceContext, dependencies: ObsidianReplicatorServiceDependencies) {
|
||||
super(context, withSleepPreference(dependencies));
|
||||
}
|
||||
|
||||
async runBoundedLocalApplicationActivity<T>(
|
||||
task: () => T | PromiseLike<T>,
|
||||
options?: ActivityOptions
|
||||
|
||||
@@ -1,25 +1,53 @@
|
||||
import { promiseWithResolvers } from "octagonal-wheels/promises";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { ObsidianReplicatorService } from "./ObsidianServices";
|
||||
import { ObsidianReplicatorService, shouldAllowSleepDuringSynchronisation } from "./ObsidianServices";
|
||||
|
||||
function handler() {
|
||||
return { addHandler: vi.fn() };
|
||||
}
|
||||
|
||||
describe("ObsidianReplicatorService", () => {
|
||||
it.each([
|
||||
{ general: false, desktop: false, mobile: false, expected: false },
|
||||
{ general: false, desktop: true, mobile: false, expected: true },
|
||||
{ general: false, desktop: true, mobile: true, expected: false },
|
||||
{ general: true, desktop: false, mobile: false, expected: true },
|
||||
{ general: true, desktop: false, mobile: true, expected: true },
|
||||
])("applies the sleep preference policy: $general/$desktop/$mobile", ({ general, desktop, mobile, expected }) => {
|
||||
expect(
|
||||
shouldAllowSleepDuringSynchronisation(
|
||||
{
|
||||
allowSleepDuringSynchronisation: general,
|
||||
allowSleepDuringSynchronisationOnDesktop: desktop,
|
||||
},
|
||||
mobile
|
||||
)
|
||||
).toBe(expected);
|
||||
});
|
||||
|
||||
it("tracks local application activity without extending remote activity", async () => {
|
||||
const activity = promiseWithResolvers<void>();
|
||||
const service = new ObsidianReplicatorService({ events: {}, translate: String } as never, {
|
||||
settingService: { onRealiseSetting: handler() },
|
||||
appLifecycleService: { onSuspending: handler(), getUnresolvedMessages: handler() },
|
||||
databaseEventService: {
|
||||
onResetDatabase: handler(),
|
||||
onDatabaseInitialisation: handler(),
|
||||
onDatabaseInitialised: handler(),
|
||||
onDatabaseHasReady: handler(),
|
||||
},
|
||||
activityRunner: { run: vi.fn(async (task: () => Promise<void>) => await task()) },
|
||||
} as never);
|
||||
const service = new ObsidianReplicatorService(
|
||||
{ events: {}, translate: String } as never,
|
||||
{
|
||||
settingService: {
|
||||
onRealiseSetting: handler(),
|
||||
currentSettings: () => ({
|
||||
allowSleepDuringSynchronisation: false,
|
||||
allowSleepDuringSynchronisationOnDesktop: false,
|
||||
}),
|
||||
},
|
||||
appLifecycleService: { onSuspending: handler(), getUnresolvedMessages: handler() },
|
||||
databaseEventService: {
|
||||
onResetDatabase: handler(),
|
||||
onDatabaseInitialisation: handler(),
|
||||
onDatabaseInitialised: handler(),
|
||||
onDatabaseHasReady: handler(),
|
||||
},
|
||||
activityRunner: { run: vi.fn(async (task: () => Promise<void>) => await task()) },
|
||||
isMobile: () => false,
|
||||
} as never
|
||||
);
|
||||
|
||||
const running = service.runBoundedLocalApplicationActivity(() => activity.promise);
|
||||
|
||||
@@ -32,4 +60,34 @@ describe("ObsidianReplicatorService", () => {
|
||||
expect(service.boundedLocalApplicationActivityCount.value).toBe(0);
|
||||
expect(service.boundedRemoteActivityCount.value).toBe(0);
|
||||
});
|
||||
|
||||
it("allows desktop sleep throughout bounded synchronisation activity when configured", async () => {
|
||||
const runWithWakeLock = vi.fn(async (task: () => Promise<void>) => await task());
|
||||
const service = new ObsidianReplicatorService(
|
||||
{ events: {}, translate: String } as never,
|
||||
{
|
||||
settingService: {
|
||||
onRealiseSetting: handler(),
|
||||
currentSettings: () => ({
|
||||
allowSleepDuringSynchronisation: false,
|
||||
allowSleepDuringSynchronisationOnDesktop: true,
|
||||
}),
|
||||
},
|
||||
appLifecycleService: { onSuspending: handler(), getUnresolvedMessages: handler() },
|
||||
databaseEventService: {
|
||||
onResetDatabase: handler(),
|
||||
onDatabaseInitialisation: handler(),
|
||||
onDatabaseInitialised: handler(),
|
||||
onDatabaseHasReady: handler(),
|
||||
},
|
||||
activityRunner: { run: runWithWakeLock },
|
||||
isMobile: () => false,
|
||||
} as never
|
||||
);
|
||||
|
||||
await service.runBoundedRemoteActivity(async () => undefined);
|
||||
await service.runBoundedLocalApplicationActivity(async () => undefined);
|
||||
|
||||
expect(runWithWakeLock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user