项目文件夹

文件
wehub-resource-sync 98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:40:49 +08:00

248 行
7.4 KiB
TypeScript

import { AgentState, Metadata, MachineMetadata } from '../storageTypes';
import { DecryptedMessage } from '../storageTypes';
interface CacheEntry<T> {
data: T;
accessTime: number;
}
/**
* In-memory cache for decrypted session data to avoid expensive re-decryption
* Uses sessionId + version as keys for agent state and metadata
* Uses messageId as key for messages (immutable)
*/
export class EncryptionCache {
private agentStateCache = new Map<string, CacheEntry<AgentState>>();
private metadataCache = new Map<string, CacheEntry<Metadata>>();
private messageCache = new Map<string, CacheEntry<DecryptedMessage>>();
private machineMetadataCache = new Map<string, CacheEntry<MachineMetadata>>();
private daemonStateCache = new Map<string, CacheEntry<any>>();
// Configuration
private readonly maxAgentStates = 1000;
private readonly maxMetadata = 1000;
private readonly maxMessages = 1000;
private readonly maxMachineMetadata = 500;
private readonly maxDaemonStates = 500;
/**
* Get cached agent state for a session
*/
getCachedAgentState(sessionId: string, version: number): AgentState | null {
const key = `${sessionId}:${version}`;
const entry = this.agentStateCache.get(key);
if (entry) {
entry.accessTime = Date.now();
return entry.data;
}
return null;
}
/**
* Cache agent state for a session
*/
setCachedAgentState(sessionId: string, version: number, data: AgentState): void {
const key = `${sessionId}:${version}`;
this.agentStateCache.set(key, {
data,
accessTime: Date.now()
});
// Evict if over limit
this.evictOldest(this.agentStateCache, this.maxAgentStates);
}
/**
* Get cached metadata for a session
*/
getCachedMetadata(sessionId: string, version: number): Metadata | null {
const key = `${sessionId}:${version}`;
const entry = this.metadataCache.get(key);
if (entry) {
entry.accessTime = Date.now();
return entry.data;
}
return null;
}
/**
* Cache metadata for a session
*/
setCachedMetadata(sessionId: string, version: number, data: Metadata): void {
const key = `${sessionId}:${version}`;
this.metadataCache.set(key, {
data,
accessTime: Date.now()
});
// Evict if over limit
this.evictOldest(this.metadataCache, this.maxMetadata);
}
/**
* Get cached decrypted message
*/
getCachedMessage(messageId: string): DecryptedMessage | null {
const entry = this.messageCache.get(messageId);
if (entry) {
entry.accessTime = Date.now();
return entry.data;
}
return null;
}
/**
* Cache decrypted message
*/
setCachedMessage(messageId: string, data: DecryptedMessage): void {
this.messageCache.set(messageId, {
data,
accessTime: Date.now()
});
// Evict if over limit
this.evictOldest(this.messageCache, this.maxMessages);
}
/**
* Get cached machine metadata
*/
getCachedMachineMetadata(machineId: string, version: number): MachineMetadata | null {
const key = `${machineId}:${version}`;
const entry = this.machineMetadataCache.get(key);
if (entry) {
entry.accessTime = Date.now();
return entry.data;
}
return null;
}
/**
* Cache machine metadata
*/
setCachedMachineMetadata(machineId: string, version: number, data: MachineMetadata): void {
const key = `${machineId}:${version}`;
this.machineMetadataCache.set(key, {
data,
accessTime: Date.now()
});
// Evict if over limit
this.evictOldest(this.machineMetadataCache, this.maxMachineMetadata);
}
/**
* Get cached daemon state
*/
getCachedDaemonState(machineId: string, version: number): any | undefined {
const key = `${machineId}:${version}`;
const entry = this.daemonStateCache.get(key);
if (entry) {
entry.accessTime = Date.now();
return entry.data;
}
return undefined;
}
/**
* Cache daemon state (including null values)
*/
setCachedDaemonState(machineId: string, version: number, data: any): void {
const key = `${machineId}:${version}`;
this.daemonStateCache.set(key, {
data,
accessTime: Date.now()
});
// Evict if over limit
this.evictOldest(this.daemonStateCache, this.maxDaemonStates);
}
/**
* Clear all cache entries for a specific machine
*/
clearMachineCache(machineId: string): void {
// Clear machine metadata and daemon state for this machine (all versions)
for (const key of this.machineMetadataCache.keys()) {
if (key.startsWith(`${machineId}:`)) {
this.machineMetadataCache.delete(key);
}
}
for (const key of this.daemonStateCache.keys()) {
if (key.startsWith(`${machineId}:`)) {
this.daemonStateCache.delete(key);
}
}
}
/**
* Clear all cache entries for a specific session
*/
clearSessionCache(sessionId: string): void {
// Clear agent state and metadata for this session (all versions)
for (const key of this.agentStateCache.keys()) {
if (key.startsWith(`${sessionId}:`)) {
this.agentStateCache.delete(key);
}
}
for (const key of this.metadataCache.keys()) {
if (key.startsWith(`${sessionId}:`)) {
this.metadataCache.delete(key);
}
}
// Note: We don't clear messages as they're immutable and session-agnostic
}
/**
* Clear all cached data
*/
clearAll(): void {
this.agentStateCache.clear();
this.metadataCache.clear();
this.messageCache.clear();
this.machineMetadataCache.clear();
this.daemonStateCache.clear();
}
/**
* Get cache statistics for debugging
*/
getStats() {
return {
agentStates: this.agentStateCache.size,
metadata: this.metadataCache.size,
messages: this.messageCache.size,
machineMetadata: this.machineMetadataCache.size,
daemonStates: this.daemonStateCache.size,
totalEntries: this.agentStateCache.size + this.metadataCache.size + this.messageCache.size +
this.machineMetadataCache.size + this.daemonStateCache.size
};
}
/**
* Evict oldest entries when cache exceeds limit (LRU eviction)
*/
private evictOldest<T>(cache: Map<string, CacheEntry<T>>, maxSize: number): void {
if (cache.size <= maxSize) {
return;
}
// Find oldest entry by access time
let oldestKey: string | null = null;
let oldestTime = Infinity;
for (const [key, entry] of cache.entries()) {
if (entry.accessTime < oldestTime) {
oldestTime = entry.accessTime;
oldestKey = key;
}
}
if (oldestKey) {
cache.delete(oldestKey);
}
}
}