Skip to main content
Glama
fileSystemStorage.ts6.68 kB
import { readFile, writeFile, access } from 'fs/promises'; import { constants } from 'fs'; import { StorageService } from './storageService.js'; import { Unit } from '../types/index.js'; import { getContentByLines, getContentByChars, insertContentAtLine, insertContentAtChar, removeContentByLines, removeContentByChars, validatePosition } from '../utils/positionUtils.js'; /** * Реализация StorageService для файловой системы */ export class FileSystemStorage extends StorageService { private backups: Map<string, string> = new Map(); async readContent(filePath: string): Promise<string> { try { return await readFile(filePath, 'utf-8'); } catch (error) { throw new Error(`Failed to read file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async writeContent(filePath: string, content: string): Promise<void> { try { await writeFile(filePath, content, 'utf-8'); } catch (error) { throw new Error(`Failed to write file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async resourceExists(filePath: string): Promise<boolean> { try { await access(filePath, constants.F_OK); return true; } catch { return false; } } async extractContent(filePath: string, position: number, count: number, unit: Unit): Promise<string> { const content = await this.readContent(filePath); validatePosition(content, position, unit); if (unit === 'lines') { return getContentByLines(content, position, count); } else { return getContentByChars(content, position, count); } } async insertContent( filePath: string, position: number, content: string, replaceCount?: number, unit: Unit = 'lines' ): Promise<void> { const existingContent = await this.readContent(filePath); validatePosition(existingContent, position, unit); let newContent: string; if (unit === 'lines') { newContent = insertContentAtLine(existingContent, position, content, replaceCount); } else { newContent = insertContentAtChar(existingContent, position, content, replaceCount); } await this.writeContent(filePath, newContent); } async extractContentByPattern(filePath: string, startPattern: string, endPattern?: string, lineCount?: number): Promise<string> { const content = await this.readContent(filePath); const startIndex = content.indexOf(startPattern); if (startIndex === -1) { throw new Error(`Start pattern "${startPattern}" not found in file ${filePath}`); } if (endPattern) { const endIndex = content.indexOf(endPattern, startIndex + startPattern.length); if (endIndex === -1) { throw new Error(`End pattern "${endPattern}" not found after start pattern`); } return content.slice(startIndex, endIndex + endPattern.length); } else if (lineCount) { const lines = content.split('\n'); const startLine = content.slice(0, startIndex).split('\n').length - 1; const endLine = Math.min(startLine + lineCount, lines.length); return lines.slice(startLine, endLine).join('\n'); } else { const lines = content.split('\n'); const startLine = content.slice(0, startIndex).split('\n').length - 1; return lines[startLine]; } } async insertContentByMarker(filePath: string, marker: string, content: string, position: 'before' | 'after' | 'replace', replacePattern?: string): Promise<void> { const existingContent = await this.readContent(filePath); const markerIndex = existingContent.indexOf(marker); if (markerIndex === -1) { throw new Error(`Marker "${marker}" not found in file ${filePath}`); } let newContent: string; if (position === 'before') { newContent = existingContent.replace(marker, `${content}\n${marker}`); } else if (position === 'after') { newContent = existingContent.replace(marker, `${marker}\n${content}`); } else if (position === 'replace') { const targetPattern = replacePattern || marker; newContent = existingContent.replace(targetPattern, content); } else { throw new Error(`Invalid position: ${position}`); } await this.writeContent(filePath, newContent); } async removeContentByPattern(filePath: string, startPattern: string, endPattern?: string, lineCount?: number): Promise<void> { const content = await this.readContent(filePath); const startIndex = content.indexOf(startPattern); if (startIndex === -1) { throw new Error(`Start pattern "${startPattern}" not found in file ${filePath}`); } let newContent: string; if (endPattern) { const endIndex = content.indexOf(endPattern, startIndex + startPattern.length); if (endIndex === -1) { throw new Error(`End pattern "${endPattern}" not found after start pattern`); } newContent = content.slice(0, startIndex) + content.slice(endIndex + endPattern.length); } else if (lineCount) { const lines = content.split('\n'); const startLine = content.slice(0, startIndex).split('\n').length - 1; const endLine = Math.min(startLine + lineCount, lines.length); lines.splice(startLine, endLine - startLine); newContent = lines.join('\n'); } else { const lines = content.split('\n'); const startLine = content.slice(0, startIndex).split('\n').length - 1; lines.splice(startLine, 1); newContent = lines.join('\n'); } await this.writeContent(filePath, newContent); } async removeContent(filePath: string, position: number, count: number, unit: Unit): Promise<void> { const content = await this.readContent(filePath); validatePosition(content, position, unit); let newContent: string; if (unit === 'lines') { newContent = removeContentByLines(content, position, count); } else { newContent = removeContentByChars(content, position, count); } await this.writeContent(filePath, newContent); } async createBackup(filePath: string): Promise<string> { const content = await this.readContent(filePath); const backupId = `${filePath}_${Date.now()}`; this.backups.set(backupId, content); return backupId; } async restoreBackup(filePath: string, backupId: string): Promise<void> { const backupContent = this.backups.get(backupId); if (!backupContent) { throw new Error(`Backup ${backupId} not found`); } await this.writeContent(filePath, backupContent); this.backups.delete(backupId); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/witqq/clipboard-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server