diff --git a/packages/extension/src/background.ts b/packages/extension/src/background.ts index 962afcda2b..15c7c66181 100644 --- a/packages/extension/src/background.ts +++ b/packages/extension/src/background.ts @@ -15,6 +15,7 @@ import { AccountsStore } from '@polkadot/extension-base/stores'; import { keyring } from '@polkadot/ui-keyring'; import { assert } from '@polkadot/util'; import { cryptoWaitReady } from '@polkadot/util-crypto'; +import { runHeartbeat, startHeartbeat } from './heartbeat'; // setup the notification (same a FF default background, white text) withErrorLog(() => chrome.action.setBadgeBackgroundColor({ color: '#d90000' })); @@ -77,6 +78,27 @@ chrome.tabs.onRemoved.addListener(() => { getActiveTabs(); }); +// add heartbeat using alarms to prevent the service worker from being killed as +// much as possible. +chrome.alarms.onAlarm.addListener(async () => { + await runHeartbeat() +}); + +chrome.runtime.onInstalled.addListener(({ reason }) => { + if ( + reason !== chrome.runtime.OnInstalledReason.INSTALL && + reason !== chrome.runtime.OnInstalledReason.UPDATE + ) { + return; + } + + chrome.alarms.create('heartbeat', { + periodInMinutes: 0.5 + }); +}); + +startHeartbeat(); + // initial setup cryptoWaitReady() .then((): void => { diff --git a/packages/extension/src/heartbeat.ts b/packages/extension/src/heartbeat.ts new file mode 100644 index 0000000000..586aa9b949 --- /dev/null +++ b/packages/extension/src/heartbeat.ts @@ -0,0 +1,39 @@ +// Copyright 2019-2024 @polkadot/extension authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +/** + * Heartbeat functions as described by google. + * + * @see https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers#keep_a_service_worker_alive_continuously + */ + +let heartbeatInterval: string | number | NodeJS.Timeout | undefined; + +export async function runHeartbeat () { + await chrome.storage.local.set({ 'last-heartbeat': new Date().getTime() }); +} + +/** + * Starts the heartbeat interval which keeps the service worker alive. Call + * this sparingly when you are doing work which requires persistence, and call + * stopHeartbeat once that work is complete. + */ +export async function startHeartbeat () { + // Run the heartbeat once at service worker startup. + runHeartbeat().then(() => { + // Then again every 20 seconds. + heartbeatInterval = setInterval(runHeartbeat, 20 * 1000); + }); +} + +export async function stopHeartbeat () { + clearInterval(heartbeatInterval); +} + +/** + * Returns the last heartbeat stored in extension storage, or undefined if + * the heartbeat has never run before. + */ +export async function getLastHeartbeat () { + return (await chrome.storage.local.get('last-heartbeat'))['last-heartbeat']; +}