llm-agent-plugin/src/references/CacheManager.ts
2025-11-11 23:03:20 +03:00

188 lines
6.7 KiB
TypeScript
Raw 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.

/**
* Управляет кешированием файлов (внутренних, внешних, промптов).
* Сохраняет файлы в указанной папке с UUID в имени.
*/
import { TFile, normalizePath } from 'obsidian';
import LLMAgentPlugin from 'main';
import { v4 as uuidv4 } from 'uuid'; // Нужно установить: npm install uuid @types/uuid
import { getMimeType } from 'src/utils/fileUtils';
export class CacheManager {
private plugin: LLMAgentPlugin;
constructor(plugin: LLMAgentPlugin) {
this.plugin = plugin;
}
/**
* Возвращает абсолютный путь к папке кеша
*/
public getCacheFolderPath(): string {
const cacheFolder = this.plugin.settings.refCacheFolder;
// Если путь относительный, делаем его относительно vault
if (!this.isAbsolutePath(cacheFolder)) {
return this.plugin.app.vault.adapter.getBasePath() + '/' + cacheFolder;
}
return cacheFolder;
}
/**
* Проверяет, является ли путь абсолютным
*/
private isAbsolutePath(path: string): boolean {
// Windows: C:\, D:\, и т.д.
if (/^[a-zA-Z]:\\/.test(path)) return true;
// Unix: /
if (path.startsWith('/')) return true;
return false;
}
/**
* Создает папку кеша, если она не существует
*/
private async ensureCacheFolderExists(): Promise<void> {
const cachePath = this.getCacheFolderPath();
if (!window.require) return; // Web версия
const fs = window.require('fs').promises;
try {
await fs.access(cachePath);
} catch {
await fs.mkdir(cachePath, { recursive: true });
}
}
/**
* Кеширует файл из vault
*/
async cacheVaultFile(file: TFile): Promise<{ uuid: string; cachedPath: string }> {
await this.ensureCacheFolderExists();
const uuid = uuidv4();
const extension = file.extension;
const cachedFileName = `${file.basename}-${uuid}.${extension}`;
const content = await this.plugin.app.vault.readBinary(file);
const cacheFolderPath = this.getCacheFolderPath();
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
if (!window.require) {
throw new Error('Кеширование доступно только в desktop версии');
}
const fs = window.require('fs').promises;
await fs.writeFile(cachedFilePath, Buffer.from(content));
return {
uuid: uuid,
cachedPath: cachedFileName // Относительный путь
};
}
/**
* Кеширует внешний файл
*/
async cacheExternalFile(absolutePath: string): Promise<{ uuid: string; cachedPath: string; name: string; mimeType: string }> {
await this.ensureCacheFolderExists();
if (!window.require) {
throw new Error('Кеширование доступно только в desktop версии');
}
const fs = window.require('fs').promises;
const path = window.require('path');
const content = await fs.readFile(absolutePath);
const fileName = path.basename(absolutePath);
const extension = path.extname(fileName).substring(1);
const baseName = path.basename(fileName, path.extname(fileName));
const uuid = uuidv4();
const cachedFileName = `${baseName}-${uuid}.${extension}`;
const cacheFolderPath = this.getCacheFolderPath();
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
await fs.writeFile(cachedFilePath, content);
return {
uuid: uuid,
cachedPath: cachedFileName,
name: fileName,
mimeType: getMimeType(fileName)
};
}
/**
* Восстанавливает кеш из исходного файла
*/
async restoreCache(sourcePath: string, type: 'file' | 'prompt' | 'external', uuid: string): Promise<string> {
if (type === 'external') {
// Для внешних файлов sourcePath - абсолютный
const result = await this.cacheExternalFile(sourcePath);
return result.cachedPath;
} else if (type === 'file') {
// Для внутренних файлов sourcePath - относительный
const file = this.plugin.app.vault.getAbstractFileByPath(sourcePath);
if (file instanceof TFile) {
const result = await this.cacheVaultFile(file);
return result.cachedPath;
}
} else if (type === 'prompt') {
// Для промптов
const promptsFolder = this.plugin.settings.promptsFolder;
const fullPath = this.isAbsolutePath(sourcePath)
? sourcePath
: `${promptsFolder}/${sourcePath}`;
const file = this.plugin.app.vault.getAbstractFileByPath(fullPath);
if (file instanceof TFile) {
const result = await this.cacheVaultFile(file);
return result.cachedPath;
}
}
throw new Error(`Не удалось восстановить кеш для ${sourcePath}`);
}
/**
* Читает содержимое из кеша
*/
async readCachedFile(cachedPath: string): Promise<ArrayBuffer> {
const cacheFolderPath = this.getCacheFolderPath();
const fullPath = `${cacheFolderPath}/${cachedPath}`;
if (!window.require) {
throw new Error('Чтение кеша доступно только в desktop версии');
}
const fs = window.require('fs').promises;
const buffer = await fs.readFile(fullPath);
return buffer.buffer;
}
/**
* Проверяет существование кешированного файла
*/
async cachedFileExists(cachedPath: string): Promise<boolean> {
const cacheFolderPath = this.getCacheFolderPath();
const fullPath = `${cacheFolderPath}/${cachedPath}`;
if (!window.require) return false;
const fs = window.require('fs').promises;
try {
await fs.access(fullPath);
return true;
} catch {
return false;
}
}
}