-
Notifications
You must be signed in to change notification settings - Fork 542
/
CronjobService.ts
125 lines (108 loc) · 2.97 KB
/
CronjobService.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import {
RestrictedControllerMessenger,
HasPermission,
GetPermissions,
} from '@metamask/controllers';
import { SnapId } from '@metamask/snap-types';
import { parseExpression } from 'cron-parser';
import { nanoid } from 'nanoid';
import {
GetSnap,
HandleSnapCronjobRequest,
SnapAdded,
SnapEndowments,
} from '..';
import { Timer } from '../snaps/Timer';
export type CronjobServiceActions =
| GetSnap
| HandleSnapCronjobRequest
| HasPermission
| GetPermissions;
export type CronjobServiceEvents = SnapAdded;
export type CronjobServiceMessenger = RestrictedControllerMessenger<
'CronjobService',
CronjobServiceActions,
CronjobServiceEvents,
CronjobServiceActions['type'],
CronjobServiceEvents['type']
>;
export type CronjobServiceArgs = {
messenger: CronjobServiceMessenger;
};
export type CronjobData = {
jobs: Cronjob[];
};
export type CronjobDefinition = {
expression: string;
request: Record<string, unknown>;
};
export type Cronjob = {
timer?: Timer;
id: string;
} & CronjobDefinition;
export class CronjobService {
private _messenger: CronjobServiceMessenger;
private _snaps: Map<SnapId, string[]>;
private _jobs: Map<string, Cronjob>;
constructor({ messenger }: CronjobServiceArgs) {
this._snaps = new Map();
this._jobs = new Map();
this._messenger = messenger;
}
async register(snapId: SnapId) {
const hasCronjob = await this._messenger.call(
'PermissionController:hasPermission',
snapId,
SnapEndowments.cronjob,
);
if (!hasCronjob) {
return;
}
const permissions = await this._messenger.call(
'PermissionController:getPermissions',
snapId,
);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const cronjobPermission = permissions![SnapEndowments.cronjob]!;
// @todo Figure out how to get this from the permission
const definitions: CronjobDefinition[] = (cronjobPermission as any).jobs;
const jobs = definitions.map((definition) => {
const id = nanoid();
return { ...definition, id };
});
this._snaps.set(
snapId,
jobs.map((job) => job.id),
);
jobs.forEach((job) => this.schedule(snapId, job));
}
unregister(snapId: SnapId) {
const jobs = this._snaps.get(snapId);
jobs?.forEach((id) => {
const job = this._jobs.get(id);
job?.timer?.cancel();
});
this._snaps.delete(snapId);
}
schedule(snapId: SnapId, job: Cronjob) {
const parsed = parseExpression(job.expression);
if (!parsed.hasNext()) {
return;
}
const next = parsed.next();
const now = new Date();
const ms = now.getTime() - next.getTime();
const timer = new Timer(ms);
timer.start(() => {
this._messenger.call(
'SnapController:handleCronjobRequest',
snapId,
// @todo Decide on origin for requests like this
'METAMASK',
job.request,
);
this.schedule(snapId, job);
});
this._jobs.set(job.id, { ...job, timer });
}
}