-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathexamples.js
132 lines (111 loc) · 4.01 KB
/
examples.js
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
/**
* Response from cache
*/
self.addEventListener('fetch', event => {
const response = self.caches.open('example')
.then(caches => caches.match(event.request))
.then(response => response || fetch(event.request));
event.respondWith(response);
});
/**
* Response to SSE by text
*/
self.addEventListener('fetch', event => {
const {headers} = event.request;
const isSSERequest = headers.get('Accept') === 'text/event-stream';
if (!isSSERequest) {
return;
}
event.respondWith(new Response('Hello!'));
});
/**
* Response to SSE by stream
*/
self.addEventListener('fetch', event => {
const {headers} = event.request;
const isSSERequest = headers.get('Accept') === 'text/event-stream';
if (!isSSERequest) {
return;
}
const responseText = 'Hello!';
const responseData = Uint8Array.from(responseText, x => x.charCodeAt(0));
const stream = new ReadableStream({start: controller => controller.enqueue(responseData)});
const response = new Response(stream);
event.respondWith(response);
});
/**
* SSE chunk data
*/
const sseChunkData = (data, event, retry, id) =>
Object.entries({event, id, data, retry})
.filter(([, value]) => ![undefined, null].includes(value))
.map(([key, value]) => `${key}: ${value}`)
.join('\n') + '\n\n';
/**
* Success response to SSE from SW
*/
self.addEventListener('fetch', event => {
const {headers} = event.request;
const isSSERequest = headers.get('Accept') === 'text/event-stream';
if (!isSSERequest) {
return;
}
const sseChunkData = (data, event, retry, id) =>
Object.entries({event, id, data, retry})
.filter(([, value]) => ![undefined, null].includes(value))
.map(([key, value]) => `${key}: ${value}`)
.join('\n') + '\n\n';
const sseHeaders = {
'content-type': 'text/event-stream',
'Transfer-Encoding': 'chunked',
'Connection': 'keep-alive',
};
const responseText = sseChunkData('Hello!');
const responseData = Uint8Array.from(responseText, x => x.charCodeAt(0));
const stream = new ReadableStream({start: controller => controller.enqueue(responseData)});
const response = new Response(stream, {headers: sseHeaders});
event.respondWith(response);
});
/**
* Result
*/
self.addEventListener('fetch', event => {
const {headers, url} = event.request;
const isSSERequest = headers.get('Accept') === 'text/event-stream';
// Process only SSE connections
if (!isSSERequest) {
return;
}
// Headers for SSE response
const sseHeaders = {
'content-type': 'text/event-stream',
'Transfer-Encoding': 'chunked',
'Connection': 'keep-alive',
};
// Function for formatting message to SSE response
const sseChunkData = (data, event, retry, id) =>
Object.entries({event, id, data, retry})
.filter(([, value]) => ![undefined, null].includes(value))
.map(([key, value]) => `${key}: ${value}`)
.join('\n') + '\n\n';
// Map with server connections, where key - url, value - EventSource
const serverConnections = {};
// For each request opens only one server connection and use it for next requests with the same url
const getServerConnection = url => {
if (!serverConnections[url]) {
serverConnections[url] = new EventSource(url);
}
return serverConnections[url];
};
// On message from server forward it to browser
const onServerMessage = (controller, {data, type, retry, lastEventId}) => {
const responseText = sseChunkData(data, type, retry, lastEventId);
const responseData = Uint8Array.from(responseText, x => x.charCodeAt(0));
controller.enqueue(responseData);
};
const stream = new ReadableStream({
start: controller => getServerConnection(url).onmessage = onServerMessage.bind(null, controller)
});
const response = new Response(stream, {headers: sseHeaders});
event.respondWith(response);
});