-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathweb-runtime.ts
More file actions
159 lines (141 loc) · 4.02 KB
/
Copy pathweb-runtime.ts
File metadata and controls
159 lines (141 loc) · 4.02 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
type EventCallback = (payload: any) => void
interface ServerEnvelope {
connectionId?: string
data: any
}
interface ScreenInfo {
width: number
height: number
isCurrent: boolean
isPrimary: boolean
}
const listeners = new Map<string, Set<EventCallback>>()
const latestEventPayload = new Map<string, any>()
const scheduledEventNames = new Set<string>()
let eventSource: EventSource | null = null
function dispatchEventPayload(eventName: string, payload: any) {
const handlers = listeners.get(eventName)
if (!handlers) {
return
}
handlers.forEach((handler) => handler(payload))
}
function queueEventPayload(eventName: string, payload: any) {
latestEventPayload.set(eventName, payload)
if (scheduledEventNames.has(eventName)) {
return
}
scheduledEventNames.add(eventName)
window.requestAnimationFrame(() => {
scheduledEventNames.delete(eventName)
const nextPayload = latestEventPayload.get(eventName)
latestEventPayload.delete(eventName)
dispatchEventPayload(eventName, nextPayload)
})
}
function ensureEventSource() {
if (eventSource) {
return
}
eventSource = new EventSource('/api/events')
eventSource.onopen = () => {
// noop
}
eventSource.onerror = () => {
// EventSource reconnects automatically.
}
const eventNames = [
'scan:log',
'maintain:log',
'inventory:log',
'quota:log',
'scan:progress',
'maintain:progress',
'inventory:progress',
'quota:progress',
'quota:snapshot',
'task:finished',
'scheduler:status',
'account:update',
]
const throttledEvents = new Set([
'scan:progress',
'maintain:progress',
'inventory:progress',
'quota:progress',
'scheduler:status',
'quota:snapshot',
'account:update',
])
eventNames.forEach((eventName) => {
eventSource?.addEventListener(eventName, (event) => {
const messageEvent = event as MessageEvent<string>
let payload: any = messageEvent.data
try {
payload = JSON.parse(messageEvent.data) as ServerEnvelope
} catch {
// keep raw string
}
const unwrappedPayload = payload && typeof payload === 'object' && 'data' in payload
? {
...(payload as ServerEnvelope).data,
connectionId: (payload as ServerEnvelope).connectionId,
}
: payload
if (throttledEvents.has(eventName)) {
queueEventPayload(eventName, unwrappedPayload)
return
}
dispatchEventPayload(eventName, unwrappedPayload)
})
})
}
export function EventsOn(eventName: string, handler: EventCallback) {
ensureEventSource()
if (!listeners.has(eventName)) {
listeners.set(eventName, new Set())
}
listeners.get(eventName)?.add(handler)
}
export function EmitScopedContextChange() {
latestEventPayload.clear()
scheduledEventNames.clear()
}
export function EventsOff(eventName: string) {
listeners.delete(eventName)
latestEventPayload.delete(eventName)
scheduledEventNames.delete(eventName)
}
export async function ClipboardSetText(value: string) {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(value)
return
}
const textarea = document.createElement('textarea')
textarea.value = value
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
}
export async function ScreenGetAll(): Promise<ScreenInfo[]> {
return [{
width: window.screen.availWidth || window.innerWidth,
height: window.screen.availHeight || window.innerHeight,
isCurrent: true,
isPrimary: true,
}]
}
export function WindowSetLightTheme() {
document.documentElement.style.colorScheme = 'light'
}
export function WindowSetMinSize(minWidth: number, minHeight: number) {
document.documentElement.style.setProperty('--app-min-width', `${minWidth}px`)
document.documentElement.style.setProperty('--app-min-height', `${minHeight}px`)
}
export function LogDebug(message: string) {
console.debug(message)
}
export function LogError(message: string) {
console.error(message)
}