Files
Aurora.3/tgui/public/iframe.html

214 lines
6.6 KiB
HTML

<!doctype html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
<meta charset='utf-8' />
<script type='text/javascript'>
const INDEXED_DB_VERSION = 2;
const INDEXED_DB_NAME = 'tgui';
const INDEXED_DB_STORE_NAME = 'storage';
const READ_ONLY = 'readonly';
const READ_WRITE = 'readwrite';
let maxStoredMessages = 2500;
let startFrom = 0;
let writeFrom = 0;
const dbPromise = new Promise((resolve, reject) => {
const indexedDB = window.indexedDB || window.msIndexedDB;
const req = indexedDB.open(INDEXED_DB_NAME, INDEXED_DB_VERSION);
req.onupgradeneeded = (event) => {
try {
if(event.oldVersion < 1) {
req.result.createObjectStore(INDEXED_DB_STORE_NAME);
}
if(event.oldVersion < 2) {
req.result.createObjectStore("ring");
req.result.createObjectStore("messages", { autoIncrement: true }).transaction.oncomplete = async () => {
const trans = req.result.transaction("messages", READ_WRITE).objectStore("messages");
startFrom = await promiseForRequest(trans.add(null)) - 1;
for (let index = 0; index < maxStoredMessages - 1; index++) {
await promiseForRequest(trans.add(null));
}
}
}
} catch (err) {
reject(new Error('Failed to upgrade IDB: ' + req.error));
}
};
req.onsuccess = async () => {
const storage = req.result.transaction(["ring", "messages", INDEXED_DB_STORE_NAME], "readonly")
writeFrom = await promiseForRequest(storage.objectStore("ring").get("value")) || 0;
const panelSettings = await promiseForRequest(storage.objectStore(INDEXED_DB_STORE_NAME).get("panel-settings"))
maxStoredMessages = panelSettings?.maxMessages || 2500;
const messageStore = storage.objectStore("messages");
const messageCount = await promiseForRequest(messageStore.count());
if(messageCount !== maxStoredMessages) {
await alterMessageRing(req.result);
}
let cursorReq = await promiseForRequest(messageStore.openCursor());
let cursor = await(cursorReq);
startFrom = cursor.key - 1;
resolve(req.result);
};
req.onerror = () => {
reject(new Error('Failed to open IDB: ' + req.error));
};
});
const alterMessageRing = async (db) => {
db = db ?? await dbPromise;
const existingMessages = (await getSavedMessages(db)).slice(0, maxStoredMessages);
const trans = db.transaction("messages", READ_WRITE).objectStore("messages");
await promiseForRequest(trans.clear());
startFrom = await promiseForRequest(trans.add(null)) - 1;
for (let index = 0; index < maxStoredMessages - 1; index++) {
await promiseForRequest(trans.add(null));
}
writeFrom = startFrom;
await addMessageBatch(existingMessages, db);
}
window.addEventListener('message', (messageEvent) => {
switch (messageEvent.data.type) {
case 'ping':
messageEvent.source.postMessage(true, "*");
break;
case 'get':
get(messageEvent.data.key).then((value) => {
messageEvent.source.postMessage({key: messageEvent.data.key, value: value}, "*");
});
break;
case 'set':
set(messageEvent.data.key, messageEvent.data.value);
break;
case 'remove':
remove(messageEvent.data.key);
break;
case 'clear':
clear();
break;
case 'setNumberStored':
maxStoredMessages = messageEvent.data.newMax;
alterMessageRing();
break;
case 'processChatMessages':
addMessageBatch(messageEvent.data.messages);
break;
case 'getChatMessages':
getSavedMessages().then((messages) => {
messageEvent.source.postMessage({messages: messages}, "*");
})
default:
break;
}
});
const addMessageBatch = async (messages, db) => {
if(!messages || !messages.length) return;
const database = db ?? await dbPromise;
const trans = database.transaction("messages", READ_WRITE).objectStore("messages");
console.log(writeFrom, startFrom);
let cursorReq = trans.openCursor(IDBKeyRange.bound(writeFrom, writeFrom + messages.length, true));
let cursor = await promiseForRequest(cursorReq);
for (let index = 0; index < messages.length; index++) {
const message = messages[index];
cursor.update(message);
writeFrom = cursor.key;
if(cursor.key === startFrom + maxStoredMessages) {
writeFrom = startFrom;
cursorReq = trans.openCursor(IDBKeyRange.bound(startFrom, startFrom + messages.length - index + 1, true));
cursor = await promiseForRequest(cursorReq);
} else {
cursor.continue();
await promiseForRequest(cursorReq);
}
}
database.transaction("ring", READ_WRITE).objectStore("ring").put(writeFrom, "value");
}
const getSavedMessages = async (db) => {
const database = db ?? await dbPromise;
const trans = database.transaction("messages", READ_ONLY).objectStore("messages");
const messyMessages = await promiseForRequest(trans.getAll());
const upTo = messyMessages.splice(0, writeFrom);
if(messyMessages[0] === null) {
return upTo;
}
const messages = messyMessages.concat(upTo);
return messages;
}
const getStore = async (mode) => {
return dbPromise.then((db) => db
.transaction(INDEXED_DB_STORE_NAME, mode)
.objectStore(INDEXED_DB_STORE_NAME));
};
const get = async (key) => {
const store = await getStore(READ_ONLY);
return new Promise((resolve, reject) => {
const req = store.get(key);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
};
const set = async (key, value) => {
const store = await getStore(READ_WRITE);
store.put(value, key);
};
const remove = async (key) => {
const store = await getStore(READ_WRITE);
store.delete(key);
};
const clear = async () => {
const store = await getStore(READ_WRITE);
store.clear();
};
const promiseForRequest = (request) => {
return new Promise((resolve, reject) => {
request.onsuccess = () => { resolve(request.result); };
request.onerror = () => { reject(request.error); };
});
}
</script>
</head>
</html>