-
-
Notifications
You must be signed in to change notification settings - Fork 337
Expand file tree
/
Copy pathwebgal-serviceworker.js
More file actions
99 lines (88 loc) · 3.03 KB
/
webgal-serviceworker.js
File metadata and controls
99 lines (88 loc) · 3.03 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
const CACHE_NAME = 'webgal-critical-assets-v3';
const GAME_PREFIX = '/game/';
const CRITICAL_PATHS = ['/game/background/', '/game/figure/', '/game/bgm/', '/game/vocal/', '/game/video/'];
const LOG_PREFIX = '[WebGAL SW]';
const loggedKeys = new Set();
function logOnce(key, ...args) {
if (loggedKeys.has(key)) return;
loggedKeys.add(key);
console.log(LOG_PREFIX, ...args);
}
self.addEventListener('install', (event) => {
logOnce('install', `install ${CACHE_NAME}`);
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', (event) => {
logOnce('activate', `activate ${CACHE_NAME}`);
event.waitUntil(
(async () => {
const keys = await caches.keys();
await Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)));
await self.clients.claim();
})(),
);
});
function isCriticalGameRequest(request) {
if (request.method !== 'GET') return false;
const url = new URL(request.url);
if (url.origin !== self.location.origin) return false;
if (!url.pathname.startsWith(GAME_PREFIX)) return false;
return CRITICAL_PATHS.some((prefix) => url.pathname.startsWith(prefix));
}
async function cacheFirst(request) {
const cache = await caches.open(CACHE_NAME);
const cached = await cache.match(request.url);
if (cached) {
logOnce(`hit:${request.url}`, 'cache hit:', new URL(request.url).pathname);
return cached;
}
const response = await fetch(request);
if (response.ok && response.status === 200) {
await cache.put(request.url, response.clone());
logOnce(`cache:${request.url}`, 'cached:', new URL(request.url).pathname);
}
return response;
}
async function prefetchFromMessage(urlString) {
const requestUrl = new URL(urlString, self.location.origin).toString();
const request = new Request(requestUrl, { method: 'GET' });
if (!isCriticalGameRequest(request)) {
return;
}
const cache = await caches.open(CACHE_NAME);
const hasCached = await cache.match(requestUrl);
if (hasCached) {
return;
}
const response = await fetch(request);
if (response.ok && response.status === 200) {
await cache.put(requestUrl, response.clone());
logOnce(`message-cache:${requestUrl}`, 'message cached:', new URL(requestUrl).pathname);
}
}
self.addEventListener('fetch', (event) => {
const { request } = event;
if (!isCriticalGameRequest(request)) return;
// Audio/video range requests are passed through to avoid partial-content edge cases.
if (request.headers.has('range')) {
logOnce(`range:${request.url}`, 'range passthrough:', new URL(request.url).pathname);
event.respondWith(fetch(request));
return;
}
event.respondWith(
cacheFirst(request).catch(() => {
return fetch(request);
}),
);
});
self.addEventListener('message', (event) => {
const data = event.data || {};
if (data.type !== 'WEBGAL_PREFETCH_ASSET' || typeof data.url !== 'string') {
return;
}
event.waitUntil(
prefetchFromMessage(data.url).catch((error) => {
console.warn(LOG_PREFIX, 'message prefetch failed:', error);
}),
);
});