Files
citygen/src/store.ts
T

60 lines
2.2 KiB
TypeScript

// Хранение миров в IndexedDB (локально в браузере).
import type { World } from './types';
const DB = 'citygen';
const STORE = 'worlds';
function open(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const req = indexedDB.open(DB, 1);
req.onupgradeneeded = () => req.result.createObjectStore(STORE);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async function tx<T>(mode: IDBTransactionMode, fn: (s: IDBObjectStore) => IDBRequest<T>): Promise<T> {
const db = await open();
return new Promise((resolve, reject) => {
const t = db.transaction(STORE, mode);
const req = fn(t.objectStore(STORE));
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
export const saveWorld = (w: World) => tx('readwrite', (s) => s.put(w, 'last'));
export const loadWorld = () => tx<World | undefined>('readonly', (s) => s.get('last'));
export const hasWorld = async () => {
try {
return (await tx<number>('readonly', (s) => s.count('last'))) > 0;
} catch {
return false;
}
};
/** Скачать мир файлом (.json.gz, если браузер умеет сжимать). */
export async function downloadWorld(w: World) {
const json = JSON.stringify(w);
let blob: Blob = new Blob([json], { type: 'application/json' });
let ext = 'json';
if ('CompressionStream' in window) {
const cs = blob.stream().pipeThrough(new CompressionStream('gzip'));
blob = await new Response(cs).blob();
ext = 'json.gz';
}
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `${(w.name || 'world').replace(/[^\p{L}\p{N}_-]+/gu, '_').slice(0, 40)}.${ext}`;
a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 2000);
}
/** Прочитать файл мира или Overpass JSON (поддерживает .gz). */
export async function readJsonFile(file: File): Promise<any> {
let stream: ReadableStream = file.stream();
const head = new Uint8Array(await file.slice(0, 2).arrayBuffer());
if (head[0] === 0x1f && head[1] === 0x8b) stream = stream.pipeThrough(new DecompressionStream('gzip'));
return JSON.parse(await new Response(stream).text());
}