mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-17658] Fix persist route to clear if service worker dies (#13382)
* Add way to convert TaskSchedulerService to RX Scheduler * Add docs to `toScheduler` * Rollback combined subscription change. * Move to barrel file * Expand `toScheduler` documentation * Add TaskName to Doc Example * Ensure register is called on service worker start
This commit is contained in:
@@ -607,6 +607,7 @@ export default class MainBackground {
|
||||
this.popupViewCacheBackgroundService = new PopupViewCacheBackgroundService(
|
||||
messageListener,
|
||||
this.globalStateProvider,
|
||||
this.taskSchedulerService,
|
||||
);
|
||||
|
||||
const migrationRunner = new MigrationRunner(
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
import { switchMap, merge, delay, filter, concatMap, map, first, of } from "rxjs";
|
||||
|
||||
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
|
||||
import {
|
||||
ScheduledTaskNames,
|
||||
TaskSchedulerService,
|
||||
toScheduler,
|
||||
} from "@bitwarden/common/platform/scheduling";
|
||||
import {
|
||||
POPUP_VIEW_MEMORY,
|
||||
KeyDefinition,
|
||||
@@ -45,7 +50,15 @@ export class PopupViewCacheBackgroundService {
|
||||
constructor(
|
||||
private messageListener: MessageListener,
|
||||
private globalStateProvider: GlobalStateProvider,
|
||||
) {}
|
||||
private readonly taskSchedulerService: TaskSchedulerService,
|
||||
) {
|
||||
this.taskSchedulerService.registerTaskHandler(
|
||||
ScheduledTaskNames.clearPopupViewCache,
|
||||
async () => {
|
||||
await this.clearState();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
startObservingTabChanges() {
|
||||
this.messageListener
|
||||
@@ -87,7 +100,14 @@ export class PopupViewCacheBackgroundService {
|
||||
// on popup closed, with 2 minute delay that is cancelled by re-opening the popup
|
||||
fromChromeEvent(chrome.runtime.onConnect).pipe(
|
||||
filter(([port]) => port.name === popupClosedPortName),
|
||||
switchMap(([port]) => fromChromeEvent(port.onDisconnect).pipe(delay(1000 * 60 * 2))),
|
||||
switchMap(([port]) =>
|
||||
fromChromeEvent(port.onDisconnect).pipe(
|
||||
delay(
|
||||
1000 * 60 * 2,
|
||||
toScheduler(this.taskSchedulerService, ScheduledTaskNames.clearPopupViewCache),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.pipe(switchMap(() => this.clearState()))
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { TaskSchedulerService } from "./task-scheduler.service";
|
||||
export { TaskSchedulerService, toScheduler } from "./task-scheduler.service";
|
||||
export { DefaultTaskSchedulerService } from "./default-task-scheduler.service";
|
||||
export { ScheduledTaskNames, ScheduledTaskName } from "./scheduled-task-name.enum";
|
||||
|
||||
@@ -7,6 +7,7 @@ export const ScheduledTaskNames = {
|
||||
scheduleNextSyncInterval: "scheduleNextSyncInterval",
|
||||
eventUploadsInterval: "eventUploadsInterval",
|
||||
vaultTimeoutCheckInterval: "vaultTimeoutCheckInterval",
|
||||
clearPopupViewCache: "clearPopupViewCache",
|
||||
} as const;
|
||||
|
||||
export type ScheduledTaskName = (typeof ScheduledTaskNames)[keyof typeof ScheduledTaskNames];
|
||||
|
||||
@@ -1,9 +1,68 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Subscription } from "rxjs";
|
||||
import { asyncScheduler, SchedulerLike, Subscription } from "rxjs";
|
||||
|
||||
import { ScheduledTaskName } from "./scheduled-task-name.enum";
|
||||
|
||||
/**
|
||||
* Creates a RXJS scheduler based on a {@link TaskSchedulerService}.
|
||||
*
|
||||
* @description This API defers to `TaskSchedulerService` to schedule a task to be ran
|
||||
* in the future but the task that is ran is NOT the remainder of your RXJS pipeline. The
|
||||
* task you want ran must instead be registered in a location reachable on a service worker
|
||||
* startup (on browser). An example of an acceptible location is the constructor of a service
|
||||
* you know is created in `MainBackground`. Uses of this API is other clients _can_ have the
|
||||
* `registerTaskHandler` call in more places, but in order to have it work across clients
|
||||
* it is recommended to register it according to the rules of browser.
|
||||
*
|
||||
* @link https://rxjs.dev/guide/scheduler#using-schedulers
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* class MyService {
|
||||
* constructor(messageListener: MessageListener, taskScheduler: TaskSchedulerService) {
|
||||
* // VERY IMPORTANT!
|
||||
* this.taskSchedulerService.registerTaskHandler(SchedulerTaskNames.myTaskName, async () => {
|
||||
* await this.runEvent();
|
||||
* });
|
||||
*
|
||||
* messageListener.messages$(MY_MESSAGE).pipe(
|
||||
* debounceTime(
|
||||
* 10 * 1000,
|
||||
* toScheduler(taskScheduler, ShedulerTaskNames.myTaskName),
|
||||
* ),
|
||||
* switchMap(() => this.runEvent()),
|
||||
* )
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param taskScheduler The task scheduler service to use to shedule RXJS work.
|
||||
* @param taskName The name of the task that the handler should be registered and scheduled based on.
|
||||
* @returns A SchedulerLike object that can be passed in to RXJS operators like `delay` and `timeout`.
|
||||
*/
|
||||
export function toScheduler(
|
||||
taskScheduler: TaskSchedulerService,
|
||||
taskName: ScheduledTaskName,
|
||||
): SchedulerLike {
|
||||
return new TaskSchedulerSheduler(taskScheduler, taskName);
|
||||
}
|
||||
|
||||
class TaskSchedulerSheduler implements SchedulerLike {
|
||||
constructor(
|
||||
private readonly taskSchedulerService: TaskSchedulerService,
|
||||
private readonly taskName: ScheduledTaskName,
|
||||
) {}
|
||||
|
||||
schedule<T>(work: (state?: T) => void, delay?: number, state?: T): Subscription {
|
||||
return this.taskSchedulerService.setTimeout(this.taskName, delay ?? 0);
|
||||
}
|
||||
|
||||
now(): number {
|
||||
return asyncScheduler.now();
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class TaskSchedulerService {
|
||||
protected taskHandlers: Map<string, () => void>;
|
||||
abstract setTimeout(taskName: ScheduledTaskName, delayInMs: number): Subscription;
|
||||
|
||||
Reference in New Issue
Block a user