mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 05:43:41 +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(
|
this.popupViewCacheBackgroundService = new PopupViewCacheBackgroundService(
|
||||||
messageListener,
|
messageListener,
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
|
this.taskSchedulerService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationRunner = new MigrationRunner(
|
const migrationRunner = new MigrationRunner(
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
import { switchMap, merge, delay, filter, concatMap, map, first, of } from "rxjs";
|
import { switchMap, merge, delay, filter, concatMap, map, first, of } from "rxjs";
|
||||||
|
|
||||||
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
|
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
|
||||||
|
import {
|
||||||
|
ScheduledTaskNames,
|
||||||
|
TaskSchedulerService,
|
||||||
|
toScheduler,
|
||||||
|
} from "@bitwarden/common/platform/scheduling";
|
||||||
import {
|
import {
|
||||||
POPUP_VIEW_MEMORY,
|
POPUP_VIEW_MEMORY,
|
||||||
KeyDefinition,
|
KeyDefinition,
|
||||||
@@ -45,7 +50,15 @@ export class PopupViewCacheBackgroundService {
|
|||||||
constructor(
|
constructor(
|
||||||
private messageListener: MessageListener,
|
private messageListener: MessageListener,
|
||||||
private globalStateProvider: GlobalStateProvider,
|
private globalStateProvider: GlobalStateProvider,
|
||||||
) {}
|
private readonly taskSchedulerService: TaskSchedulerService,
|
||||||
|
) {
|
||||||
|
this.taskSchedulerService.registerTaskHandler(
|
||||||
|
ScheduledTaskNames.clearPopupViewCache,
|
||||||
|
async () => {
|
||||||
|
await this.clearState();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
startObservingTabChanges() {
|
startObservingTabChanges() {
|
||||||
this.messageListener
|
this.messageListener
|
||||||
@@ -87,7 +100,14 @@ export class PopupViewCacheBackgroundService {
|
|||||||
// on popup closed, with 2 minute delay that is cancelled by re-opening the popup
|
// on popup closed, with 2 minute delay that is cancelled by re-opening the popup
|
||||||
fromChromeEvent(chrome.runtime.onConnect).pipe(
|
fromChromeEvent(chrome.runtime.onConnect).pipe(
|
||||||
filter(([port]) => port.name === popupClosedPortName),
|
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()))
|
.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 { DefaultTaskSchedulerService } from "./default-task-scheduler.service";
|
||||||
export { ScheduledTaskNames, ScheduledTaskName } from "./scheduled-task-name.enum";
|
export { ScheduledTaskNames, ScheduledTaskName } from "./scheduled-task-name.enum";
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const ScheduledTaskNames = {
|
|||||||
scheduleNextSyncInterval: "scheduleNextSyncInterval",
|
scheduleNextSyncInterval: "scheduleNextSyncInterval",
|
||||||
eventUploadsInterval: "eventUploadsInterval",
|
eventUploadsInterval: "eventUploadsInterval",
|
||||||
vaultTimeoutCheckInterval: "vaultTimeoutCheckInterval",
|
vaultTimeoutCheckInterval: "vaultTimeoutCheckInterval",
|
||||||
|
clearPopupViewCache: "clearPopupViewCache",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type ScheduledTaskName = (typeof ScheduledTaskNames)[keyof typeof ScheduledTaskNames];
|
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
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Subscription } from "rxjs";
|
import { asyncScheduler, SchedulerLike, Subscription } from "rxjs";
|
||||||
|
|
||||||
import { ScheduledTaskName } from "./scheduled-task-name.enum";
|
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 {
|
export abstract class TaskSchedulerService {
|
||||||
protected taskHandlers: Map<string, () => void>;
|
protected taskHandlers: Map<string, () => void>;
|
||||||
abstract setTimeout(taskName: ScheduledTaskName, delayInMs: number): Subscription;
|
abstract setTimeout(taskName: ScheduledTaskName, delayInMs: number): Subscription;
|
||||||
|
|||||||
Reference in New Issue
Block a user