Files
mkd/services/offlineCacheService.ts
2026-02-04 00:17:04 +05:00

142 lines
4.0 KiB
TypeScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Сервис кэширования данных для offline режима
type CachedRequest = {
id: string;
method: string;
url: string;
body?: unknown;
timestamp: number;
retries: number;
};
const CACHE_KEY = 'mkd_offline_cache';
const MAX_RETRIES = 10;
const MAX_CACHE_AGE = 7 * 24 * 60 * 60 * 1000; // 7 дней
class OfflineCacheService {
// Сохранить запрос в кэш
cacheRequest(method: string, url: string, body?: unknown): string {
const cachedRequests = this.getCachedRequests();
const id = `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const request: CachedRequest = {
id,
method,
url,
body,
timestamp: Date.now(),
retries: 0,
};
cachedRequests.push(request);
this.saveCachedRequests(cachedRequests);
return id;
}
// Получить все закэшированные запросы
getCachedRequests(): CachedRequest[] {
try {
const stored = localStorage.getItem(CACHE_KEY);
if (stored) {
const requests = JSON.parse(stored) as CachedRequest[];
// Фильтруем устаревшие запросы
const now = Date.now();
return requests.filter(req => now - req.timestamp < MAX_CACHE_AGE);
}
return [];
} catch (e) {
console.error('Failed to get cached requests', e);
return [];
}
}
// Сохранить закэшированные запросы
private saveCachedRequests(requests: CachedRequest[]) {
try {
localStorage.setItem(CACHE_KEY, JSON.stringify(requests));
} catch (e) {
console.error('Failed to save cached requests', e);
}
}
// Удалить запрос из кэша
removeRequest(id: string): void {
const cachedRequests = this.getCachedRequests();
const filtered = cachedRequests.filter(req => req.id !== id);
this.saveCachedRequests(filtered);
}
// Увеличить счётчик попыток для запроса
incrementRetries(id: string): void {
const cachedRequests = this.getCachedRequests();
const updated = cachedRequests.map(req => {
if (req.id === id) {
return { ...req, retries: req.retries + 1 };
}
return req;
});
this.saveCachedRequests(updated);
}
// Синхронизировать все закэшированные запросы
async syncCachedRequests(apiBaseUrl: string): Promise<{ success: number; failed: number }> {
const cachedRequests = this.getCachedRequests();
let success = 0;
let failed = 0;
for (const request of cachedRequests) {
// Пропускаем запросы с превышенным лимитом попыток
if (request.retries >= MAX_RETRIES) {
this.removeRequest(request.id);
failed++;
continue;
}
try {
const fullUrl = request.url.startsWith('http')
? request.url
: `${apiBaseUrl}${request.url}`;
const options: RequestInit = {
method: request.method,
headers: {
'Content-Type': 'application/json',
},
};
if (request.body && (request.method === 'POST' || request.method === 'PUT')) {
options.body = JSON.stringify(request.body);
}
const response = await fetch(fullUrl, options);
if (response.ok) {
this.removeRequest(request.id);
success++;
} else {
this.incrementRetries(request.id);
failed++;
}
} catch (error) {
this.incrementRetries(request.id);
failed++;
}
}
return { success, failed };
}
// Очистить весь кэш
clearCache(): void {
localStorage.removeItem(CACHE_KEY);
}
// Получить количество закэшированных запросов
getCacheSize(): number {
return this.getCachedRequests().length;
}
}
// Создаём единственный экземпляр сервиса
export const offlineCacheService = new OfflineCacheService();