release: v0.2.2 AriaEngine OPFS 自研存储后端 — 零依赖纯文件系统
CI / test (18.x) (push) Successful in 10m0s
CI / test (20.x) (push) Successful in 9m56s
CI / test (22.x) (push) Successful in 9m56s
CI / test (24.x) (push) Successful in 9m52s

This commit is contained in:
thzxx
2026-07-27 21:08:57 +08:00
parent eab58adc37
commit fef4db44ca
18 changed files with 450 additions and 73 deletions
+4 -1
View File
@@ -25,6 +25,7 @@ import { WAL } from './wal/log';
import { WALRecordType, type WALRecord } from './types';
import { CheckpointManager } from './wal/checkpoint';
import { IndexedDBBackend, MemoryBackend, type IStorageBackend } from './store/backend';
import { OPFSBackend } from './store/opfs_backend';
// ---------------------------------------------------------------------------
// AriaEngine
@@ -63,7 +64,9 @@ export class AriaEngine implements IStorageEngine {
this.dbName = dbName;
// 1. 存储后端
if (this.config.storageBackend === 'indexeddb') {
if (this.config.storageBackend === 'opfs') {
this.backend = new OPFSBackend();
} else if (this.config.storageBackend === 'indexeddb') {
this.backend = new IndexedDBBackend();
} else {
this.backend = new MemoryBackend();
+88
View File
@@ -0,0 +1,88 @@
/**
* AriaEngine OPFS Backend — 基于 Origin Private File System 的自研存储后端
* @module engine/aria/store/opfs_backend
*
* 零外部依赖,纯浏览器文件系统 API。
* 每个 key 对应 OPFS 目录下的一个二进制文件。
*
* 浏览器要求:Chrome 102+ / Edge 102+
*/
import type { IStorageBackend } from './backend';
export class OPFSBackend implements IStorageBackend {
private root: FileSystemDirectoryHandle | null = null;
private dbDir: FileSystemDirectoryHandle | null = null;
private dbName = '';
async open(name: string): Promise<void> {
this.dbName = name;
this.root = await navigator.storage.getDirectory();
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
}
async close(): Promise<void> {
this.dbDir = null;
this.root = null;
}
isOpen(): boolean {
return this.dbDir !== null;
}
async read(key: string): Promise<ArrayBuffer | null> {
if (!this.dbDir) return null;
try {
const fh = await this.dbDir.getFileHandle(key);
const file = await fh.getFile();
return await file.arrayBuffer();
} catch {
return null;
}
}
async write(key: string, data: ArrayBuffer): Promise<void> {
if (!this.dbDir) return;
const fh = await this.dbDir.getFileHandle(key, { create: true });
const writable = await fh.createWritable();
await writable.write(data);
await writable.close();
}
async delete(key: string): Promise<void> {
if (!this.dbDir) return;
try {
await this.dbDir.removeEntry(key);
} catch {
// 文件不存在则忽略
}
}
async listKeys(): Promise<string[]> {
if (!this.dbDir) return [];
const keys: string[] = [];
// FileSystemDirectoryHandle.entries() 返回 AsyncIterable,使用 any 绕过 dts 生成限制
const dir = this.dbDir as any;
for await (const [name] of dir.entries()) {
keys.push(name);
}
return keys;
}
async exists(key: string): Promise<boolean> {
if (!this.dbDir) return false;
try {
await this.dbDir.getFileHandle(key);
return true;
} catch {
return false;
}
}
async clear(): Promise<void> {
if (!this.dbDir) return;
const dir = this.dbDir as any;
for await (const [name] of dir.entries()) {
try { await this.dbDir!.removeEntry(name); } catch { /* ignore */ }
}
}
}