2020-11-26 16:29:10 +11:00
|
|
|
import * as Comlink from "comlink";
|
2021-02-13 21:51:31 +11:00
|
|
|
import {
|
|
|
|
|
importInto,
|
|
|
|
|
exportDB,
|
|
|
|
|
peakImportFile,
|
|
|
|
|
} from "@mitchemmc/dexie-export-import";
|
2021-03-16 17:49:50 +11:00
|
|
|
import { encode, decode } from "@msgpack/msgpack";
|
2020-11-26 16:29:10 +11:00
|
|
|
|
|
|
|
|
import { getDatabase } from "../database";
|
2021-04-15 15:18:47 +10:00
|
|
|
import blobToBuffer from "../helpers/blobToBuffer";
|
2020-11-26 16:29:10 +11:00
|
|
|
|
|
|
|
|
// Worker to load large amounts of database data on a separate thread
|
2021-01-27 16:24:13 +11:00
|
|
|
let service = {
|
2021-01-22 14:59:05 +11:00
|
|
|
/**
|
|
|
|
|
* Load either a whole table or individual item from the DB
|
|
|
|
|
* @param {string} table Table to load from
|
2021-02-08 16:53:56 +11:00
|
|
|
* @param {string=} key Optional database key to load, if undefined whole table will be loaded
|
2021-01-22 14:59:05 +11:00
|
|
|
*/
|
2021-04-22 16:53:35 +10:00
|
|
|
async loadData(table, key) {
|
2020-11-26 17:08:09 +11:00
|
|
|
try {
|
|
|
|
|
let db = getDatabase({});
|
2021-01-22 14:59:05 +11:00
|
|
|
if (key) {
|
|
|
|
|
// Load specific item
|
2021-02-13 21:51:31 +11:00
|
|
|
const data = await db.table(table).get(key);
|
2021-04-22 16:53:35 +10:00
|
|
|
const packed = encode(data);
|
|
|
|
|
return Comlink.transfer(packed, [packed.buffer]);
|
2021-01-22 14:59:05 +11:00
|
|
|
} else {
|
|
|
|
|
// Load entire table
|
2021-01-27 16:24:13 +11:00
|
|
|
let items = [];
|
2021-01-22 14:59:05 +11:00
|
|
|
// Use a cursor instead of toArray to prevent IPC max size error
|
2021-02-08 16:53:56 +11:00
|
|
|
await db.table(table).each((item) => {
|
2021-04-22 16:53:35 +10:00
|
|
|
items.push(item);
|
2021-02-08 16:53:56 +11:00
|
|
|
});
|
2021-01-27 16:24:13 +11:00
|
|
|
|
|
|
|
|
// Pack data with msgpack so we can use transfer to avoid memory issues
|
|
|
|
|
const packed = encode(items);
|
|
|
|
|
return Comlink.transfer(packed, [packed.buffer]);
|
2021-01-22 14:59:05 +11:00
|
|
|
}
|
2020-11-26 17:08:09 +11:00
|
|
|
} catch {}
|
2020-11-26 16:29:10 +11:00
|
|
|
},
|
2021-01-27 11:57:23 +11:00
|
|
|
|
2021-03-16 17:49:50 +11:00
|
|
|
/**
|
|
|
|
|
* Put data into table encoded by msgpack
|
|
|
|
|
* @param {Uint8Array} data
|
|
|
|
|
* @param {string} table
|
|
|
|
|
* @param {boolean} wait Whether to wait for the put to finish
|
|
|
|
|
*/
|
|
|
|
|
async putData(data, table, wait = true) {
|
|
|
|
|
try {
|
|
|
|
|
let db = getDatabase({});
|
|
|
|
|
const decoded = decode(data);
|
|
|
|
|
if (wait) {
|
|
|
|
|
await db.table(table).put(decoded);
|
|
|
|
|
} else {
|
|
|
|
|
db.table(table).put(decoded);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} catch {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2021-01-27 11:57:23 +11:00
|
|
|
/**
|
|
|
|
|
* Export current database
|
|
|
|
|
* @param {function} progressCallback
|
2021-02-13 21:51:31 +11:00
|
|
|
* @param {string[]} maps An array of map ids to export
|
|
|
|
|
* @param {string[]} tokens An array of token ids to export
|
2021-01-27 11:57:23 +11:00
|
|
|
*/
|
2021-02-13 21:51:31 +11:00
|
|
|
async exportData(progressCallback, maps, tokens) {
|
2021-02-13 13:21:13 +11:00
|
|
|
let db = getDatabase({});
|
2021-02-13 21:51:31 +11:00
|
|
|
|
|
|
|
|
const filter = (table, value) => {
|
|
|
|
|
if (table === "maps") {
|
|
|
|
|
return maps.includes(value.id);
|
|
|
|
|
}
|
|
|
|
|
if (table === "states") {
|
|
|
|
|
return maps.includes(value.mapId);
|
|
|
|
|
}
|
|
|
|
|
if (table === "tokens") {
|
|
|
|
|
return tokens.includes(value.id);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const data = await exportDB(db, {
|
2021-02-13 13:21:13 +11:00
|
|
|
progressCallback,
|
2021-02-13 21:51:31 +11:00
|
|
|
filter,
|
2021-02-13 13:21:13 +11:00
|
|
|
numRowsPerChunk: 1,
|
2021-02-14 10:11:52 +11:00
|
|
|
prettyJson: true,
|
2021-02-13 13:21:13 +11:00
|
|
|
});
|
2021-04-15 15:18:47 +10:00
|
|
|
|
|
|
|
|
const buffer = await blobToBuffer(data);
|
|
|
|
|
|
|
|
|
|
return Comlink.transfer(buffer, [buffer.buffer]);
|
2021-01-27 11:57:23 +11:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Import into current database
|
|
|
|
|
* @param {Blob} data
|
2021-02-13 21:51:31 +11:00
|
|
|
* @param {string} databaseName The name of the database to import into
|
2021-01-27 11:57:23 +11:00
|
|
|
* @param {function} progressCallback
|
|
|
|
|
*/
|
2021-02-13 21:51:31 +11:00
|
|
|
async importData(data, databaseName, progressCallback) {
|
|
|
|
|
const importMeta = await peakImportFile(data);
|
2021-02-14 19:17:14 +11:00
|
|
|
if (!importMeta.data) {
|
|
|
|
|
throw new Error("Uanble to parse file");
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-13 13:21:13 +11:00
|
|
|
let db = getDatabase({});
|
2021-02-13 21:51:31 +11:00
|
|
|
|
|
|
|
|
if (importMeta.data.databaseName !== db.name) {
|
|
|
|
|
throw new Error("Unable to import database, name mismatch");
|
|
|
|
|
}
|
2021-02-14 13:36:00 +11:00
|
|
|
if (importMeta.data.databaseVersion > db.verno) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`Database version differs. Current database is in version ${db.verno} but export is ${importMeta.data.databaseVersion}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure import DB is cleared before importing new data
|
2021-03-18 12:57:41 +11:00
|
|
|
let importDB = getDatabase({ addons: [] }, databaseName, 0);
|
2021-02-14 13:36:00 +11:00
|
|
|
await importDB.delete();
|
|
|
|
|
importDB.close();
|
2021-02-13 21:51:31 +11:00
|
|
|
|
2021-02-14 13:36:00 +11:00
|
|
|
// Load import database up to it's desired version
|
2021-03-18 12:57:41 +11:00
|
|
|
importDB = getDatabase(
|
|
|
|
|
{ addons: [] },
|
|
|
|
|
databaseName,
|
|
|
|
|
importMeta.data.databaseVersion
|
|
|
|
|
);
|
2021-02-13 21:51:31 +11:00
|
|
|
await importInto(importDB, data, {
|
|
|
|
|
progressCallback,
|
|
|
|
|
acceptNameDiff: true,
|
|
|
|
|
overwriteValues: true,
|
|
|
|
|
filter: (table, value) => {
|
|
|
|
|
// Ensure values are of the correct form
|
|
|
|
|
if (table === "maps" || table === "tokens") {
|
|
|
|
|
return "id" in value && "owner" in value;
|
|
|
|
|
}
|
|
|
|
|
if (table === "states") {
|
|
|
|
|
return "mapId" in value;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
},
|
2021-02-14 13:36:00 +11:00
|
|
|
acceptVersionDiff: true,
|
2021-02-13 21:51:31 +11:00
|
|
|
});
|
|
|
|
|
importDB.close();
|
2021-01-27 11:57:23 +11:00
|
|
|
},
|
2020-11-26 16:29:10 +11:00
|
|
|
};
|
|
|
|
|
|
2021-01-27 16:24:13 +11:00
|
|
|
Comlink.expose(service);
|