Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions web/src/lib/utils/sw-messaging.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
const broadcast = new BroadcastChannel('immich');

let isLoadedReplyListeners: ((url: string, isUrlCached: boolean) => void)[] = [];
broadcast.addEventListener('message', (event) => {
if (event.data.type == 'isImageUrlCachedReply') {
for (const listener of isLoadedReplyListeners) {
listener(event.data.url, event.data.isImageUrlCached);
}
}
});

export function cancelImageUrl(url: string) {
broadcast.postMessage({ type: 'cancel', url });
}

export function preloadImageUrl(url: string) {
broadcast.postMessage({ type: 'preload', url });
}

export function isImageUrlCached(url: string) {
if (!globalThis.isSecureContext) {
return Promise.resolve(false);
}
return new Promise((resolve) => {
const listener = (urlReply: string, isUrlCached: boolean) => {
if (urlReply === url) {
cleanup(isUrlCached);
}
};
const cleanup = (isUrlCached: boolean) => {
isLoadedReplyListeners = isLoadedReplyListeners.filter((element) => element !== listener);
resolve(isUrlCached);
};
isLoadedReplyListeners.push(listener);
broadcast.postMessage({ type: 'isImageUrlCached', url });

setTimeout(() => cleanup(false), 5000);
});
}
14 changes: 12 additions & 2 deletions web/src/service-worker/broadcast-channel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { handleCancel, handlePreload } from './request';
import { handleCancel, handleIsUrlCached, handlePreload } from './request';

export const broadcast = new BroadcastChannel('immich');

export const installBroadcastChannelListener = () => {
const broadcast = new BroadcastChannel('immich');
// eslint-disable-next-line unicorn/prefer-add-event-listener
broadcast.onmessage = (event) => {
if (!event.data) {
Expand All @@ -20,6 +21,15 @@ export const installBroadcastChannelListener = () => {
handleCancel(url);
break;
}

case 'isImageUrlCached': {
void handleIsUrlCached(url);
break;
}
}
};
};

export const replyIsImageUrlCached = (url: string, isImageUrlCached: boolean) => {
broadcast.postMessage({ type: 'isImageUrlCachedReply', url, isImageUrlCached });
};
6 changes: 5 additions & 1 deletion web/src/service-worker/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export const put = async (key: string, response: Response) => {
return;
}

cache.put(key, response.clone());
try {
await cache.put(key, response.clone());
} catch (error) {
console.error('Ignoring error during cache put', error);
}
};

export const prune = async () => {
Expand Down
9 changes: 8 additions & 1 deletion web/src/service-worker/request.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { replyIsImageUrlCached } from './broadcast-channel';
import { get, put } from './cache';

const pendingRequests = new Map<string, AbortController>();
Expand Down Expand Up @@ -44,7 +45,7 @@ export const handleRequest = async (request: URL | Request) => {
const response = await fetch(request, { signal: cancelToken.signal });

assertResponse(response);
put(cacheKey, response);
await put(cacheKey, response);

return response;
} catch (error) {
Expand All @@ -71,3 +72,9 @@ export const handleCancel = (url: URL) => {
pendingRequest.abort();
pendingRequests.delete(cacheKey);
};

export const handleIsUrlCached = async (url: URL) => {
const cacheKey = getCacheKey(url);
const isImageUrlCached = !!(await get(cacheKey));
replyIsImageUrlCached(url.pathname + url.search + url.hash, isImageUrlCached);
};
Loading