synthia-cache-system
Version:
Synthia Engine Cache System - 核心缓存系统实现,提供多级缓存、版本管理、性能监控等功能
1,562 lines (1,555 loc) • 89.8 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
CacheCompressor: () => CacheCompressor,
CacheManagerWithPlugins: () => CacheManagerWithPlugins,
CacheMetricsCollector: () => CacheMetricsCollector,
CachePluginManager: () => CachePluginManager,
CacheStrategyManager: () => CacheStrategyManager,
CacheVersionManager: () => CacheVersionManager,
CloudCache: () => CloudCache,
HashManager: () => HashManager,
HotStartOptimizer: () => HotStartOptimizer,
LocalCache: () => LocalCache,
SynthiaCacheManager: () => SynthiaCacheManager,
createHotStartOptimizer: () => createHotStartOptimizer,
hotStartOptimizer: () => hotStartOptimizer
});
module.exports = __toCommonJS(src_exports);
// src/local-cache.ts
var import_fs_extra = __toESM(require("fs-extra"));
var import_path = require("path");
var import_chalk = __toESM(require("chalk"));
var import_ora = __toESM(require("ora"));
var LocalCache = class {
constructor(cacheDir = ".synthia-cache", config) {
this.spinner = (0, import_ora.default)();
this.stats = {
totalItems: 0,
totalSize: 0,
hits: 0,
misses: 0,
hitRate: 0,
avgAccessTime: 0,
topItems: []
};
this.cacheDir = cacheDir;
this.config = {
dir: cacheDir,
maxSize: 100 * 1024 * 1024,
// 100MB
ttl: 7 * 24 * 60 * 60 * 1e3,
// 7天
compression: false,
...config
};
this.ensureCacheDir();
this.loadStats();
}
/**
* 设置缓存
*/
async set(key, value, meta = {}) {
this.spinner.start(`\u8BBE\u7F6E\u672C\u5730\u7F13\u5B58: ${key}`);
try {
const startTime = Date.now();
const cacheItem = {
key,
value,
meta: {
hash: meta.hash || this.calculateObjectHash(value),
size: meta.size || JSON.stringify(value).length,
expiresAt: meta.expiresAt || Date.now() + this.config.ttl,
dependencies: meta.dependencies || [],
tags: meta.tags || [],
version: meta.version || "1.0.0"
},
createdAt: Date.now(),
lastAccessedAt: Date.now(),
accessCount: 0
};
const cachePath = this.getCachePath(key);
import_fs_extra.default.writeFileSync(cachePath, JSON.stringify(cacheItem, null, 2));
this.updateStats("set", key, Date.now() - startTime, true);
this.spinner.succeed(`\u672C\u5730\u7F13\u5B58\u8BBE\u7F6E\u5B8C\u6210: ${key}`);
} catch (error) {
this.spinner.fail(`\u672C\u5730\u7F13\u5B58\u8BBE\u7F6E\u5931\u8D25: ${key}`);
console.error(import_chalk.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
this.updateStats(
"set",
key,
0,
false,
error instanceof Error ? error.message : "Unknown error"
);
}
}
/**
* 获取缓存
*/
async get(key) {
this.spinner.start(`\u83B7\u53D6\u672C\u5730\u7F13\u5B58: ${key}`);
try {
const startTime = Date.now();
const cachePath = this.getCachePath(key);
if (!import_fs_extra.default.existsSync(cachePath)) {
this.spinner.warn(`\u7F13\u5B58\u4E0D\u5B58\u5728: ${key}`);
this.updateStats("get", key, Date.now() - startTime, false);
return null;
}
const cacheItem = JSON.parse(
import_fs_extra.default.readFileSync(cachePath, "utf-8")
);
if (cacheItem.meta.expiresAt < Date.now()) {
this.spinner.warn(`\u7F13\u5B58\u5DF2\u8FC7\u671F: ${key}`);
await this.delete(key);
this.updateStats("get", key, Date.now() - startTime, false);
return null;
}
cacheItem.lastAccessedAt = Date.now();
cacheItem.accessCount++;
import_fs_extra.default.writeFileSync(cachePath, JSON.stringify(cacheItem, null, 2));
this.spinner.succeed(`\u672C\u5730\u7F13\u5B58\u83B7\u53D6\u6210\u529F: ${key}`);
this.updateStats("get", key, Date.now() - startTime, true);
return cacheItem;
} catch (error) {
this.spinner.fail(`\u672C\u5730\u7F13\u5B58\u83B7\u53D6\u5931\u8D25: ${key}`);
console.error(import_chalk.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
this.updateStats(
"get",
key,
0,
false,
error instanceof Error ? error.message : "Unknown error"
);
return null;
}
}
/**
* 删除缓存
*/
async delete(key) {
try {
const startTime = Date.now();
const cachePath = this.getCachePath(key);
if (import_fs_extra.default.existsSync(cachePath)) {
require("fs").unlinkSync(cachePath);
this.updateStats("delete", key, Date.now() - startTime, true);
console.log(import_chalk.default.green(`\u7F13\u5B58\u5DF2\u5220\u9664: ${key}`));
} else {
this.updateStats("delete", key, Date.now() - startTime, false);
}
} catch (error) {
console.error(import_chalk.default.red("\u5220\u9664\u7F13\u5B58\u5931\u8D25:"), error);
this.updateStats(
"delete",
key,
0,
false,
error instanceof Error ? error.message : "Unknown error"
);
}
}
/**
* 清空所有缓存
*/
async clear() {
this.spinner.start("\u6E05\u7A7A\u672C\u5730\u7F13\u5B58...");
try {
const startTime = Date.now();
if (import_fs_extra.default.existsSync(this.cacheDir)) {
const files = import_fs_extra.default.readdirSync(this.cacheDir);
for (const file of files) {
const filePath = (0, import_path.join)(this.cacheDir, file);
const stats = import_fs_extra.default.statSync(filePath);
if (stats.isFile()) {
require("fs").unlinkSync(filePath);
} else if (stats.isDirectory()) {
require("fs").rmSync(filePath, { recursive: true, force: true });
}
}
}
this.stats = {
totalItems: 0,
totalSize: 0,
hits: 0,
misses: 0,
hitRate: 0,
avgAccessTime: 0,
topItems: []
};
this.saveStats();
this.spinner.succeed("\u672C\u5730\u7F13\u5B58\u5DF2\u6E05\u7A7A");
this.updateStats("clear", "", Date.now() - startTime, true);
} catch (error) {
this.spinner.fail("\u6E05\u7A7A\u672C\u5730\u7F13\u5B58\u5931\u8D25");
console.error(import_chalk.default.red("\u6E05\u7A7A\u9519\u8BEF:"), error);
this.updateStats(
"clear",
"",
0,
false,
error instanceof Error ? error.message : "Unknown error"
);
}
}
/**
* 检查缓存是否存在
*/
async has(key) {
const cachePath = this.getCachePath(key);
return import_fs_extra.default.existsSync(cachePath);
}
/**
* 获取缓存统计信息
*/
async getStats() {
await this.refreshStats();
return { ...this.stats };
}
/**
* 获取所有缓存键
*/
async keys() {
if (!import_fs_extra.default.existsSync(this.cacheDir)) {
return [];
}
const files = import_fs_extra.default.readdirSync(this.cacheDir);
return files.filter((file) => file.endsWith(".cache")).map((file) => file.replace(".cache", ""));
}
/**
* 获取缓存大小
*/
async size() {
await this.refreshStats();
return this.stats.totalSize;
}
/**
* 获取缓存路径
*/
getCachePath(key) {
return (0, import_path.join)(this.cacheDir, `${key}.cache`);
}
/**
* 确保缓存目录存在
*/
ensureCacheDir() {
if (!import_fs_extra.default.existsSync(this.cacheDir)) {
import_fs_extra.default.mkdirSync(this.cacheDir, { recursive: true });
}
}
/**
* 更新统计信息
*/
updateStats(type, _key, duration, success, _error) {
if (type === "get") {
if (success) {
this.stats.hits++;
} else {
this.stats.misses++;
}
}
const total = this.stats.hits + this.stats.misses;
this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;
if (type === "get" && success) {
const totalTime = this.stats.avgAccessTime * (this.stats.hits - 1) + duration;
this.stats.avgAccessTime = totalTime / this.stats.hits;
}
this.saveStats();
}
/**
* 刷新统计信息
*/
async refreshStats() {
if (!import_fs_extra.default.existsSync(this.cacheDir)) {
return;
}
const files = import_fs_extra.default.readdirSync(this.cacheDir);
const cacheFiles = files.filter((file) => file.endsWith(".cache"));
let totalSize = 0;
const topItems = [];
for (const file of cacheFiles) {
try {
const cachePath = (0, import_path.join)(this.cacheDir, file);
const cacheItem = JSON.parse(
import_fs_extra.default.readFileSync(cachePath, "utf-8")
);
totalSize += cacheItem.meta.size;
topItems.push({
key: cacheItem.key,
accessCount: cacheItem.accessCount,
size: cacheItem.meta.size
});
} catch (error) {
continue;
}
}
this.stats.totalItems = cacheFiles.length;
this.stats.totalSize = totalSize;
this.stats.topItems = topItems.sort((a, b) => b.accessCount - a.accessCount).slice(0, 10);
}
/**
* 加载统计信息
*/
loadStats() {
const statsPath = (0, import_path.join)(this.cacheDir, ".stats.json");
if (import_fs_extra.default.existsSync(statsPath)) {
try {
const statsData = JSON.parse(import_fs_extra.default.readFileSync(statsPath, "utf-8"));
this.stats = { ...this.stats, ...statsData };
} catch (error) {
}
}
}
/**
* 保存统计信息
*/
saveStats() {
const statsPath = (0, import_path.join)(this.cacheDir, ".stats.json");
import_fs_extra.default.writeFileSync(statsPath, JSON.stringify(this.stats, null, 2));
}
/**
* 计算对象哈希
*/
calculateObjectHash(obj) {
const hash = require("crypto").createHash("sha256");
hash.update(JSON.stringify(obj));
return hash.digest("hex");
}
};
// src/cloud-cache.ts
var import_client_s3 = require("@aws-sdk/client-s3");
var import_crypto = require("crypto");
var import_chalk2 = __toESM(require("chalk"));
var import_ora2 = __toESM(require("ora"));
var CloudCache = class {
constructor(config) {
this.spinner = (0, import_ora2.default)();
this.bucket = config.bucket;
this.prefix = "synthia-cache/";
this.client = new import_client_s3.S3Client({
region: config.region,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.accessKeySecret
},
endpoint: config.endpoint
});
}
/**
* 获取缓存
*/
async get(key) {
this.spinner.start(`\u4ECE\u4E91\u7AEF\u83B7\u53D6\u7F13\u5B58: ${key}`);
try {
const objectKey = this.getObjectKey(key);
const command = new import_client_s3.GetObjectCommand({
Bucket: this.bucket,
Key: objectKey
});
const response = await this.client.send(command);
if (!response.Body) {
this.spinner.warn(`\u4E91\u7AEF\u7F13\u5B58\u4E0D\u5B58\u5728: ${key}`);
return null;
}
const chunks = [];
const reader = response.Body.transformToWebStream().getReader();
while (true) {
const { done, value } = await reader.read();
if (done)
break;
chunks.push(value);
}
const buffer = Buffer.concat(chunks);
const data = JSON.parse(buffer.toString());
this.spinner.succeed(`\u4E91\u7AEF\u7F13\u5B58\u83B7\u53D6\u6210\u529F: ${key}`);
return data;
} catch (error) {
this.spinner.fail(`\u4E91\u7AEF\u7F13\u5B58\u83B7\u53D6\u5931\u8D25: ${key}`);
console.error(import_chalk2.default.red("\u4E91\u7AEF\u7F13\u5B58\u9519\u8BEF:"), error);
return null;
}
}
/**
* 设置缓存
*/
async set(key, value, meta) {
this.spinner.start(`\u8BBE\u7F6E\u4E91\u7AEF\u7F13\u5B58: ${key}`);
try {
const cacheItem = {
key,
value,
meta: {
hash: meta.hash || this.calculateHash(value),
size: meta.size || JSON.stringify(value).length,
expiresAt: meta.expiresAt || Date.now() + 7 * 24 * 60 * 60 * 1e3,
// 7天
dependencies: meta.dependencies || [],
tags: meta.tags || [],
version: meta.version || "1.0.0"
},
createdAt: Date.now(),
lastAccessedAt: Date.now(),
accessCount: 0
};
const objectKey = this.getObjectKey(key);
const command = new import_client_s3.PutObjectCommand({
Bucket: this.bucket,
Key: objectKey,
Body: JSON.stringify(cacheItem),
ContentType: "application/json",
Metadata: {
"synthia-cache-key": key,
"synthia-cache-version": cacheItem.meta.version,
"synthia-cache-hash": cacheItem.meta.hash
}
});
await this.client.send(command);
this.spinner.succeed(`\u4E91\u7AEF\u7F13\u5B58\u8BBE\u7F6E\u5B8C\u6210: ${key}`);
} catch (error) {
this.spinner.fail(`\u4E91\u7AEF\u7F13\u5B58\u8BBE\u7F6E\u5931\u8D25: ${key}`);
console.error(import_chalk2.default.red("\u4E91\u7AEF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 删除缓存
*/
async delete(key) {
this.spinner.start(`\u5220\u9664\u4E91\u7AEF\u7F13\u5B58: ${key}`);
try {
const objectKey = this.getObjectKey(key);
const command = new import_client_s3.DeleteObjectCommand({
Bucket: this.bucket,
Key: objectKey
});
await this.client.send(command);
this.spinner.succeed(`\u4E91\u7AEF\u7F13\u5B58\u5220\u9664\u5B8C\u6210: ${key}`);
} catch (error) {
this.spinner.fail(`\u4E91\u7AEF\u7F13\u5B58\u5220\u9664\u5931\u8D25: ${key}`);
console.error(import_chalk2.default.red("\u4E91\u7AEF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 清空缓存
*/
async clear() {
this.spinner.start("\u6E05\u7A7A\u4E91\u7AEF\u7F13\u5B58...");
try {
const command = new import_client_s3.ListObjectsV2Command({
Bucket: this.bucket,
Prefix: this.prefix
});
const response = await this.client.send(command);
if (response.Contents) {
const deletePromises = response.Contents.map(
(obj) => this.client.send(
new import_client_s3.DeleteObjectCommand({
Bucket: this.bucket,
Key: obj.Key
})
)
);
await Promise.all(deletePromises);
}
this.spinner.succeed("\u4E91\u7AEF\u7F13\u5B58\u5DF2\u6E05\u7A7A");
} catch (error) {
this.spinner.fail("\u6E05\u7A7A\u4E91\u7AEF\u7F13\u5B58\u5931\u8D25");
console.error(import_chalk2.default.red("\u4E91\u7AEF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 检查缓存是否存在
*/
async has(key) {
try {
const objectKey = this.getObjectKey(key);
const command = new import_client_s3.HeadObjectCommand({
Bucket: this.bucket,
Key: objectKey
});
await this.client.send(command);
return true;
} catch (error) {
return false;
}
}
/**
* 获取缓存统计信息
*/
async getStats() {
this.spinner.start("\u83B7\u53D6\u4E91\u7AEF\u7F13\u5B58\u7EDF\u8BA1...");
try {
const command = new import_client_s3.ListObjectsV2Command({
Bucket: this.bucket,
Prefix: this.prefix
});
const response = await this.client.send(command);
let totalItems = 0;
let totalSize = 0;
const topItems = [];
if (response.Contents) {
totalItems = response.Contents.length;
totalSize = response.Contents.reduce(
(sum, obj) => sum + (obj.Size || 0),
0
);
const sortedItems = response.Contents.sort(
(a, b) => (b.Size || 0) - (a.Size || 0)
).slice(0, 10);
for (const item of sortedItems) {
if (item.Key) {
const key = this.extractKeyFromObjectKey(item.Key);
topItems.push({
key,
accessCount: 0,
// 云端无法获取访问次数
size: item.Size || 0
});
}
}
}
const stats = {
totalItems,
totalSize,
hits: 0,
// 云端无法统计命中率
misses: 0,
hitRate: 0,
avgAccessTime: 0,
topItems
};
this.spinner.succeed("\u4E91\u7AEF\u7F13\u5B58\u7EDF\u8BA1\u83B7\u53D6\u5B8C\u6210");
return stats;
} catch (error) {
this.spinner.fail("\u83B7\u53D6\u4E91\u7AEF\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25");
console.error(import_chalk2.default.red("\u4E91\u7AEF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 获取所有缓存键
*/
async keys() {
try {
const command = new import_client_s3.ListObjectsV2Command({
Bucket: this.bucket,
Prefix: this.prefix
});
const response = await this.client.send(command);
if (!response.Contents) {
return [];
}
return response.Contents.map((obj) => obj.Key).filter((key) => key !== void 0).map((key) => this.extractKeyFromObjectKey(key));
} catch (error) {
console.error(import_chalk2.default.red("\u83B7\u53D6\u7F13\u5B58\u952E\u5931\u8D25:"), error);
return [];
}
}
/**
* 获取缓存大小
*/
async size() {
const stats = await this.getStats();
return stats.totalSize;
}
/**
* 同步到云端
*/
async sync(key) {
this.spinner.start(`\u540C\u6B65\u7F13\u5B58\u5230\u4E91\u7AEF: ${key}`);
try {
this.spinner.succeed(`\u7F13\u5B58\u540C\u6B65\u5B8C\u6210: ${key}`);
} catch (error) {
this.spinner.fail(`\u7F13\u5B58\u540C\u6B65\u5931\u8D25: ${key}`);
console.error(import_chalk2.default.red("\u540C\u6B65\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 从云端拉取
*/
async pull(key) {
return this.get(key);
}
/**
* 批量同步
*/
async batchSync(keys) {
this.spinner.start(`\u6279\u91CF\u540C\u6B65 ${keys.length} \u4E2A\u7F13\u5B58\u5230\u4E91\u7AEF...`);
try {
const syncPromises = keys.map((key) => this.sync(key));
await Promise.all(syncPromises);
this.spinner.succeed(`\u6279\u91CF\u540C\u6B65\u5B8C\u6210: ${keys.length} \u4E2A\u7F13\u5B58`);
} catch (error) {
this.spinner.fail("\u6279\u91CF\u540C\u6B65\u5931\u8D25");
console.error(import_chalk2.default.red("\u6279\u91CF\u540C\u6B65\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 获取对象键
*/
getObjectKey(key) {
return `${this.prefix}${key}.json`;
}
/**
* 从对象键提取缓存键
*/
extractKeyFromObjectKey(objectKey) {
return objectKey.replace(this.prefix, "").replace(".json", "");
}
/**
* 计算哈希值
*/
calculateHash(value) {
const hash = (0, import_crypto.createHash)("sha256");
hash.update(JSON.stringify(value));
return hash.digest("hex");
}
};
// src/hash-manager.ts
var import_crypto2 = require("crypto");
var import_fs_extra2 = __toESM(require("fs-extra"));
var import_path2 = require("path");
var HashManager = class {
constructor(_cacheDir = ".synthia-cache") {
this.hashAlgorithm = "sha256";
}
/**
* 计算文件哈希
*/
calculateFileHash(filePath) {
try {
const content = import_fs_extra2.default.readFileSync(filePath);
const hash = (0, import_crypto2.createHash)(this.hashAlgorithm);
hash.update(content);
return hash.digest("hex");
} catch (error) {
console.warn(`\u65E0\u6CD5\u8BA1\u7B97\u6587\u4EF6\u54C8\u5E0C: ${filePath}`, error);
return "";
}
}
/**
* 计算目录哈希
*/
calculateDirectoryHash(dirPath, patterns = ["**/*"]) {
const hash = (0, import_crypto2.createHash)(this.hashAlgorithm);
try {
const files = this.getFilesInDirectory(dirPath, patterns);
files.sort();
for (const file of files) {
const filePath = (0, import_path2.join)(dirPath, file);
const stats = import_fs_extra2.default.statSync(filePath);
const content = import_fs_extra2.default.readFileSync(filePath);
hash.update(file);
hash.update(stats.size.toString());
hash.update(stats.mtime.getTime().toString());
hash.update(content);
}
return hash.digest("hex");
} catch (error) {
console.warn(`\u65E0\u6CD5\u8BA1\u7B97\u76EE\u5F55\u54C8\u5E0C: ${dirPath}`, error);
return "";
}
}
/**
* 计算依赖哈希
*/
calculateDependenciesHash(dependencies) {
const hash = (0, import_crypto2.createHash)(this.hashAlgorithm);
const sortedDeps = Object.keys(dependencies).sort();
for (const key of sortedDeps) {
hash.update(key);
hash.update(dependencies[key]);
}
return hash.digest("hex");
}
/**
* 生成缓存键
*/
generateCacheKey(projectPath, dependencies, buildConfig) {
const hash = (0, import_crypto2.createHash)(this.hashAlgorithm);
const projectHash = this.calculateDirectoryHash(projectPath);
hash.update(projectHash);
const depsHash = this.calculateDependenciesHash(dependencies);
hash.update(depsHash);
const configHash = this.calculateObjectHash(buildConfig);
hash.update(configHash);
return hash.digest("hex");
}
/**
* 创建缓存信息
*/
createCacheInfo(hash, size, dependencies) {
return {
hash,
size,
lastModified: Date.now(),
dependencies
};
}
/**
* 验证缓存有效性
*/
validateCache(cacheInfo, currentHash) {
return cacheInfo.hash === currentHash;
}
/**
* 获取目录中的文件
*/
getFilesInDirectory(dirPath, patterns) {
const { glob } = require("glob");
const files = [];
for (const pattern of patterns) {
const matches = glob.sync(pattern, {
cwd: dirPath,
nodir: true,
ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"]
});
files.push(...matches);
}
return [...new Set(files)];
}
/**
* 计算对象哈希
*/
calculateObjectHash(obj) {
const hash = (0, import_crypto2.createHash)(this.hashAlgorithm);
const str = JSON.stringify(obj, Object.keys(obj).sort());
hash.update(str);
return hash.digest("hex");
}
};
// src/cache-manager.ts
var import_chalk3 = __toESM(require("chalk"));
var import_ora3 = __toESM(require("ora"));
var SynthiaCacheManager = class {
constructor(config) {
this.spinner = (0, import_ora3.default)();
this.config = config;
this.localCache = new LocalCache(config.local.dir, config.local);
if (config.cloud.enabled) {
this.cloudCache = new CloudCache(config.cloud);
}
}
/**
* 获取缓存
*/
async get(key) {
this.spinner.start(`\u83B7\u53D6\u7F13\u5B58: ${key}`);
try {
if (this.config.strategy.localFirst) {
const localItem = await this.localCache.get(key);
if (localItem) {
this.spinner.succeed(`\u672C\u5730\u7F13\u5B58\u547D\u4E2D: ${key}`);
return localItem.value;
}
if (this.cloudCache) {
const cloudItem = await this.cloudCache.get(key);
if (cloudItem) {
await this.localCache.set(key, cloudItem.value, cloudItem.meta);
this.spinner.succeed(`\u4E91\u7AEF\u7F13\u5B58\u547D\u4E2D\u5E76\u540C\u6B65\u5230\u672C\u5730: ${key}`);
return cloudItem.value;
}
}
} else {
if (this.cloudCache) {
const cloudItem = await this.cloudCache.get(key);
if (cloudItem) {
await this.localCache.set(key, cloudItem.value, cloudItem.meta);
this.spinner.succeed(`\u4E91\u7AEF\u7F13\u5B58\u547D\u4E2D\u5E76\u540C\u6B65\u5230\u672C\u5730: ${key}`);
return cloudItem.value;
}
}
const localItem = await this.localCache.get(key);
if (localItem) {
this.spinner.succeed(`\u672C\u5730\u7F13\u5B58\u547D\u4E2D: ${key}`);
return localItem.value;
}
}
this.spinner.warn(`\u7F13\u5B58\u672A\u547D\u4E2D: ${key}`);
return null;
} catch (error) {
this.spinner.fail(`\u83B7\u53D6\u7F13\u5B58\u5931\u8D25: ${key}`);
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
return null;
}
}
/**
* 设置缓存
*/
async set(key, value, options = {}) {
this.spinner.start(`\u8BBE\u7F6E\u7F13\u5B58: ${key}`);
try {
await this.localCache.set(key, value, options);
if (this.cloudCache && this.config.strategy.autoSync) {
await this.cloudCache.set(key, value, options);
}
this.spinner.succeed(`\u7F13\u5B58\u8BBE\u7F6E\u5B8C\u6210: ${key}`);
} catch (error) {
this.spinner.fail(`\u7F13\u5B58\u8BBE\u7F6E\u5931\u8D25: ${key}`);
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 批量设置缓存
*/
async setBatch(items) {
this.spinner.start(`\u6279\u91CF\u8BBE\u7F6E\u7F13\u5B58 (${items.length} \u9879)`);
try {
const localPromises = items.map(
(item) => this.localCache.set(item.key, item.value, item.options || {})
);
await Promise.all(localPromises);
if (this.cloudCache && this.config.strategy.autoSync) {
const cloudPromises = items.map(
(item) => this.cloudCache.set(item.key, item.value, item.options || {})
);
await Promise.all(cloudPromises);
}
this.spinner.succeed(`\u6279\u91CF\u7F13\u5B58\u8BBE\u7F6E\u5B8C\u6210 (${items.length} \u9879)`);
} catch (error) {
this.spinner.fail(`\u6279\u91CF\u7F13\u5B58\u8BBE\u7F6E\u5931\u8D25`);
console.error(import_chalk3.default.red("\u6279\u91CF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 事务性设置缓存
*/
async setTransaction(operations) {
this.spinner.start(`\u6267\u884C\u7F13\u5B58\u4E8B\u52A1 (${operations.length} \u4E2A\u64CD\u4F5C)`);
try {
for (const operation of operations) {
if (operation.type === "set") {
await this.localCache.set(
operation.key,
operation.value,
operation.options || {}
);
} else if (operation.type === "delete") {
await this.localCache.delete(operation.key);
}
}
if (this.cloudCache && this.config.strategy.autoSync) {
for (const operation of operations) {
if (operation.type === "set") {
await this.cloudCache.set(
operation.key,
operation.value,
operation.options || {}
);
} else if (operation.type === "delete") {
await this.cloudCache.delete(operation.key);
}
}
}
this.spinner.succeed(`\u7F13\u5B58\u4E8B\u52A1\u6267\u884C\u5B8C\u6210 (${operations.length} \u4E2A\u64CD\u4F5C)`);
} catch (error) {
this.spinner.fail(`\u7F13\u5B58\u4E8B\u52A1\u6267\u884C\u5931\u8D25`);
console.error(import_chalk3.default.red("\u4E8B\u52A1\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 批量获取缓存
*/
async getBatch(keys) {
this.spinner.start(`\u6279\u91CF\u83B7\u53D6\u7F13\u5B58 (${keys.length} \u9879)`);
try {
const results = /* @__PURE__ */ new Map();
const localPromises = keys.map(async (key) => {
const item = await this.localCache.get(key);
if (item) {
results.set(key, item.value);
}
return { key, item };
});
const localResults = await Promise.all(localPromises);
if (this.cloudCache) {
const missedKeys = localResults.filter((result) => !result.item).map((result) => result.key);
if (missedKeys.length > 0) {
const cloudPromises = missedKeys.map(async (key) => {
const item = await this.cloudCache.get(key);
if (item) {
await this.localCache.set(key, item.value, item.meta);
results.set(key, item.value);
}
return { key, item };
});
await Promise.all(cloudPromises);
}
}
this.spinner.succeed(
`\u6279\u91CF\u7F13\u5B58\u83B7\u53D6\u5B8C\u6210 (${keys.length} \u9879, \u547D\u4E2D ${results.size} \u9879)`
);
return results;
} catch (error) {
this.spinner.fail(`\u6279\u91CF\u7F13\u5B58\u83B7\u53D6\u5931\u8D25`);
console.error(import_chalk3.default.red("\u6279\u91CF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 删除缓存
*/
async delete(key) {
this.spinner.start(`\u5220\u9664\u7F13\u5B58: ${key}`);
try {
await this.localCache.delete(key);
if (this.cloudCache) {
await this.cloudCache.delete(key);
}
this.spinner.succeed(`\u7F13\u5B58\u5220\u9664\u5B8C\u6210: ${key}`);
} catch (error) {
this.spinner.fail(`\u5220\u9664\u7F13\u5B58\u5931\u8D25: ${key}`);
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 批量删除缓存
*/
async deleteBatch(keys) {
this.spinner.start(`\u6279\u91CF\u5220\u9664\u7F13\u5B58 (${keys.length} \u9879)`);
try {
const localPromises = keys.map((key) => this.localCache.delete(key));
await Promise.all(localPromises);
if (this.cloudCache && this.config.strategy.autoSync) {
const cloudPromises = keys.map((key) => this.cloudCache.delete(key));
await Promise.all(cloudPromises);
}
this.spinner.succeed(`\u6279\u91CF\u7F13\u5B58\u5220\u9664\u5B8C\u6210 (${keys.length} \u9879)`);
} catch (error) {
this.spinner.fail(`\u6279\u91CF\u7F13\u5B58\u5220\u9664\u5931\u8D25`);
console.error(import_chalk3.default.red("\u6279\u91CF\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 清空缓存
*/
async clear() {
this.spinner.start("\u6E05\u7A7A\u6240\u6709\u7F13\u5B58...");
try {
await this.localCache.clear();
if (this.cloudCache) {
await this.cloudCache.clear();
}
this.spinner.succeed("\u6240\u6709\u7F13\u5B58\u5DF2\u6E05\u7A7A");
} catch (error) {
this.spinner.fail("\u6E05\u7A7A\u7F13\u5B58\u5931\u8D25");
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 获取缓存统计
*/
async getStats() {
this.spinner.start("\u83B7\u53D6\u7F13\u5B58\u7EDF\u8BA1...");
try {
const localStats = await this.localCache.getStats();
if (this.cloudCache) {
const cloudStats = await this.cloudCache.getStats();
const combinedStats = {
totalItems: localStats.totalItems + cloudStats.totalItems,
totalSize: localStats.totalSize + cloudStats.totalSize,
hits: localStats.hits + cloudStats.hits,
misses: localStats.misses + cloudStats.misses,
hitRate: localStats.hitRate,
// 使用本地命中率
avgAccessTime: localStats.avgAccessTime,
// 使用本地平均时间
topItems: [...localStats.topItems, ...cloudStats.topItems].sort((a, b) => b.accessCount - a.accessCount).slice(0, 10)
};
this.spinner.succeed("\u7F13\u5B58\u7EDF\u8BA1\u83B7\u53D6\u5B8C\u6210");
return combinedStats;
}
this.spinner.succeed("\u672C\u5730\u7F13\u5B58\u7EDF\u8BA1\u83B7\u53D6\u5B8C\u6210");
return localStats;
} catch (error) {
this.spinner.fail("\u83B7\u53D6\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25");
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 预热缓存
*/
async warmup(keys) {
this.spinner.start(`\u9884\u70ED ${keys.length} \u4E2A\u7F13\u5B58...`);
try {
const warmupPromises = keys.map(async (key) => {
try {
await this.get(key);
} catch (error) {
console.warn(import_chalk3.default.yellow(`\u9884\u70ED\u7F13\u5B58\u5931\u8D25: ${key}`), error);
}
});
await Promise.all(warmupPromises);
this.spinner.succeed(`\u7F13\u5B58\u9884\u70ED\u5B8C\u6210: ${keys.length} \u4E2A`);
} catch (error) {
this.spinner.fail("\u7F13\u5B58\u9884\u70ED\u5931\u8D25");
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 清理过期缓存
*/
async cleanup() {
this.spinner.start("\u6E05\u7406\u8FC7\u671F\u7F13\u5B58...");
try {
const keys = await this.localCache.keys();
let cleanedCount = 0;
for (const key of keys) {
const item = await this.localCache.get(key);
if (!item) {
await this.localCache.delete(key);
cleanedCount++;
}
}
this.spinner.succeed(`\u8FC7\u671F\u7F13\u5B58\u6E05\u7406\u5B8C\u6210: ${cleanedCount} \u4E2A`);
} catch (error) {
this.spinner.fail("\u6E05\u7406\u8FC7\u671F\u7F13\u5B58\u5931\u8D25");
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 导出缓存
*/
async export() {
this.spinner.start("\u5BFC\u51FA\u7F13\u5B58...");
try {
const keys = await this.localCache.keys();
const exportData = {
version: "1.0.0",
timestamp: Date.now(),
config: this.config,
items: []
};
for (const key of keys) {
const item = await this.localCache.get(key);
if (item) {
exportData.items.push({ key, item });
}
}
const buffer = Buffer.from(JSON.stringify(exportData, null, 2));
this.spinner.succeed(`\u7F13\u5B58\u5BFC\u51FA\u5B8C\u6210: ${buffer.length} \u5B57\u8282`);
return buffer;
} catch (error) {
this.spinner.fail("\u5BFC\u51FA\u7F13\u5B58\u5931\u8D25");
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 导入缓存
*/
async import(data) {
this.spinner.start("\u5BFC\u5165\u7F13\u5B58...");
try {
const importData = JSON.parse(data.toString());
if (importData.version !== "1.0.0") {
throw new Error(`\u4E0D\u652F\u6301\u7684\u7F13\u5B58\u7248\u672C: ${importData.version}`);
}
let importedCount = 0;
for (const { key, item } of importData.items) {
await this.localCache.set(key, item.value, item.meta);
importedCount++;
}
this.spinner.succeed(`\u7F13\u5B58\u5BFC\u5165\u5B8C\u6210: ${importedCount} \u4E2A`);
} catch (error) {
this.spinner.fail("\u5BFC\u5165\u7F13\u5B58\u5931\u8D25");
console.error(import_chalk3.default.red("\u7F13\u5B58\u9519\u8BEF:"), error);
throw error;
}
}
};
// src/cache-version-manager.ts
var import_fs_extra3 = __toESM(require("fs-extra"));
var import_path3 = require("path");
var import_crypto3 = require("crypto");
var import_chalk4 = __toESM(require("chalk"));
var import_ora4 = __toESM(require("ora"));
var CacheVersionManager = class {
constructor(versionDir = ".synthia-cache/versions") {
this.dependencyGraph = /* @__PURE__ */ new Map();
this.versionHistory = /* @__PURE__ */ new Map();
this.spinner = (0, import_ora4.default)();
this.versionDir = versionDir;
this.ensureVersionDir();
this.loadDependencyGraph();
this.loadVersionHistory();
}
/**
* 计算文件或内容的哈希值
*/
calculateHash(content) {
const hash = (0, import_crypto3.createHash)("sha256");
hash.update(content);
return hash.digest("hex");
}
/**
* 计算文件哈希值
*/
calculateFileHash(filePath) {
try {
const content = import_fs_extra3.default.readFileSync(filePath, "utf-8");
return this.calculateHash(content);
} catch (error) {
console.warn(import_chalk4.default.yellow(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${filePath}: ${error}`));
return "";
}
}
/**
* 计算依赖文件的哈希值
*/
calculateDependenciesHash(dependencies) {
const hashes = dependencies.map((dep) => this.calculateFileHash(dep)).filter(Boolean);
return this.calculateHash(hashes.join("|"));
}
/**
* 检查缓存是否有效
*/
isCacheValid(key, dependencies, currentHash) {
const cacheMeta = this.getCacheMeta(key);
if (!cacheMeta) {
return false;
}
if (cacheMeta.expiresAt < Date.now()) {
return false;
}
const currentDepsHash = this.calculateDependenciesHash(dependencies);
if (cacheMeta.dependenciesHash !== currentDepsHash) {
return false;
}
if (currentHash && cacheMeta.hash !== currentHash) {
return false;
}
return true;
}
/**
* 更新缓存版本信息
*/
updateCacheVersion(key, value, dependencies, tags = [], version = "1.0.0") {
const hash = this.calculateHash(JSON.stringify(value));
const dependenciesHash = this.calculateDependenciesHash(dependencies);
const size = JSON.stringify(value).length;
const meta = {
hash,
size,
expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1e3,
// 7天
dependencies,
tags,
version,
dependenciesHash,
createdAt: Date.now(),
lastModified: Date.now()
};
this.saveCacheMeta(key, meta);
this.updateDependencyGraph(key, dependencies);
this.updateVersionHistory(key, hash);
return meta;
}
/**
* 获取受影响的缓存键
*/
getAffectedCacheKeys(changedFiles) {
const affectedKeys = /* @__PURE__ */ new Set();
for (const file of changedFiles) {
for (const [key, deps] of this.dependencyGraph.entries()) {
if (deps.has(file)) {
affectedKeys.add(key);
}
}
}
return Array.from(affectedKeys);
}
/**
* 清理无效的缓存版本
*/
cleanupInvalidVersions() {
this.spinner.start("\u6E05\u7406\u65E0\u6548\u7684\u7F13\u5B58\u7248\u672C...");
try {
let cleanedCount = 0;
const currentTime = Date.now();
for (const [key, versions] of this.versionHistory.entries()) {
const cacheMeta = this.getCacheMeta(key);
if (!cacheMeta) {
continue;
}
const validVersions = /* @__PURE__ */ new Set([cacheMeta.hash]);
const cleanedVersions = versions.filter((version) => {
if (validVersions.has(version)) {
return true;
}
const versionPath = this.getVersionPath(key, version);
if (import_fs_extra3.default.existsSync(versionPath)) {
const stats = require("fs").statSync(versionPath);
const age = currentTime - stats.mtime.getTime();
if (age > 30 * 24 * 60 * 60 * 1e3) {
require("fs").unlinkSync(versionPath);
cleanedCount++;
return false;
}
}
return true;
});
if (cleanedVersions.length !== versions.length) {
this.versionHistory.set(key, cleanedVersions);
}
}
this.saveVersionHistory();
this.spinner.succeed(`\u6E05\u7406\u5B8C\u6210\uFF0C\u5220\u9664\u4E86 ${cleanedCount} \u4E2A\u65E0\u6548\u7248\u672C`);
} catch (error) {
this.spinner.fail("\u6E05\u7406\u65E0\u6548\u7248\u672C\u5931\u8D25");
console.error(import_chalk4.default.red("\u6E05\u7406\u9519\u8BEF:"), error);
}
}
/**
* 获取缓存统计信息
*/
getVersionStats() {
const totalKeys = this.versionHistory.size;
const totalVersions = Array.from(this.versionHistory.values()).reduce(
(sum, versions) => sum + versions.length,
0
);
const dependencyGraphSize = this.dependencyGraph.size;
const averageVersionsPerKey = totalKeys > 0 ? totalVersions / totalKeys : 0;
return {
totalKeys,
totalVersions,
dependencyGraphSize,
averageVersionsPerKey
};
}
/**
* 导出版本信息
*/
exportVersionInfo() {
const versionInfo = {
dependencyGraph: Object.fromEntries(this.dependencyGraph),
versionHistory: Object.fromEntries(this.versionHistory),
timestamp: Date.now()
};
return Buffer.from(JSON.stringify(versionInfo, null, 2));
}
/**
* 导入版本信息
*/
importVersionInfo(data) {
try {
const versionInfo = JSON.parse(data.toString());
this.dependencyGraph = new Map(
Object.entries(versionInfo.dependencyGraph)
);
this.versionHistory = new Map(Object.entries(versionInfo.versionHistory));
this.saveDependencyGraph();
this.saveVersionHistory();
console.log(import_chalk4.default.green("\u7248\u672C\u4FE1\u606F\u5BFC\u5165\u6210\u529F"));
} catch (error) {
console.error(import_chalk4.default.red("\u7248\u672C\u4FE1\u606F\u5BFC\u5165\u5931\u8D25:"), error);
throw error;
}
}
/**
* 获取缓存元信息
*/
getCacheMeta(key) {
const metaPath = (0, import_path3.join)(this.versionDir, `${key}.meta.json`);
if (!import_fs_extra3.default.existsSync(metaPath)) {
return null;
}
try {
return JSON.parse(import_fs_extra3.default.readFileSync(metaPath, "utf-8"));
} catch (error) {
return null;
}
}
/**
* 保存缓存元信息
*/
saveCacheMeta(key, meta) {
const metaPath = (0, import_path3.join)(this.versionDir, `${key}.meta.json`);
import_fs_extra3.default.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
}
/**
* 更新依赖图
*/
updateDependencyGraph(key, dependencies) {
this.dependencyGraph.set(key, new Set(dependencies));
this.saveDependencyGraph();
}
/**
* 更新版本历史
*/
updateVersionHistory(key, hash) {
const versions = this.versionHistory.get(key) || [];
if (!versions.includes(hash)) {
versions.push(hash);
this.versionHistory.set(key, versions);
this.saveVersionHistory();
}
}
/**
* 获取版本路径
*/
getVersionPath(key, version) {
return (0, import_path3.join)(this.versionDir, `${key}.${version}.cache`);
}
/**
* 确保版本目录存在
*/
ensureVersionDir() {
if (!import_fs_extra3.default.existsSync(this.versionDir)) {
import_fs_extra3.default.mkdirSync(this.versionDir, { recursive: true });
}
}
/**
* 加载依赖图
*/
loadDependencyGraph() {
const graphPath = (0, import_path3.join)(this.versionDir, "dependency-graph.json");
if (import_fs_extra3.default.existsSync(graphPath)) {
try {
const graphData = JSON.parse(import_fs_extra3.default.readFileSync(graphPath, "utf-8"));
this.dependencyGraph = new Map(Object.entries(graphData));
} catch (error) {
console.warn(import_chalk4.default.yellow("\u65E0\u6CD5\u52A0\u8F7D\u4F9D\u8D56\u56FE\uFF0C\u5C06\u91CD\u65B0\u521B\u5EFA"));
}
}
}
/**
* 保存依赖图
*/
saveDependencyGraph() {
const graphPath = (0, import_path3.join)(this.versionDir, "dependency-graph.json");
const graphData = Object.fromEntries(this.dependencyGraph);
import_fs_extra3.default.writeFileSync(graphPath, JSON.stringify(graphData, null, 2));
}
/**
* 加载版本历史
*/
loadVersionHistory() {
const historyPath = (0, import_path3.join)(this.versionDir, "version-history.json");
if (import_fs_extra3.default.existsSync(historyPath)) {
try {
const historyData = JSON.parse(import_fs_extra3.default.readFileSync(historyPath, "utf-8"));
this.versionHistory = new Map(Object.entries(historyData));
} catch (error) {
console.warn(import_chalk4.default.yellow("\u65E0\u6CD5\u52A0\u8F7D\u7248\u672C\u5386\u53F2\uFF0C\u5C06\u91CD\u65B0\u521B\u5EFA"));
}
}
}
/**
* 保存版本历史
*/
saveVersionHistory() {
const historyPath = (0, import_path3.join)(this.versionDir, "version-history.json");
const historyData = Object.fromEntries(this.versionHistory);
import_fs_extra3.default.writeFileSync(historyPath, JSON.stringify(historyData, null, 2));
}
};
// src/cache-compressor.ts
var import_zlib = require("zlib");
var import_util = require("util");
var import_chalk5 = __toESM(require("chalk"));
var import_ora5 = __toESM(require("ora"));
var gzipAsync = (0, import_util.promisify)(import_zlib.gzip);
var gunzipAsync = (0, import_util.promisify)(import_zlib.gunzip);
var CacheCompressor = class {
constructor(compressionLevel = 6) {
this.compressionLevel = 6;
// 默认压缩级别
this.spinner = (0, import_ora5.default)();
this.compressionLevel = compressionLevel;
}
/**
* 压缩缓存数据
*/
async compress(data, algorithm = "gzip") {
const serialized = this.serialize(data);
switch (algorithm) {
case "gzip":
return await this.compressGzip(serialized);
case "brotli":
return await this.compressBrotli(serialized);
case "none":
return Buffer.from(serialized);
default:
throw new Error(`\u4E0D\u652F\u6301\u7684\u538B\u7F29\u7B97\u6CD5: ${algorithm}`);
}
}
/**
* 解压缩缓存数据
*/
async decompress(buffer, algorithm = "gzip") {
let decompressed;
switch (algorithm) {
case "gzip":
decompressed = await this.decompressGzip(buffer);
break;
case "brotli":
decompressed = await this.decompressBrotli(buffer);
break;
case "none":
decompressed = buffer;
break;
default:
throw new Error(`\u4E0D\u652F\u6301\u7684\u538B\u7F29\u7B97\u6CD5: ${algorithm}`);
}
return this.deserialize(decompressed.toString());
}
/**
* 序列化数据
*/
serialize(data) {
try {
return JSON.stringify(data);
} catch (error) {
console.error(import_chalk5.default.red("\u5E8F\u5217\u5316\u5931\u8D25:"), error);
throw error;
}
}
/**
* 反序列化数据
*/
deserialize(serialized) {
try {
return JSON.parse(serialized);
} catch (error) {
console.error(import_chalk5.default.red("\u53CD\u5E8F\u5217\u5316\u5931\u8D25:"), error);
throw error;
}
}
/**
* 计算压缩比
*/
calculateCompressionRatio(originalSize, compressedSize) {
return originalSize > 0 ? (originalSize - compressedSize) / originalSize : 0;
}
/**
* 选择最佳压缩算法
*/
async selectBestCompression(data) {
this.spinner.start("\u9009\u62E9\u6700\u4F73\u538B\u7F29\u7B97\u6CD5...");
try {
const serialized = this.serialize(data);
const results = await Promise.all([
this.testCompression(serialized, "gzip"),
this.testCompression(serialized, "brotli"),
this.testCompression(serialized, "none")
]);
const bestResult = results.reduce(
(best, current) => current.ratio > best.ratio ? current : best
);
this.spinner.succeed(
`\u9009\u62E9\u538B\u7F29\u7B97\u6CD5: ${bestResult.algorithm} (\u538B\u7F29\u6BD4: ${(bestResult.ratio * 100).toFixed(2)}%)`
);
return bestResult;
} catch (error) {
this.spinner.fail("\u9009\u62E9\u538B\u7F29\u7B97\u6CD5\u5931\u8D25");
console.error(import_chalk5.default.red("\u538B\u7F29\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 批量压缩
*/
async compressBatch(items, algorithm = "gzip") {
this.spinner.start(`\u6279\u91CF\u538B\u7F29 ${items.length} \u9879\u6570\u636E...`);
try {
const compressedItems = /* @__PURE__ */ new Map();
const promises = items.map(async (item) => {
const compressed = await this.compress(item.data, algorithm);
return { key: item.key, compressed };
});
const results = await Promise.all(promises);
for (const result of results) {
compressedItems.set(result.key, result.compressed);
}
this.spinner.succeed(`\u6279\u91CF\u538B\u7F29\u5B8C\u6210 (${items.length} \u9879)`);
return compressedItems;
} catch (error) {
this.spinner.fail("\u6279\u91CF\u538B\u7F29\u5931\u8D25");
console.error(import_chalk5.default.red("\u6279\u91CF\u538B\u7F29\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 批量解压缩
*/
async decompressBatch(items, algorithm = "gzip") {
this.spinner.start(`\u6279\u91CF\u89E3\u538B\u7F29 ${items.size} \u9879\u6570\u636E...`);
try {
const decompressedItems = /* @__PURE__ */ new Map();
const promises = Array.from(items.entries()).map(
async ([key, buffer]) => {
const decompressed = await this.decompress(buffer, algorithm);
return { key, decompressed };
}
);
const results = await Promise.all(promises);
for (const result of results) {
decompressedItems.set(result.key, result.decompressed);
}
this.spinner.succeed(`\u6279\u91CF\u89E3\u538B\u7F29\u5B8C\u6210 (${items.size} \u9879)`);
return decompressedItems;
} catch (error) {
this.spinner.fail("\u6279\u91CF\u89E3\u538B\u7F29\u5931\u8D25");
console.error(import_chalk5.default.red("\u6279\u91CF\u89E3\u538B\u7F29\u9519\u8BEF:"), error);
throw error;
}
}
/**
* 测试压缩算法
*/
async testCompression(data, algorithm) {
const originalSize = Buffer.byteLength(data);
let compressed;
switch (algorithm) {
case "gzip":
compressed = await this.compressGzip(data);
break;
case "brotli":
compressed = await this.compressBrotli(data);
break;
case "none":
com