mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat: enhance backup process with lease management and attachment deletion
- Implemented a backup runner lease mechanism to prevent concurrent backup executions. - Added `deleteAllAttachmentsForCiphers` function to delete attachments for multiple ciphers efficiently. - Introduced `bulkDeleteAttachmentsByIds` method in storage to handle batch deletion of attachments. - Updated backup execution logic to utilize the new lease management and ensure timely updates during the backup process. - Refactored cipher deletion to handle attachments more effectively. - Improved website icon loading with a dedicated caching mechanism for better performance. - Added new index on `ciphers` table for `folder_id` to optimize queries related to folder management. - Enhanced response handling for CORS policy to allow credentials for specific origins.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
type WebsiteIconStatus = 'idle' | 'loading' | 'loaded' | 'error';
|
||||
|
||||
interface WebsiteIconRecord {
|
||||
status: WebsiteIconStatus;
|
||||
promise: Promise<WebsiteIconStatus> | null;
|
||||
listeners: Set<(status: WebsiteIconStatus) => void>;
|
||||
}
|
||||
|
||||
const iconRecords = new Map<string, WebsiteIconRecord>();
|
||||
|
||||
function ensureRecord(host: string): WebsiteIconRecord {
|
||||
let record = iconRecords.get(host);
|
||||
if (!record) {
|
||||
record = {
|
||||
status: 'idle',
|
||||
promise: null,
|
||||
listeners: new Set(),
|
||||
};
|
||||
iconRecords.set(host, record);
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
function notifyRecord(host: string, status: WebsiteIconStatus): void {
|
||||
const record = ensureRecord(host);
|
||||
record.status = status;
|
||||
for (const listener of Array.from(record.listeners)) {
|
||||
listener(status);
|
||||
}
|
||||
}
|
||||
|
||||
export function getWebsiteIconStatus(host: string): WebsiteIconStatus {
|
||||
if (!host) return 'idle';
|
||||
return ensureRecord(host).status;
|
||||
}
|
||||
|
||||
export function subscribeWebsiteIconStatus(host: string, listener: (status: WebsiteIconStatus) => void): () => void {
|
||||
if (!host) return () => undefined;
|
||||
const record = ensureRecord(host);
|
||||
record.listeners.add(listener);
|
||||
return () => {
|
||||
record.listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
export function markWebsiteIconLoaded(host: string): void {
|
||||
if (!host) return;
|
||||
const record = ensureRecord(host);
|
||||
record.promise = null;
|
||||
notifyRecord(host, 'loaded');
|
||||
}
|
||||
|
||||
export function markWebsiteIconErrored(host: string): void {
|
||||
if (!host) return;
|
||||
const record = ensureRecord(host);
|
||||
record.promise = null;
|
||||
notifyRecord(host, 'error');
|
||||
}
|
||||
|
||||
export function preloadWebsiteIcon(host: string, src: string): Promise<WebsiteIconStatus> {
|
||||
if (!host) return Promise.resolve('error');
|
||||
|
||||
const record = ensureRecord(host);
|
||||
if (record.status === 'loaded' || record.status === 'error') {
|
||||
return Promise.resolve(record.status);
|
||||
}
|
||||
if (record.promise) {
|
||||
return record.promise;
|
||||
}
|
||||
|
||||
record.status = 'loading';
|
||||
record.promise = new Promise<WebsiteIconStatus>((resolve) => {
|
||||
const img = new Image();
|
||||
img.decoding = 'async';
|
||||
img.loading = 'eager';
|
||||
img.referrerPolicy = 'no-referrer';
|
||||
img.onload = () => {
|
||||
markWebsiteIconLoaded(host);
|
||||
resolve('loaded');
|
||||
};
|
||||
img.onerror = () => {
|
||||
markWebsiteIconErrored(host);
|
||||
resolve('error');
|
||||
};
|
||||
img.src = src;
|
||||
});
|
||||
|
||||
return record.promise;
|
||||
}
|
||||
Reference in New Issue
Block a user