mirror of
https://github.com/ChiChou/entdb.git
synced 2026-06-11 07:17:47 +02:00
Fix base path and restore wasm engine
This commit is contained in:
+8
-16
@@ -1,31 +1,23 @@
|
||||
import type { Engine } from "./types";
|
||||
import { WASMEngine } from "./wasm";
|
||||
import { checkWASMSupport as checkSQLiteWASMSupport } from "./wasm";
|
||||
import { KVEngine } from "./kv";
|
||||
|
||||
let wasmSupported: boolean | null = null;
|
||||
const wasmDisabled = process.env.NEXT_PUBLIC_USE_WASM === "0";
|
||||
|
||||
async function checkWASMSupport(): Promise<boolean> {
|
||||
if (wasmSupported !== null) return wasmSupported;
|
||||
|
||||
try {
|
||||
if (typeof WebAssembly === "undefined") {
|
||||
wasmSupported = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
await WebAssembly.instantiate(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
|
||||
|
||||
await import("@sqlite.org/sqlite-wasm");
|
||||
|
||||
wasmSupported = true;
|
||||
return true;
|
||||
} catch {
|
||||
wasmSupported = false;
|
||||
return false;
|
||||
}
|
||||
wasmSupported = await checkSQLiteWASMSupport();
|
||||
return wasmSupported;
|
||||
}
|
||||
|
||||
export async function createEngine(group: string): Promise<Engine> {
|
||||
if (wasmDisabled) {
|
||||
return new KVEngine(group);
|
||||
}
|
||||
|
||||
const supported = await checkWASMSupport();
|
||||
if (supported) {
|
||||
return new WASMEngine();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Engine } from "./types";
|
||||
import type { OS } from "@/lib/types";
|
||||
import { addBasePath, dataBaseURL } from "@/lib/env";
|
||||
import { dataBaseURL } from "@/lib/env";
|
||||
import { fetchText, fetchLines } from "@/lib/client";
|
||||
|
||||
interface KVRecord {
|
||||
@@ -55,14 +55,14 @@ export class KVEngine implements Engine {
|
||||
}
|
||||
|
||||
async listOS(): Promise<OS[]> {
|
||||
const list = await fetchText(addBasePath(`${this.#baseURL}/list.json`));
|
||||
const list = await fetchText(`${this.#baseURL}/list.json`);
|
||||
return JSON.parse(list);
|
||||
}
|
||||
|
||||
async getPaths(build: string): Promise<string[]> {
|
||||
const os = await this.findOS(build);
|
||||
const tag = `${os.version}_${build}`;
|
||||
return fetchLines(addBasePath(`${this.#baseURL}/${tag}/paths.txt`));
|
||||
return fetchLines(`${this.#baseURL}/${tag}/paths.txt`);
|
||||
}
|
||||
|
||||
async getBinaryXML(build: string, path: string): Promise<string> {
|
||||
|
||||
+92
-52
@@ -2,40 +2,80 @@ import type { Engine } from "./types";
|
||||
import type { OS } from "@/lib/types";
|
||||
import { dataBaseURL } from "@/lib/env";
|
||||
|
||||
type SQLite3Database = {
|
||||
exec: (options: {
|
||||
sql: string;
|
||||
bind?: unknown[];
|
||||
rowMode: "array";
|
||||
returnValue: "resultRows";
|
||||
}) => unknown[][];
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
type SQLite3API = {
|
||||
Database: new (data: ArrayLike<number | bigint>) => {
|
||||
exec: (
|
||||
sql: string,
|
||||
bind?: unknown[]
|
||||
) => {
|
||||
columns: string[];
|
||||
rows: unknown[][];
|
||||
}[];
|
||||
close: () => void;
|
||||
oo1: {
|
||||
DB: new (filename?: string, flags?: string, vfs?: string) => SQLite3Database;
|
||||
};
|
||||
capi: {
|
||||
sqlite3_js_posix_create_file: (
|
||||
filename: string,
|
||||
data: Uint8Array | ArrayBuffer,
|
||||
dataLen?: number
|
||||
) => void;
|
||||
};
|
||||
};
|
||||
|
||||
let sqlite3Module: SQLite3API | null = null;
|
||||
let dbInstance: InstanceType<SQLite3API["Database"]> | null = null;
|
||||
let dbInstance: SQLite3Database | null = null;
|
||||
let dbReady = false;
|
||||
|
||||
async function loadSQLite(): Promise<SQLite3API> {
|
||||
if (sqlite3Module) return sqlite3Module;
|
||||
|
||||
const sqliteModule = await import("@sqlite.org/sqlite-wasm");
|
||||
sqlite3Module = (sqliteModule.default || sqliteModule) as unknown as SQLite3API;
|
||||
const initSQLite = sqliteModule.default;
|
||||
sqlite3Module = (await initSQLite()) as unknown as SQLite3API;
|
||||
return sqlite3Module;
|
||||
}
|
||||
|
||||
async function getDB(): Promise<InstanceType<SQLite3API["Database"]>> {
|
||||
export async function checkWASMSupport(): Promise<boolean> {
|
||||
try {
|
||||
if (typeof WebAssembly === "undefined") {
|
||||
return false;
|
||||
}
|
||||
|
||||
await WebAssembly.instantiate(
|
||||
Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)
|
||||
);
|
||||
await loadSQLite();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDB(): Promise<SQLite3Database> {
|
||||
if (dbReady && dbInstance) return dbInstance;
|
||||
|
||||
const sqlite3 = await loadSQLite();
|
||||
|
||||
const response = await fetch(`${dataBaseURL()}/ent.db`);
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch SQLite database: ${response.status} ${response.statusText}`
|
||||
);
|
||||
}
|
||||
const buffer = await response.arrayBuffer();
|
||||
const bytes = new Uint8Array(buffer);
|
||||
const filename = "/ent.db";
|
||||
|
||||
dbInstance = new sqlite3.Database(new Uint8Array(buffer));
|
||||
try {
|
||||
sqlite3.capi.sqlite3_js_posix_create_file(filename, bytes, bytes.byteLength);
|
||||
} catch {
|
||||
// Ignore duplicate file creation in hot-reload or repeated initialization cases.
|
||||
}
|
||||
|
||||
dbInstance = new sqlite3.oo1.DB(filename, "r");
|
||||
dbReady = true;
|
||||
return dbInstance;
|
||||
}
|
||||
@@ -43,64 +83,64 @@ async function getDB(): Promise<InstanceType<SQLite3API["Database"]>> {
|
||||
export class WASMEngine implements Engine {
|
||||
async listOS(): Promise<OS[]> {
|
||||
const db = await getDB();
|
||||
const results = db.exec(
|
||||
"SELECT name, version, build, devices FROM os ORDER BY version DESC"
|
||||
);
|
||||
if (!results.length) return [];
|
||||
const rows = db.exec({
|
||||
sql: "SELECT name, version, build, devices FROM os ORDER BY version DESC",
|
||||
rowMode: "array",
|
||||
returnValue: "resultRows",
|
||||
});
|
||||
|
||||
const cols = results[0].columns;
|
||||
const nameIdx = cols.indexOf("name");
|
||||
const versionIdx = cols.indexOf("version");
|
||||
const buildIdx = cols.indexOf("build");
|
||||
const devicesIdx = cols.indexOf("devices");
|
||||
|
||||
return results[0].rows.map((row) => ({
|
||||
name: row[nameIdx] as string,
|
||||
version: row[versionIdx] as string,
|
||||
build: row[buildIdx] as string,
|
||||
devices: JSON.parse(row[devicesIdx] as string),
|
||||
return rows.map((row) => ({
|
||||
name: row[0] as string,
|
||||
version: row[1] as string,
|
||||
build: row[2] as string,
|
||||
devices: JSON.parse(row[3] as string),
|
||||
}));
|
||||
}
|
||||
|
||||
async getPaths(build: string): Promise<string[]> {
|
||||
const db = await getDB();
|
||||
const results = db.exec(
|
||||
`SELECT path FROM bin JOIN os ON bin.osid=os.id WHERE os.build=?`,
|
||||
[build]
|
||||
);
|
||||
if (!results.length) return [];
|
||||
return results[0].rows.map((row) => row[0] as string);
|
||||
const rows = db.exec({
|
||||
sql: `SELECT path FROM bin JOIN os ON bin.osid=os.id WHERE os.build=?`,
|
||||
bind: [build],
|
||||
rowMode: "array",
|
||||
returnValue: "resultRows",
|
||||
});
|
||||
return rows.map((row) => row[0] as string);
|
||||
}
|
||||
|
||||
async getBinaryXML(build: string, path: string): Promise<string> {
|
||||
const db = await getDB();
|
||||
const results = db.exec(
|
||||
`SELECT xml FROM bin JOIN os ON bin.osid=os.id WHERE os.build=? AND bin.path=?`,
|
||||
[build, path]
|
||||
);
|
||||
if (!results.length || !results[0].rows.length) {
|
||||
const rows = db.exec({
|
||||
sql: `SELECT xml FROM bin JOIN os ON bin.osid=os.id WHERE os.build=? AND bin.path=?`,
|
||||
bind: [build, path],
|
||||
rowMode: "array",
|
||||
returnValue: "resultRows",
|
||||
});
|
||||
if (!rows.length) {
|
||||
throw new Error(`Binary not found: ${path}`);
|
||||
}
|
||||
return results[0].rows[0][0] as string;
|
||||
return rows[0][0] as string;
|
||||
}
|
||||
|
||||
async getKeys(build: string): Promise<string[]> {
|
||||
const db = await getDB();
|
||||
const results = db.exec(
|
||||
`SELECT DISTINCT key FROM pair JOIN bin ON pair.binid=bin.id JOIN os ON bin.osid=os.id WHERE os.build=?`,
|
||||
[build]
|
||||
);
|
||||
if (!results.length) return [];
|
||||
return results[0].rows.map((row) => row[0] as string);
|
||||
const rows = db.exec({
|
||||
sql: `SELECT DISTINCT key FROM pair JOIN bin ON pair.binid=bin.id JOIN os ON bin.osid=os.id WHERE os.build=?`,
|
||||
bind: [build],
|
||||
rowMode: "array",
|
||||
returnValue: "resultRows",
|
||||
});
|
||||
return rows.map((row) => row[0] as string);
|
||||
}
|
||||
|
||||
async getPathsForKey(build: string, key: string): Promise<string[]> {
|
||||
const db = await getDB();
|
||||
const results = db.exec(
|
||||
`SELECT path FROM bin JOIN pair ON bin.id=pair.binid JOIN os ON bin.osid=os.id WHERE os.build=? AND pair.key=?`,
|
||||
[build, key]
|
||||
);
|
||||
if (!results.length) return [];
|
||||
return results[0].rows.map((row) => row[0] as string);
|
||||
const rows = db.exec({
|
||||
sql: `SELECT path FROM bin JOIN pair ON bin.id=pair.binid JOIN os ON bin.osid=os.id WHERE os.build=? AND pair.key=?`,
|
||||
bind: [build, key],
|
||||
rowMode: "array",
|
||||
returnValue: "resultRows",
|
||||
});
|
||||
return rows.map((row) => row[0] as string);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user