117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
import * as plugins from './smartupdate.plugins.js';
|
|
import type { ICacheStatus, ICacheOptions } from './smartupdate.interfaces.js';
|
|
|
|
/**
|
|
* Manages caching of update check results
|
|
*/
|
|
export class UpdateCacheManager {
|
|
private kvStore: plugins.npmextra.KeyValueStore;
|
|
private cacheDurationMs: number;
|
|
|
|
constructor(options: ICacheOptions) {
|
|
this.cacheDurationMs = options.durationMs;
|
|
this.kvStore = new plugins.npmextra.KeyValueStore({
|
|
typeArg: 'userHomeDir',
|
|
identityArg: options.storeIdentifier || 'global_smartupdate',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the cache duration in milliseconds
|
|
*/
|
|
public getCacheDuration(): number {
|
|
return this.cacheDurationMs;
|
|
}
|
|
|
|
/**
|
|
* Get cached status for a package
|
|
*/
|
|
public async getCached(packageName: string): Promise<ICacheStatus | null> {
|
|
return await this.kvStore.readKey(packageName);
|
|
}
|
|
|
|
/**
|
|
* Set cache status for a package
|
|
*/
|
|
public async setCached(packageName: string, status: ICacheStatus): Promise<void> {
|
|
await this.kvStore.writeKey(packageName, status);
|
|
}
|
|
|
|
/**
|
|
* Clear cache for a specific package or all packages
|
|
*/
|
|
public async clearCache(packageName?: string): Promise<void> {
|
|
if (packageName) {
|
|
await this.kvStore.deleteKey(packageName);
|
|
} else {
|
|
// Clear all keys - this requires reading all keys first
|
|
// For now, we'll skip implementing full cache clear as it requires more kvStore API
|
|
throw new Error('Clearing all cache entries is not yet implemented');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if we should check the registry or use cache
|
|
* @returns Object with shouldCheck flag and optional nextCheckTime
|
|
*/
|
|
public async shouldCheckRegistry(
|
|
packageName: string,
|
|
strategy: 'always' | 'never' | 'time-based' = 'time-based'
|
|
): Promise<{
|
|
shouldCheck: boolean;
|
|
cacheStatus?: ICacheStatus;
|
|
nextCheckTime?: Date;
|
|
minutesUntilNextCheck?: number;
|
|
}> {
|
|
// Never use cache
|
|
if (strategy === 'never') {
|
|
return { shouldCheck: true };
|
|
}
|
|
|
|
// Get cached data
|
|
const cacheStatus = await this.getCached(packageName);
|
|
|
|
// No cache exists
|
|
if (!cacheStatus) {
|
|
return { shouldCheck: true };
|
|
}
|
|
|
|
// Always use cache if available
|
|
if (strategy === 'always') {
|
|
return { shouldCheck: false, cacheStatus };
|
|
}
|
|
|
|
// Time-based strategy: check if cache is still valid
|
|
const now = Date.now();
|
|
const lastCheckTime = cacheStatus.lastCheck;
|
|
const timeSinceLastCheck = now - lastCheckTime;
|
|
|
|
// Cache is still valid
|
|
if (timeSinceLastCheck < this.cacheDurationMs) {
|
|
const nextCheckTime = new Date(lastCheckTime + this.cacheDurationMs);
|
|
const minutesUntilNextCheck = (this.cacheDurationMs - timeSinceLastCheck) / 60000;
|
|
|
|
return {
|
|
shouldCheck: false,
|
|
cacheStatus,
|
|
nextCheckTime,
|
|
minutesUntilNextCheck,
|
|
};
|
|
}
|
|
|
|
// Cache is expired
|
|
return { shouldCheck: true, cacheStatus };
|
|
}
|
|
|
|
/**
|
|
* Create a new cache status object
|
|
*/
|
|
public createCacheStatus(latestVersion: string, performedUpgrade: boolean = false): ICacheStatus {
|
|
return {
|
|
lastCheck: Date.now(),
|
|
latestVersion,
|
|
performedUpgrade,
|
|
};
|
|
}
|
|
}
|