forked from sheepzh/time-tracker-4-browser
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalarm-manager.ts
More file actions
113 lines (101 loc) · 3.07 KB
/
alarm-manager.ts
File metadata and controls
113 lines (101 loc) · 3.07 KB
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
import { clearAlarm, createAlarm, onAlarm } from "@api/chrome/alarm"
import { getRuntimeId } from "@api/chrome/runtime"
type _AlarmConfig = {
handler: _Handler,
interval?: number,
when?: () => number,
}
type _Handler = (alarm: ChromeAlarm) => void
const ALARM_PREFIX = 'timer-alarm-' + getRuntimeId() + '-'
const ALARM_PREFIX_LENGTH = ALARM_PREFIX.length
const getInnerName = (outerName: string) => ALARM_PREFIX + outerName
const getOuterName = (innerName: string) => innerName.substring(ALARM_PREFIX_LENGTH)
const calcNextTs = (config: _AlarmConfig): number => {
const { interval, when } = config
if (interval) return Date.now() + interval
if (when) return when()
return Date.now()
}
/**
* The manager of alarms
*
* @since 1.4.6
*/
class AlarmManager {
private alarms: Record<string, _AlarmConfig> = {}
constructor() {
this.init()
}
private init() {
onAlarm(async alarm => {
const name = alarm.name
if (!name.startsWith(ALARM_PREFIX)) {
// Unknown alarm
return
}
const innerName = getOuterName(name)
const config: _AlarmConfig = this.alarms[innerName]
if (!config) {
// Not registered, or removed
return
}
// Handle alarm event
try {
config.handler?.(alarm)
} catch (e) {
console.info("Failed to handle alarm event", e)
} finally {
const nextTs = calcNextTs(config)
// Clear this one
await clearAlarm(name)
createAlarm(name, nextTs)
}
})
}
/**
* Set a alarm to do sth with interval
*
* @param interval mills
*/
setInterval(outerName: string, interval: number, handler: _Handler): void {
if (!interval || !handler) {
return
}
const config: _AlarmConfig = { handler, interval }
if (this.alarms[outerName]) {
// Existed, only update the config
this.alarms[outerName] = config
return
}
// Initialize config
this.alarms[outerName] = config
// Create new one alarm
createAlarm(getInnerName(outerName), Date.now() + interval)
}
/**
* Set a alarm to do sth if the time arrives
*/
setWhen(outerName: string, when: () => number, handler: _Handler): void {
if (!when || !handler) {
return
}
const config: _AlarmConfig = { handler, when }
if (this.alarms[outerName]) {
// Existed, only update the config
this.alarms[outerName] = config
return
}
// Initialize config
this.alarms[outerName] = config
// Create new one alarm
createAlarm(getInnerName(outerName), when())
}
/**
* Remove a interval
*/
remove(outerName: string) {
delete this.alarms[outerName]
clearAlarm(getInnerName(outerName))
}
}
export default new AlarmManager()