first commit
This commit is contained in:
146
src/services/cache.service.ts
Normal file
146
src/services/cache.service.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import redis from '../config/redis.js';
|
||||
import { env } from '../config/env.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import type { GetInfoResponse, CacheEntry, DataSource } from '../types/index.js';
|
||||
|
||||
/**
|
||||
* Cache key prefix for Netflix content
|
||||
*/
|
||||
const CACHE_PREFIX = 'netflix:content:';
|
||||
|
||||
/**
|
||||
* Generate cache key from URL
|
||||
*/
|
||||
function getCacheKey(url: string): string {
|
||||
// Use URL hash or title ID as key
|
||||
const titleId = url.match(/\/title\/(\d+)/)?.[1] || url;
|
||||
return `${CACHE_PREFIX}${titleId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache Service for Redis operations
|
||||
* Handles caching with TTL support
|
||||
*/
|
||||
export class CacheService {
|
||||
/**
|
||||
* Get cached content by URL
|
||||
*/
|
||||
static async get(url: string): Promise<GetInfoResponse | null> {
|
||||
const key = getCacheKey(url);
|
||||
|
||||
try {
|
||||
const cached = await redis.get(key);
|
||||
|
||||
if (!cached) {
|
||||
logger.debug('Cache miss', { url });
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug('Cache hit', { url });
|
||||
const entry: CacheEntry<GetInfoResponse> = JSON.parse(cached);
|
||||
return entry.data;
|
||||
} catch (error) {
|
||||
logger.error('Cache get error', {
|
||||
url,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache entry with TTL
|
||||
*/
|
||||
static async set(url: string, data: GetInfoResponse): Promise<void> {
|
||||
const key = getCacheKey(url);
|
||||
const ttl = env.REDIS_TTL_SECONDS;
|
||||
|
||||
const entry: CacheEntry<GetInfoResponse> = {
|
||||
data,
|
||||
cachedAt: Date.now(),
|
||||
ttl,
|
||||
};
|
||||
|
||||
try {
|
||||
await redis.setex(key, ttl, JSON.stringify(entry));
|
||||
logger.debug('Cache set', { url, ttl });
|
||||
} catch (error) {
|
||||
logger.error('Cache set error', {
|
||||
url,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cached content
|
||||
*/
|
||||
static async delete(url: string): Promise<void> {
|
||||
const key = getCacheKey(url);
|
||||
|
||||
try {
|
||||
await redis.del(key);
|
||||
logger.debug('Cache deleted', { url });
|
||||
} catch (error) {
|
||||
logger.error('Cache delete error', {
|
||||
url,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cache exists
|
||||
*/
|
||||
static async exists(url: string): Promise<boolean> {
|
||||
const key = getCacheKey(url);
|
||||
|
||||
try {
|
||||
const result = await redis.exists(key);
|
||||
return result === 1;
|
||||
} catch (error) {
|
||||
logger.error('Cache exists check error', {
|
||||
url,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache TTL remaining
|
||||
*/
|
||||
static async getTTL(url: string): Promise<number> {
|
||||
const key = getCacheKey(url);
|
||||
|
||||
try {
|
||||
return await redis.ttl(key);
|
||||
} catch (error) {
|
||||
logger.error('Cache TTL check error', {
|
||||
url,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all Netflix content cache
|
||||
*/
|
||||
static async clearAll(): Promise<void> {
|
||||
try {
|
||||
const keys = await redis.keys(`${CACHE_PREFIX}*`);
|
||||
|
||||
if (keys.length > 0) {
|
||||
await redis.del(...keys);
|
||||
logger.info('Cache cleared', { count: keys.length });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Cache clear error', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CacheService;
|
||||
Reference in New Issue
Block a user