/
sse.jsy
132 lines (100 loc) · 3.97 KB
/
sse.jsy
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
import {debounce} from '../utils.jsy'
export const sse_reload_key = '@@sse-reload'
export const sse_reload_evt_rebind = '@@sse-reload rebind'
export const sse_reload_evt_connection = '@@sse-reload connection'
export const sse_reload_evt_update = '@@sse-reload update'
export const sse_reload_evt_errors = '@@sse-reload errors'
export const sse_reload_evt_shutdown = '@@sse-reload shutdown'
export default connectReloadEventSource
export function connectReloadEventSource(url) ::
if ! url :: url = 'http://127.0.0.1:35810'
const tsid = Date.now().toString(36)
let update_count = 0
const es = new EventSource(url)
Object.assign @ es, @{}
onopen() ::
const evt = new Event @ sse_reload_evt_connection
if window.dispatchEvent(evt) ::
console.warn @ `SSE reload ready (${tsid})`
onerror(err) ::
const evt = new Event @ sse_reload_evt_connection
evt.error = err
if window.dispatchEvent(evt) ::
console.warn @ `SSE reload NOT ready (${tsid})`
onmessage({data}) ::
let detail
try ::
detail = JSON.parse @ data
catch err ::
return console.error @ `SSE reload JSON error (${tsid})`, err
detail.tsid = tsid
detail.count = update_count++
dispatch_update(detail)
::
const prev_shutdown = window[sse_reload_key]
window[sse_reload_key] = shutdown
if null != prev_shutdown ::
prev_shutdown()
window.dispatchEvent @
new Event(sse_reload_evt_rebind)
return shutdown
function shutdown() ::
es.close()
window.dispatchEvent @
new Event(sse_reload_evt_shutdown)
function dispatch_update(detail) ::
const {updates, errors, tsid, count} = detail
const has_errors = errors && 0 !== errors.length
const grp_msg = has_errors
? `SSE reload (${tsid}:${count}) with ${errors.length} errors`
: Array.isArray(updates)
? `SSE reload (${tsid}:${count}) with ${updates.length} updates`
: `SSE reload (${tsid}:${count}) notice`
if has_errors ::
console.group(grp_msg)
else console.groupCollapsed(grp_msg)
try ::
const evt_err = new CustomEvent @ sse_reload_evt_errors, @{} detail: errors
if window.dispatchEvent(evt_err) ::
if has_errors ::
for const [err_key, err_msg] of errors ::
console.error @ 'Build Error:', err_msg
const evt = new CustomEvent @ sse_reload_evt_update, @{} detail
if window.dispatchEvent(evt) ::
if updates ::
console.log @ 'Build Updates:', updates
catch err ::
console.error(err)
finally ::
console.groupEnd(grp_msg)
export function onSSEReloadUpdate({ms_reload, preventDefault, on_reload}) ::
const do_reload = debounce @ ms_reload || 150, on_reload
window.addEventListener @ sse_reload_evt_update, _on_reload_, false
return () => ::
window.removeEventListener @ sse_reload_evt_update, _on_reload_, false
function _on_reload_(evt) ::
if preventDefault && null != evt ::
evt.preventDefault()
const {count, updates, mapping} = evt.detail || {}
if 0 === count :: return
if null == updates || 0 === updates.length :: return
do_reload(evt.detail)
export function onSSEReloadErrors({on_show, on_clear, on_update, on_start, on_stop, autoStart}) ::
window.addEventListener @ sse_reload_evt_errors, _on_update_, false
window.addEventListener @ sse_reload_evt_rebind, on_start, false
window.addEventListener @ sse_reload_evt_shutdown, on_stop, false
if autoStart :: on_start()
return () => ::
window.removeEventListener @ sse_reload_evt_errors, _on_update_, false
window.removeEventListener @ sse_reload_evt_rebind, on_start, false
window.removeEventListener @ sse_reload_evt_shutdown, on_stop, false
function _on_update_(evt) ::
const errorList = evt.detail || []
if 0 === errorList.length ::
if null !== on_clear ::
on_clear(evt)
else ::
if null !== on_show ::
on_show(errorList, evt)
if null != on_update ::
on_update(evt)