@metamask/snaps-controllers 14.1.0 → 14.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -1
- package/dist/cronjob/CronjobController.cjs +22 -8
- package/dist/cronjob/CronjobController.cjs.map +1 -1
- package/dist/cronjob/CronjobController.d.cts +12 -1
- package/dist/cronjob/CronjobController.d.cts.map +1 -1
- package/dist/cronjob/CronjobController.d.mts +12 -1
- package/dist/cronjob/CronjobController.d.mts.map +1 -1
- package/dist/cronjob/CronjobController.mjs +22 -8
- package/dist/cronjob/CronjobController.mjs.map +1 -1
- package/dist/services/AbstractExecutionService.cjs +7 -7
- package/dist/services/AbstractExecutionService.cjs.map +1 -1
- package/dist/services/AbstractExecutionService.d.cts +1 -2
- package/dist/services/AbstractExecutionService.d.cts.map +1 -1
- package/dist/services/AbstractExecutionService.d.mts +1 -2
- package/dist/services/AbstractExecutionService.d.mts.map +1 -1
- package/dist/services/AbstractExecutionService.mjs +7 -7
- package/dist/services/AbstractExecutionService.mjs.map +1 -1
- package/dist/snaps/SnapController.cjs +37 -17
- package/dist/snaps/SnapController.cjs.map +1 -1
- package/dist/snaps/SnapController.d.cts +15 -4
- package/dist/snaps/SnapController.d.cts.map +1 -1
- package/dist/snaps/SnapController.d.mts +15 -4
- package/dist/snaps/SnapController.d.mts.map +1 -1
- package/dist/snaps/SnapController.mjs +37 -17
- package/dist/snaps/SnapController.mjs.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [14.2.1]
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Prevent double scheduling events and ensure long-running events work correctly ([#3561](https://github.com/MetaMask/snaps/pull/3561))
|
|
15
|
+
- Emit event when destroying execution environment streams ([#3074](https://github.com/MetaMask/snaps/pull/3074))
|
|
16
|
+
- Ignore terminate calls to not executing Snaps ([#3559](https://github.com/MetaMask/snaps/pull/3559))
|
|
17
|
+
- Properly stop Snaps when clearing state ([#3552](https://github.com/MetaMask/snaps/pull/3552))
|
|
18
|
+
|
|
19
|
+
## [14.2.0]
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Add support for `onActive` and `onInactive` lifecycle hooks ([#3542](https://github.com/MetaMask/snaps/pull/3542))
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Bump `@metamask/phishing-controller` from `12.6.0` to `13.1.0` ([#3538](https://github.com/MetaMask/snaps/pull/3538))
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Use custom state manager for cronjob controller ([#3539](https://github.com/MetaMask/snaps/pull/3539))
|
|
32
|
+
|
|
10
33
|
## [14.1.0]
|
|
11
34
|
|
|
12
35
|
### Added
|
|
@@ -858,7 +881,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
858
881
|
- The version of the package no longer needs to match the version of all other
|
|
859
882
|
MetaMask Snaps packages.
|
|
860
883
|
|
|
861
|
-
[Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.1
|
|
884
|
+
[Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.2.1...HEAD
|
|
885
|
+
[14.2.1]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.2.0...@metamask/snaps-controllers@14.2.1
|
|
886
|
+
[14.2.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.1.0...@metamask/snaps-controllers@14.2.0
|
|
862
887
|
[14.1.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.0.2...@metamask/snaps-controllers@14.1.0
|
|
863
888
|
[14.0.2]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.0.1...@metamask/snaps-controllers@14.0.2
|
|
864
889
|
[14.0.1]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.0.0...@metamask/snaps-controllers@14.0.1
|
|
@@ -20,20 +20,23 @@ const controllerName = 'CronjobController';
|
|
|
20
20
|
*/
|
|
21
21
|
class CronjobController extends base_controller_1.BaseController {
|
|
22
22
|
#timers;
|
|
23
|
+
#stateManager;
|
|
23
24
|
#dailyTimer = new Timer_1.Timer(exports.DAILY_TIMEOUT);
|
|
24
|
-
constructor({ messenger, state }) {
|
|
25
|
+
constructor({ messenger, state, stateManager }) {
|
|
25
26
|
super({
|
|
26
27
|
messenger,
|
|
27
28
|
metadata: {
|
|
28
|
-
events: { persist:
|
|
29
|
+
events: { persist: false, anonymous: false },
|
|
29
30
|
},
|
|
30
31
|
name: controllerName,
|
|
31
32
|
state: {
|
|
32
33
|
events: {},
|
|
33
34
|
...state,
|
|
35
|
+
...stateManager.getInitialState(),
|
|
34
36
|
},
|
|
35
37
|
});
|
|
36
38
|
this.#timers = new Map();
|
|
39
|
+
this.#stateManager = stateManager;
|
|
37
40
|
this.messagingSystem.subscribe('SnapController:snapInstalled', this.#handleSnapInstalledEvent);
|
|
38
41
|
this.messagingSystem.subscribe('SnapController:snapUninstalled', this.#handleSnapUninstalledEvent);
|
|
39
42
|
this.messagingSystem.subscribe('SnapController:snapEnabled', this.#handleSnapEnabledEvent);
|
|
@@ -158,9 +161,10 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
158
161
|
date: (0, utils_2.getExecutionDate)(event.schedule),
|
|
159
162
|
scheduledAt: new Date().toISOString(),
|
|
160
163
|
};
|
|
161
|
-
this.update((state) => {
|
|
164
|
+
const { nextState } = this.update((state) => {
|
|
162
165
|
state.events[internalEvent.id] = (0, immer_1.castDraft)(internalEvent);
|
|
163
166
|
});
|
|
167
|
+
this.#stateManager.set(nextState);
|
|
164
168
|
this.#schedule(internalEvent);
|
|
165
169
|
return id;
|
|
166
170
|
}
|
|
@@ -168,12 +172,19 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
168
172
|
* Get the next execution date for a given event and start a timer for it.
|
|
169
173
|
*
|
|
170
174
|
* @param event - The event to schedule.
|
|
175
|
+
* @param next - Whether to schedule to the next date, otherwise will
|
|
176
|
+
* schedule for existing date.
|
|
171
177
|
*/
|
|
172
|
-
#schedule(event) {
|
|
178
|
+
#schedule(event, next = true) {
|
|
179
|
+
if (!next) {
|
|
180
|
+
this.#startTimer(event);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
173
183
|
const date = (0, utils_2.getExecutionDate)(event.schedule);
|
|
174
|
-
this.update((state) => {
|
|
184
|
+
const { nextState } = this.update((state) => {
|
|
175
185
|
state.events[event.id].date = date;
|
|
176
186
|
});
|
|
187
|
+
this.#stateManager.set(nextState);
|
|
177
188
|
this.#startTimer({
|
|
178
189
|
...event,
|
|
179
190
|
date,
|
|
@@ -227,9 +238,10 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
227
238
|
// Non-recurring events are removed from the state after execution, and
|
|
228
239
|
// recurring events are rescheduled.
|
|
229
240
|
if (!event.recurring) {
|
|
230
|
-
this.update((state) => {
|
|
241
|
+
const { nextState } = this.update((state) => {
|
|
231
242
|
delete state.events[event.id];
|
|
232
243
|
});
|
|
244
|
+
this.#stateManager.set(nextState);
|
|
233
245
|
return;
|
|
234
246
|
}
|
|
235
247
|
this.#schedule(event);
|
|
@@ -244,9 +256,10 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
244
256
|
const timer = this.#timers.get(id);
|
|
245
257
|
timer?.cancel();
|
|
246
258
|
this.#timers.delete(id);
|
|
247
|
-
this.update((state) => {
|
|
259
|
+
const { nextState } = this.update((state) => {
|
|
248
260
|
delete state.events[id];
|
|
249
261
|
});
|
|
262
|
+
this.#stateManager.set(nextState);
|
|
250
263
|
}
|
|
251
264
|
/**
|
|
252
265
|
* Retrieve all cronjob specifications for a Snap.
|
|
@@ -344,8 +357,9 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
344
357
|
// immediately.
|
|
345
358
|
if (event.recurring && eventDate <= now) {
|
|
346
359
|
this.#execute(event);
|
|
360
|
+
continue;
|
|
347
361
|
}
|
|
348
|
-
this.#schedule(event);
|
|
362
|
+
this.#schedule(event, false);
|
|
349
363
|
}
|
|
350
364
|
}
|
|
351
365
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.cjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\n/**\n * Initialise the CronjobController. This should be called after all controllers\n * are created.\n */\nexport type CronjobControllerInitAction = {\n type: `${typeof controllerName}:init`;\n handler: CronjobController['init'];\n};\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get\n | CronjobControllerInitAction;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n },\n });\n\n this.#timers = new Map();\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:init`,\n (...args) => this.init(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n }\n\n /**\n * Initialize the CronjobController.\n *\n * This starts the daily timer, clears out expired events\n * and reschedules any remaining events.\n */\n init() {\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n */\n #schedule(event: InternalBackgroundEvent) {\n const date = getExecutionDate(event.schedule);\n this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n // When an event is supposed to be scheduled close to the current time\n // we may end up needing to execute immediately instead.\n if (ms <= 0) {\n this.#execute(event);\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n this.update((state) => {\n delete state.events[event.id];\n });\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n this.update((state) => {\n delete state.events[id];\n });\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n // In case of local Snaps, they may already have cronjobs that should be cleared.\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n }\n\n this.#schedule(event);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CronjobController.cjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":";;;AAKA,+DAA2D;AAE3D,mEAGqC;AAGrC,uDAI+B;AAC/B,2CAAmE;AACnE,iCAAkC;AAClC,iCAAiC;AACjC,mCAAgC;AAEhC,uCAA4E;AAS5E,sDAAqD;AACrD,8CAAuC;AA4D1B,QAAA,aAAa,GAAG,IAAA,sBAAc,EAAC,EAAE,EAAE,gBAAQ,CAAC,IAAI,CAAC,CAAC;AAiE/D,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAE3C;;;;GAIG;AACH,MAAa,iBAAkB,SAAQ,gCAItC;IACU,OAAO,CAAqB;IAE5B,aAAa,CAAgC;IAEtD,WAAW,GAAU,IAAI,aAAK,CAAC,qBAAa,CAAC,CAAC;IAE9C,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAyB;QACnE,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE;gBACR,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;aAC7C;YACD,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,MAAM,EAAE,EAAE;gBACV,GAAG,KAAK;gBACR,GAAG,YAAY,CAAC,eAAe,EAAE;aAClC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAElC,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,8BAA8B,EAC9B,IAAI,CAAC,yBAAyB,CAC/B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,gCAAgC,EAChC,IAAI,CAAC,2BAA2B,CACjC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,6BAA6B,EAC7B,IAAI,CAAC,wBAAwB,CAC9B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,OAAO,EACxB,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAChC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,WAAW,EAC5B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CACpC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,SAAS,EAC1B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAClC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,MAAM,EACvB,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAC/B,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,IAAI;QACF,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,KAAoD;QAC3D,OAAO,IAAI,CAAC,IAAI,CAAC;YACf,GAAG,KAAK;YACR,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,MAAc,EAAE,EAAU;QAC/B,IAAA,cAAM,EACJ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EACrB,sCAAsC,EAAE,mBAAmB,CAC5D,CAAC;QAEF,IAAA,cAAM,EACJ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,KAAK,MAAM,EACvC,0DAA0D,CAC3D,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,MAAc;QAChB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;aACpC,MAAM,CACL,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CACnE;aACA,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACf,GAAG,KAAK;YACR,IAAI,EAAE,IAAA,qCAAuB,EAAC,KAAK,CAAC,IAAI,CAAC;YACzC,WAAW,EAAE,IAAA,qCAAuB,EAAC,KAAK,CAAC,WAAW,CAAC;SACxD,CAAC,CAAC,CAAC;IACR,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,MAAc;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,MAAc;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,OAAO;QACL,KAAK,CAAC,OAAO,EAAE,CAAC;QAEhB,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,8BAA8B,EAC9B,IAAI,CAAC,yBAAyB,CAC/B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,gCAAgC,EAChC,IAAI,CAAC,2BAA2B,CACjC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,6BAA6B,EAC7B,IAAI,CAAC,wBAAwB,CAC9B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,uCAAuC;QACvC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1C,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAI,CAAC,WAAW,GAAG,IAAI,aAAK,CAAC,qBAAa,CAAC,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,IAAI,CAAC,KAAiC;QACpC,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAA,eAAM,GAAE,CAAC;QAChC,MAAM,aAAa,GAA4B;YAC7C,GAAG,KAAK;YACR,EAAE;YACF,IAAI,EAAE,IAAA,wBAAgB,EAAC,KAAK,CAAC,QAAQ,CAAC;YACtC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC;QAEF,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1C,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,IAAA,iBAAS,EAAC,aAAa,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAElC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,KAA8B,EAAE,IAAI,GAAG,IAAI;QACnD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACxB,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAA,wBAAgB,EAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1C,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAElC,IAAI,CAAC,WAAW,CAAC;YACf,GAAG,KAAK;YACR,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,KAA8B;QACxC,MAAM,EAAE,GACN,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE1E,iEAAiE;QACjE,IAAI,EAAE,GAAG,qBAAa,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QAED,sEAAsE;QACtE,wDAAwD;QACxD,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACZ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,aAAK,CAAC,EAAE,CAAC,CAAC;QAC5B,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE;YACf,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACpC,CAAC;IAED;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAA8B;QACrC,IAAI,CAAC,eAAe;aACjB,IAAI,CAAC,8BAA8B,EAAE;YACpC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,2BAAe;YACvB,OAAO,EAAE,yBAAW,CAAC,SAAS;YAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAA,sBAAQ,EACN,wDAAwD,KAAK,CAAC,MAAM,IAAI,EACxE,KAAK,CACN,CAAC;QACJ,CAAC,CAAC,CAAC;QAEL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAE9B,uEAAuE;QACvE,oCAAoC;QACpC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC1C,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAElC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,EAAU;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAExB,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1C,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,MAAc;QAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC3C,qCAAqC,EACrC,MAAM,CACP,CAAC;QAEF,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC,kCAAc,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,IAAA,wCAAoB,EAAC,UAAU,CAAC,CAAC;QAErD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE;YACzC,OAAO;gBACL,MAAM;gBACN,EAAE,EAAE,WAAW,MAAM,IAAI,GAAG,EAAE;gBAC9B,OAAO,EAAE,UAAU,CAAC,OAAO;gBAC3B,QAAQ,EAAE,IAAA,uCAA+B,EAAC,UAAU,CAAC;gBACrD,SAAS,EAAE,IAAI;aAChB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACM,yBAAyB,GAAG,CAAC,IAAmB,EAAE,EAAE;QAC3D,iFAAiF;QACjF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF;;;;;OAKG;IACM,uBAAuB,GAAG,CAAC,IAAmB,EAAE,EAAE;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF;;;;;OAKG;IACM,2BAA2B,GAAG,CAAC,IAAmB,EAAE,EAAE;QAC7D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF;;;;;OAKG;IACM,wBAAwB,GAAG,CAAC,IAAmB,EAAE,EAAE;QAC1D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF;;;;OAIG;IACM,uBAAuB,GAAG,CAAC,IAAmB,EAAE,EAAE;QACzD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF;;;;;;;OAOG;IACH,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,+DAA+D;gBAC/D,iBAAiB;gBACjB,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE;gBAC7C,OAAO,EAAE,IAAI;aACd,CAAC;iBACC,KAAK,EAAE;iBACP,QAAQ,EAAE,CAAC;YAEd,oEAAoE;YACpE,eAAe;YACf,IAAI,KAAK,CAAC,SAAS,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;gBACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACrB,SAAS;YACX,CAAC;YAED,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,MAAM,SAAS,GAAG,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE;gBAC7C,OAAO,EAAE,IAAI;aACd,CAAC;iBACC,KAAK,EAAE;iBACP,QAAQ,EAAE,CAAC;YAEd,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;gBACxC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA1eD,8CA0eC","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\n/**\n * Initialise the CronjobController. This should be called after all controllers\n * are created.\n */\nexport type CronjobControllerInitAction = {\n type: `${typeof controllerName}:init`;\n handler: CronjobController['init'];\n};\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get\n | CronjobControllerInitAction;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerStateManager = {\n set(state: CronjobControllerState): void;\n getInitialState(): CronjobControllerState | undefined;\n};\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n\n /**\n * State manager for the controller.\n *\n * This is a temporary workaround to allow the controller to update the state\n * often without persisting all of the client state to disk.\n */\n stateManager: CronjobControllerStateManager;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n readonly #stateManager: CronjobControllerStateManager;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state, stateManager }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n ...stateManager.getInitialState(),\n },\n });\n\n this.#timers = new Map();\n this.#stateManager = stateManager;\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:init`,\n (...args) => this.init(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n }\n\n /**\n * Initialize the CronjobController.\n *\n * This starts the daily timer, clears out expired events\n * and reschedules any remaining events.\n */\n init() {\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n const { nextState } = this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#stateManager.set(nextState);\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n * @param next - Whether to schedule to the next date, otherwise will\n * schedule for existing date.\n */\n #schedule(event: InternalBackgroundEvent, next = true) {\n if (!next) {\n this.#startTimer(event);\n return;\n }\n\n const date = getExecutionDate(event.schedule);\n const { nextState } = this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#stateManager.set(nextState);\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n // When an event is supposed to be scheduled close to the current time\n // we may end up needing to execute immediately instead.\n if (ms <= 0) {\n this.#execute(event);\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n const { nextState } = this.update((state) => {\n delete state.events[event.id];\n });\n\n this.#stateManager.set(nextState);\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n const { nextState } = this.update((state) => {\n delete state.events[id];\n });\n\n this.#stateManager.set(nextState);\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n // In case of local Snaps, they may already have cronjobs that should be cleared.\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n continue;\n }\n\n this.#schedule(event, false);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
@@ -29,12 +29,23 @@ export type CronjobControllerActions = CronjobControllerGetStateAction | HandleS
|
|
|
29
29
|
export type CronjobControllerEvents = CronjobControllerStateChangeEvent | SnapInstalled | SnapUninstalled | SnapUpdated | SnapEnabled | SnapDisabled;
|
|
30
30
|
export type CronjobControllerMessenger = RestrictedMessenger<typeof controllerName, CronjobControllerActions, CronjobControllerEvents, CronjobControllerActions['type'], CronjobControllerEvents['type']>;
|
|
31
31
|
export declare const DAILY_TIMEOUT: number;
|
|
32
|
+
export type CronjobControllerStateManager = {
|
|
33
|
+
set(state: CronjobControllerState): void;
|
|
34
|
+
getInitialState(): CronjobControllerState | undefined;
|
|
35
|
+
};
|
|
32
36
|
export type CronjobControllerArgs = {
|
|
33
37
|
messenger: CronjobControllerMessenger;
|
|
34
38
|
/**
|
|
35
39
|
* Persisted state that will be used for rehydration.
|
|
36
40
|
*/
|
|
37
41
|
state?: CronjobControllerState;
|
|
42
|
+
/**
|
|
43
|
+
* State manager for the controller.
|
|
44
|
+
*
|
|
45
|
+
* This is a temporary workaround to allow the controller to update the state
|
|
46
|
+
* often without persisting all of the client state to disk.
|
|
47
|
+
*/
|
|
48
|
+
stateManager: CronjobControllerStateManager;
|
|
38
49
|
};
|
|
39
50
|
/**
|
|
40
51
|
* Represents a background event that is scheduled to be executed by the
|
|
@@ -78,7 +89,7 @@ declare const controllerName = "CronjobController";
|
|
|
78
89
|
*/
|
|
79
90
|
export declare class CronjobController extends BaseController<typeof controllerName, CronjobControllerState, CronjobControllerMessenger> {
|
|
80
91
|
#private;
|
|
81
|
-
constructor({ messenger, state }: CronjobControllerArgs);
|
|
92
|
+
constructor({ messenger, state, stateManager }: CronjobControllerArgs);
|
|
82
93
|
/**
|
|
83
94
|
* Initialize the CronjobController.
|
|
84
95
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.d.cts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,wCAAwC;AAKtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,4BAA4B;AAanE,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACZ,qBAAW;AAIZ,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CACpE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AACF,MAAM,MAAM,iCAAiC,GAAG,0BAA0B,CACxE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,GAAG,OAAO,cAAc,OAAO,CAAC;IACtC,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,GAAG,OAAO,cAAc,WAAW,CAAC;IAC1C,OAAO,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,GAAG,OAAO,cAAc,SAAS,CAAC;IACxC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG;IAChB,IAAI,EAAE,GAAG,OAAO,cAAc,MAAM,CAAC;IACrC,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAChC,+BAA+B,GAC/B,iBAAiB,GACjB,cAAc,GACd,QAAQ,GACR,MAAM,GACN,GAAG,GACH,2BAA2B,CAAC;AAEhC,MAAM,MAAM,uBAAuB,GAC/B,iCAAiC,GACjC,aAAa,GACb,eAAe,GACf,WAAW,GACX,WAAW,GACX,YAAY,CAAC;AAEjB,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,CAC1D,OAAO,cAAc,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,CAAC,MAAM,CAAC,EAChC,uBAAuB,CAAC,MAAM,CAAC,CAChC,CAAC;AAEF,eAAO,MAAM,aAAa,QAAoC,CAAC;AAE/D,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,0BAA0B,CAAC;IAEtC;;OAEG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"CronjobController.d.cts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,12 +29,23 @@ export type CronjobControllerActions = CronjobControllerGetStateAction | HandleS
|
|
|
29
29
|
export type CronjobControllerEvents = CronjobControllerStateChangeEvent | SnapInstalled | SnapUninstalled | SnapUpdated | SnapEnabled | SnapDisabled;
|
|
30
30
|
export type CronjobControllerMessenger = RestrictedMessenger<typeof controllerName, CronjobControllerActions, CronjobControllerEvents, CronjobControllerActions['type'], CronjobControllerEvents['type']>;
|
|
31
31
|
export declare const DAILY_TIMEOUT: number;
|
|
32
|
+
export type CronjobControllerStateManager = {
|
|
33
|
+
set(state: CronjobControllerState): void;
|
|
34
|
+
getInitialState(): CronjobControllerState | undefined;
|
|
35
|
+
};
|
|
32
36
|
export type CronjobControllerArgs = {
|
|
33
37
|
messenger: CronjobControllerMessenger;
|
|
34
38
|
/**
|
|
35
39
|
* Persisted state that will be used for rehydration.
|
|
36
40
|
*/
|
|
37
41
|
state?: CronjobControllerState;
|
|
42
|
+
/**
|
|
43
|
+
* State manager for the controller.
|
|
44
|
+
*
|
|
45
|
+
* This is a temporary workaround to allow the controller to update the state
|
|
46
|
+
* often without persisting all of the client state to disk.
|
|
47
|
+
*/
|
|
48
|
+
stateManager: CronjobControllerStateManager;
|
|
38
49
|
};
|
|
39
50
|
/**
|
|
40
51
|
* Represents a background event that is scheduled to be executed by the
|
|
@@ -78,7 +89,7 @@ declare const controllerName = "CronjobController";
|
|
|
78
89
|
*/
|
|
79
90
|
export declare class CronjobController extends BaseController<typeof controllerName, CronjobControllerState, CronjobControllerMessenger> {
|
|
80
91
|
#private;
|
|
81
|
-
constructor({ messenger, state }: CronjobControllerArgs);
|
|
92
|
+
constructor({ messenger, state, stateManager }: CronjobControllerArgs);
|
|
82
93
|
/**
|
|
83
94
|
* Initialize the CronjobController.
|
|
84
95
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.d.mts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,wCAAwC;AAKtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,4BAA4B;AAanE,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACZ,qBAAW;AAIZ,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CACpE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AACF,MAAM,MAAM,iCAAiC,GAAG,0BAA0B,CACxE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,GAAG,OAAO,cAAc,OAAO,CAAC;IACtC,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,GAAG,OAAO,cAAc,WAAW,CAAC;IAC1C,OAAO,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,GAAG,OAAO,cAAc,SAAS,CAAC;IACxC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG;IAChB,IAAI,EAAE,GAAG,OAAO,cAAc,MAAM,CAAC;IACrC,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAChC,+BAA+B,GAC/B,iBAAiB,GACjB,cAAc,GACd,QAAQ,GACR,MAAM,GACN,GAAG,GACH,2BAA2B,CAAC;AAEhC,MAAM,MAAM,uBAAuB,GAC/B,iCAAiC,GACjC,aAAa,GACb,eAAe,GACf,WAAW,GACX,WAAW,GACX,YAAY,CAAC;AAEjB,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,CAC1D,OAAO,cAAc,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,CAAC,MAAM,CAAC,EAChC,uBAAuB,CAAC,MAAM,CAAC,CAChC,CAAC;AAEF,eAAO,MAAM,aAAa,QAAoC,CAAC;AAE/D,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,0BAA0B,CAAC;IAEtC;;OAEG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"CronjobController.d.mts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,20 +17,23 @@ const controllerName = 'CronjobController';
|
|
|
17
17
|
*/
|
|
18
18
|
export class CronjobController extends BaseController {
|
|
19
19
|
#timers;
|
|
20
|
+
#stateManager;
|
|
20
21
|
#dailyTimer = new Timer(DAILY_TIMEOUT);
|
|
21
|
-
constructor({ messenger, state }) {
|
|
22
|
+
constructor({ messenger, state, stateManager }) {
|
|
22
23
|
super({
|
|
23
24
|
messenger,
|
|
24
25
|
metadata: {
|
|
25
|
-
events: { persist:
|
|
26
|
+
events: { persist: false, anonymous: false },
|
|
26
27
|
},
|
|
27
28
|
name: controllerName,
|
|
28
29
|
state: {
|
|
29
30
|
events: {},
|
|
30
31
|
...state,
|
|
32
|
+
...stateManager.getInitialState(),
|
|
31
33
|
},
|
|
32
34
|
});
|
|
33
35
|
this.#timers = new Map();
|
|
36
|
+
this.#stateManager = stateManager;
|
|
34
37
|
this.messagingSystem.subscribe('SnapController:snapInstalled', this.#handleSnapInstalledEvent);
|
|
35
38
|
this.messagingSystem.subscribe('SnapController:snapUninstalled', this.#handleSnapUninstalledEvent);
|
|
36
39
|
this.messagingSystem.subscribe('SnapController:snapEnabled', this.#handleSnapEnabledEvent);
|
|
@@ -155,9 +158,10 @@ export class CronjobController extends BaseController {
|
|
|
155
158
|
date: getExecutionDate(event.schedule),
|
|
156
159
|
scheduledAt: new Date().toISOString(),
|
|
157
160
|
};
|
|
158
|
-
this.update((state) => {
|
|
161
|
+
const { nextState } = this.update((state) => {
|
|
159
162
|
state.events[internalEvent.id] = castDraft(internalEvent);
|
|
160
163
|
});
|
|
164
|
+
this.#stateManager.set(nextState);
|
|
161
165
|
this.#schedule(internalEvent);
|
|
162
166
|
return id;
|
|
163
167
|
}
|
|
@@ -165,12 +169,19 @@ export class CronjobController extends BaseController {
|
|
|
165
169
|
* Get the next execution date for a given event and start a timer for it.
|
|
166
170
|
*
|
|
167
171
|
* @param event - The event to schedule.
|
|
172
|
+
* @param next - Whether to schedule to the next date, otherwise will
|
|
173
|
+
* schedule for existing date.
|
|
168
174
|
*/
|
|
169
|
-
#schedule(event) {
|
|
175
|
+
#schedule(event, next = true) {
|
|
176
|
+
if (!next) {
|
|
177
|
+
this.#startTimer(event);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
170
180
|
const date = getExecutionDate(event.schedule);
|
|
171
|
-
this.update((state) => {
|
|
181
|
+
const { nextState } = this.update((state) => {
|
|
172
182
|
state.events[event.id].date = date;
|
|
173
183
|
});
|
|
184
|
+
this.#stateManager.set(nextState);
|
|
174
185
|
this.#startTimer({
|
|
175
186
|
...event,
|
|
176
187
|
date,
|
|
@@ -224,9 +235,10 @@ export class CronjobController extends BaseController {
|
|
|
224
235
|
// Non-recurring events are removed from the state after execution, and
|
|
225
236
|
// recurring events are rescheduled.
|
|
226
237
|
if (!event.recurring) {
|
|
227
|
-
this.update((state) => {
|
|
238
|
+
const { nextState } = this.update((state) => {
|
|
228
239
|
delete state.events[event.id];
|
|
229
240
|
});
|
|
241
|
+
this.#stateManager.set(nextState);
|
|
230
242
|
return;
|
|
231
243
|
}
|
|
232
244
|
this.#schedule(event);
|
|
@@ -241,9 +253,10 @@ export class CronjobController extends BaseController {
|
|
|
241
253
|
const timer = this.#timers.get(id);
|
|
242
254
|
timer?.cancel();
|
|
243
255
|
this.#timers.delete(id);
|
|
244
|
-
this.update((state) => {
|
|
256
|
+
const { nextState } = this.update((state) => {
|
|
245
257
|
delete state.events[id];
|
|
246
258
|
});
|
|
259
|
+
this.#stateManager.set(nextState);
|
|
247
260
|
}
|
|
248
261
|
/**
|
|
249
262
|
* Retrieve all cronjob specifications for a Snap.
|
|
@@ -341,8 +354,9 @@ export class CronjobController extends BaseController {
|
|
|
341
354
|
// immediately.
|
|
342
355
|
if (event.recurring && eventDate <= now) {
|
|
343
356
|
this.#execute(event);
|
|
357
|
+
continue;
|
|
344
358
|
}
|
|
345
|
-
this.#schedule(event);
|
|
359
|
+
this.#schedule(event, false);
|
|
346
360
|
}
|
|
347
361
|
}
|
|
348
362
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.mjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\n/**\n * Initialise the CronjobController. This should be called after all controllers\n * are created.\n */\nexport type CronjobControllerInitAction = {\n type: `${typeof controllerName}:init`;\n handler: CronjobController['init'];\n};\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get\n | CronjobControllerInitAction;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n },\n });\n\n this.#timers = new Map();\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:init`,\n (...args) => this.init(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n }\n\n /**\n * Initialize the CronjobController.\n *\n * This starts the daily timer, clears out expired events\n * and reschedules any remaining events.\n */\n init() {\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n */\n #schedule(event: InternalBackgroundEvent) {\n const date = getExecutionDate(event.schedule);\n this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n // When an event is supposed to be scheduled close to the current time\n // we may end up needing to execute immediately instead.\n if (ms <= 0) {\n this.#execute(event);\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n this.update((state) => {\n delete state.events[event.id];\n });\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n this.update((state) => {\n delete state.events[id];\n });\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n // In case of local Snaps, they may already have cronjobs that should be cleared.\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n }\n\n this.#schedule(event);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CronjobController.mjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\n/**\n * Initialise the CronjobController. This should be called after all controllers\n * are created.\n */\nexport type CronjobControllerInitAction = {\n type: `${typeof controllerName}:init`;\n handler: CronjobController['init'];\n};\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get\n | CronjobControllerInitAction;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerStateManager = {\n set(state: CronjobControllerState): void;\n getInitialState(): CronjobControllerState | undefined;\n};\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n\n /**\n * State manager for the controller.\n *\n * This is a temporary workaround to allow the controller to update the state\n * often without persisting all of the client state to disk.\n */\n stateManager: CronjobControllerStateManager;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n readonly #stateManager: CronjobControllerStateManager;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state, stateManager }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: false, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n ...stateManager.getInitialState(),\n },\n });\n\n this.#timers = new Map();\n this.#stateManager = stateManager;\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:init`,\n (...args) => this.init(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n }\n\n /**\n * Initialize the CronjobController.\n *\n * This starts the daily timer, clears out expired events\n * and reschedules any remaining events.\n */\n init() {\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n const { nextState } = this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#stateManager.set(nextState);\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n * @param next - Whether to schedule to the next date, otherwise will\n * schedule for existing date.\n */\n #schedule(event: InternalBackgroundEvent, next = true) {\n if (!next) {\n this.#startTimer(event);\n return;\n }\n\n const date = getExecutionDate(event.schedule);\n const { nextState } = this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#stateManager.set(nextState);\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n // When an event is supposed to be scheduled close to the current time\n // we may end up needing to execute immediately instead.\n if (ms <= 0) {\n this.#execute(event);\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n const { nextState } = this.update((state) => {\n delete state.events[event.id];\n });\n\n this.#stateManager.set(nextState);\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n const { nextState } = this.update((state) => {\n delete state.events[id];\n });\n\n this.#stateManager.set(nextState);\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n // In case of local Snaps, they may already have cronjobs that should be cleared.\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n continue;\n }\n\n this.#schedule(event, false);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
@@ -51,15 +51,14 @@ class AbstractExecutionService {
|
|
|
51
51
|
/**
|
|
52
52
|
* Terminates the Snap with the specified ID and deletes all its associated
|
|
53
53
|
* data. Any subsequent messages targeting the Snap will fail with an error.
|
|
54
|
-
* Throws an error if
|
|
55
|
-
* fails unexpectedly.
|
|
54
|
+
* Throws an error if termination fails unexpectedly.
|
|
56
55
|
*
|
|
57
56
|
* @param snapId - The id of the Snap to be terminated.
|
|
58
57
|
*/
|
|
59
58
|
async terminateSnap(snapId) {
|
|
60
59
|
const job = this.#jobs.get(snapId);
|
|
61
60
|
if (!job) {
|
|
62
|
-
|
|
61
|
+
return;
|
|
63
62
|
}
|
|
64
63
|
try {
|
|
65
64
|
// Ping worker and tell it to run teardown, continue with termination if it takes too long
|
|
@@ -83,8 +82,9 @@ class AbstractExecutionService {
|
|
|
83
82
|
}
|
|
84
83
|
Object.values(job.streams).forEach((stream) => {
|
|
85
84
|
try {
|
|
86
|
-
!stream.destroyed
|
|
87
|
-
|
|
85
|
+
if (!stream.destroyed) {
|
|
86
|
+
stream.destroy();
|
|
87
|
+
}
|
|
88
88
|
}
|
|
89
89
|
catch (error) {
|
|
90
90
|
(0, snaps_utils_1.logError)('Error while destroying stream', error);
|
|
@@ -108,7 +108,7 @@ class AbstractExecutionService {
|
|
|
108
108
|
const rpcEngine = new json_rpc_engine_1.JsonRpcEngine();
|
|
109
109
|
const jsonRpcConnection = (0, json_rpc_middleware_stream_1.createStreamMiddleware)();
|
|
110
110
|
(0, readable_stream_1.pipeline)(jsonRpcConnection.stream, streams.command, jsonRpcConnection.stream, (error) => {
|
|
111
|
-
if (error) {
|
|
111
|
+
if (error && !error.message?.match('Premature close')) {
|
|
112
112
|
(0, snaps_utils_1.logError)(`Command stream failure.`, error);
|
|
113
113
|
}
|
|
114
114
|
});
|
|
@@ -288,7 +288,7 @@ exports.AbstractExecutionService = AbstractExecutionService;
|
|
|
288
288
|
function setupMultiplex(connectionStream, streamName) {
|
|
289
289
|
const mux = new object_multiplex_1.default();
|
|
290
290
|
(0, readable_stream_1.pipeline)(connectionStream, mux, connectionStream, (error) => {
|
|
291
|
-
if (error) {
|
|
291
|
+
if (error && !error.message?.match('Premature close')) {
|
|
292
292
|
(0, snaps_utils_1.logError)(`"${streamName}" stream failure.`, error);
|
|
293
293
|
}
|
|
294
294
|
});
|