mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
Compare commits
7 Commits
1b99ac2969
...
ad7d82f3ae
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad7d82f3ae | ||
|
|
c4337dc60a | ||
|
|
90bebd219a | ||
|
|
067ab7459b | ||
|
|
a42bdce47b | ||
|
|
28a8d23bf6 | ||
|
|
ba5019bd9d |
33
.github/workflows/generate_client_storage.yml
vendored
Normal file
33
.github/workflows/generate_client_storage.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: "Generate Client Storage"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- tgui/public/*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch_repo:
|
||||||
|
if: ( !contains(github.event.head_commit.message, '[ci skip]') )
|
||||||
|
name: Repository Dispatch
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Generate App Token
|
||||||
|
id: app-token-generation
|
||||||
|
uses: actions/create-github-app-token@v2
|
||||||
|
if: env.APP_PRIVATE_KEY != '' && env.APP_ID != ''
|
||||||
|
with:
|
||||||
|
app-id: ${{ secrets.APP_ID }}
|
||||||
|
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||||
|
owner: vorestation
|
||||||
|
env:
|
||||||
|
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
|
||||||
|
APP_ID: ${{ secrets.APP_ID }}
|
||||||
|
|
||||||
|
- name: Send Repository Dispatch
|
||||||
|
if: success()
|
||||||
|
uses: peter-evans/repository-dispatch@v4
|
||||||
|
with:
|
||||||
|
token: ${{ steps.app-token-generation.outputs.token }}
|
||||||
|
repository: vorestation/byond-client-storage
|
||||||
|
event-type: on_master_push
|
||||||
@@ -58,4 +58,4 @@
|
|||||||
#endif //ifdef REFERENCE_TRACKING
|
#endif //ifdef REFERENCE_TRACKING
|
||||||
|
|
||||||
// Standard flags to use for browser-options
|
// Standard flags to use for browser-options
|
||||||
#define DEFAULT_CLIENT_BROWSER_OPTIONS "byondstorage,find"
|
#define DEFAULT_CLIENT_BROWSER_OPTIONS "find"
|
||||||
|
|||||||
@@ -11,3 +11,7 @@
|
|||||||
/datum/config_entry/flag/smart_cache_assets
|
/datum/config_entry/flag/smart_cache_assets
|
||||||
|
|
||||||
/datum/config_entry/flag/save_spritesheets
|
/datum/config_entry/flag/save_spritesheets
|
||||||
|
|
||||||
|
/datum/config_entry/string/storage_cdn_iframe
|
||||||
|
protection = CONFIG_ENTRY_LOCKED
|
||||||
|
default = "https://vorestation.github.io/byond-client-storage/iframe.html"
|
||||||
|
|||||||
@@ -15,9 +15,12 @@ SUBSYSTEM_DEF(tgui)
|
|||||||
wait = 9
|
wait = 9
|
||||||
flags = SS_NO_INIT
|
flags = SS_NO_INIT
|
||||||
priority = FIRE_PRIORITY_TGUI
|
priority = FIRE_PRIORITY_TGUI
|
||||||
init_stage = INITSTAGE_EARLY
|
|
||||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
||||||
|
|
||||||
|
dependencies = list(
|
||||||
|
/datum/controller/subsystem/assets
|
||||||
|
)
|
||||||
|
|
||||||
/// A list of UIs scheduled to process
|
/// A list of UIs scheduled to process
|
||||||
var/list/current_run = list()
|
var/list/current_run = list()
|
||||||
/// A list of all open UIs
|
/// A list of all open UIs
|
||||||
@@ -40,6 +43,25 @@ SUBSYSTEM_DEF(tgui)
|
|||||||
|
|
||||||
basehtml = replacetextEx(basehtml, "<!-- tgui:nt-copyright -->", "Nanotrasen (c) 2284-[text2num(time2text(world.realtime,"YYYY")) + STATION_YEAR_OFFSET]")
|
basehtml = replacetextEx(basehtml, "<!-- tgui:nt-copyright -->", "Nanotrasen (c) 2284-[text2num(time2text(world.realtime,"YYYY")) + STATION_YEAR_OFFSET]")
|
||||||
|
|
||||||
|
/datum/controller/subsystem/tgui/OnConfigLoad()
|
||||||
|
var/storage_iframe = CONFIG_GET(string/storage_cdn_iframe)
|
||||||
|
|
||||||
|
if(storage_iframe && storage_iframe != /datum/config_entry/string/storage_cdn_iframe::default)
|
||||||
|
basehtml = replacetextEx(basehtml, "\[tgui:storagecdn]", storage_iframe)
|
||||||
|
return
|
||||||
|
|
||||||
|
if(CONFIG_GET(string/asset_transport) == "webroot")
|
||||||
|
var/datum/asset_transport/webroot/webroot = SSassets.transport
|
||||||
|
|
||||||
|
var/datum/asset_cache_item/item = webroot.register_asset("iframe.html", file("tgui/public/iframe.html"))
|
||||||
|
basehtml = replacetextEx(basehtml, "\[tgui:storagecdn]", webroot.get_asset_url("iframe.html", item))
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!storage_iframe)
|
||||||
|
return
|
||||||
|
|
||||||
|
basehtml = replacetextEx(basehtml, "\[tgui:storagecdn]", storage_iframe)
|
||||||
|
|
||||||
/datum/controller/subsystem/tgui/Shutdown()
|
/datum/controller/subsystem/tgui/Shutdown()
|
||||||
close_all_uis()
|
close_all_uis()
|
||||||
|
|
||||||
|
|||||||
@@ -782,3 +782,8 @@ ADMIN_VERB(quick_nif, R_ADMIN, "Quick NIF", "Spawns a NIF into someone in quick-
|
|||||||
|
|
||||||
log_and_message_admins("Quick NIF'd [H.real_name] with a [input_NIF].", user)
|
log_and_message_admins("Quick NIF'd [H.real_name] with a [input_NIF].", user)
|
||||||
feedback_add_details("admin_verb","QNIF") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
feedback_add_details("admin_verb","QNIF") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||||
|
|
||||||
|
ADMIN_VERB(reload_configuration, R_DEBUG, "Reload Configuration", "Reloads the configuration from the default path on the disk, wiping any in-round modifications.", ADMIN_CATEGORY_DEBUG)
|
||||||
|
if(tgui_alert(user, "Are you absolutely sure you want to reload the configuration from the default path on the disk, wiping any in-round modifications?", "Really reset?", list("No", "Yes")) != "Yes")
|
||||||
|
return
|
||||||
|
config.admin_reload()
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
|||||||
if (CONFIG_GET(flag/chatlog_database_backend))
|
if (CONFIG_GET(flag/chatlog_database_backend))
|
||||||
chatlog_token = vchatlog_generate_token(ckey, GLOB.round_id)
|
chatlog_token = vchatlog_generate_token(ckey, GLOB.round_id)
|
||||||
|
|
||||||
|
winset(src, null, list("browser-options" = "find,refresh"))
|
||||||
// Instantiate stat panel
|
// Instantiate stat panel
|
||||||
stat_panel = new(src, "statbrowser")
|
stat_panel = new(src, "statbrowser")
|
||||||
stat_panel.subscribe(src, PROC_REF(on_stat_panel_message))
|
stat_panel.subscribe(src, PROC_REF(on_stat_panel_message))
|
||||||
|
|||||||
@@ -42,3 +42,12 @@ SMART_CACHE_ASSETS
|
|||||||
## Useful for developers to debug potential spritesheet issues to determine where the issue is cropping up (either in DM-side sprite generation or in the TGUI-side display of said spritesheet).
|
## Useful for developers to debug potential spritesheet issues to determine where the issue is cropping up (either in DM-side sprite generation or in the TGUI-side display of said spritesheet).
|
||||||
## Will only seek to waste disk space if ran on production.
|
## Will only seek to waste disk space if ran on production.
|
||||||
#SAVE_SPRITESHEETS
|
#SAVE_SPRITESHEETS
|
||||||
|
|
||||||
|
# If configured, this allows server operators to define the persistent origin used for clientside
|
||||||
|
# storage. This must host the same file as available in tgui/public/iframe.html. This is also hosted
|
||||||
|
# on the GitHub Pages site for the /tg/station repository, so does not need to be configured.
|
||||||
|
# If multiple servers use the same domain name, clientside features such as message saving
|
||||||
|
# and chat tabs will be persistent across both.
|
||||||
|
# If this setting is not configured, but the webroot CDN is, that will be used instead of GitHub Pages.
|
||||||
|
# If this setting is mpty, and the webroot CDN is disabled, byondstorage will be used.
|
||||||
|
# STORAGE_CDN_IFRAME https://vorestation.github.io/byond-client-storage/iframe.html
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
author: "CHOMPStation2StaffMirrorBot"
|
|
||||||
delete-after: True
|
|
||||||
changes:
|
|
||||||
- bugfix: "sun subsystem overruns"
|
|
||||||
- bugfix: "nightshift subsystem overruns"
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
author: "Will"
|
|
||||||
delete-after: True
|
|
||||||
changes:
|
|
||||||
- bugfix: "Phased shadekin are no longer knocked down or thrown when a shuttle they are inside of moves."
|
|
||||||
@@ -31,3 +31,14 @@
|
|||||||
FluffMedic:
|
FluffMedic:
|
||||||
- bugfix: A certain Tyr boss mechanic functions as intended, and one tyr wrecked
|
- bugfix: A certain Tyr boss mechanic functions as intended, and one tyr wrecked
|
||||||
shuttles is more accurate
|
shuttles is more accurate
|
||||||
|
2025-12-05:
|
||||||
|
CHOMPStation2StaffMirrorBot:
|
||||||
|
- bugfix: windows should no longer be just white from an invalid iframe
|
||||||
|
- admin: re-added the 'reload configuration' verb to reload config from disk
|
||||||
|
- bugfix: fixed the hairs I tried to add a bit ago
|
||||||
|
- bugfix: sun subsystem overruns
|
||||||
|
- bugfix: nightshift subsystem overruns
|
||||||
|
- bugfix: some remaining hitching issues
|
||||||
|
Will:
|
||||||
|
- bugfix: Phased shadekin are no longer knocked down or thrown when a shuttle they
|
||||||
|
are inside of moves.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 204 KiB |
5
tgui/global.d.ts
vendored
5
tgui/global.d.ts
vendored
@@ -63,6 +63,11 @@ type ByondType = {
|
|||||||
*/
|
*/
|
||||||
strictMode: boolean;
|
strictMode: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The external URL for the IndexedDB IFrame to use as the origin
|
||||||
|
*/
|
||||||
|
storageCdn: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a BYOND call.
|
* Makes a BYOND call.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const IMPL_MEMORY = 0;
|
|
||||||
export const IMPL_HUB_STORAGE = 1;
|
export const IMPL_HUB_STORAGE = 1;
|
||||||
|
export const IMPL_IFRAME_INDEXED_DB = 2;
|
||||||
type StorageImplementation = typeof IMPL_MEMORY | typeof IMPL_HUB_STORAGE;
|
|
||||||
|
|
||||||
const KEY_NAME = 'chomp'; // CHOMPEdit - CHOMPStation Localstore
|
const KEY_NAME = 'chomp'; // CHOMPEdit - CHOMPStation Localstore
|
||||||
|
type StorageImplementation =
|
||||||
|
| typeof IMPL_HUB_STORAGE
|
||||||
|
| typeof IMPL_IFRAME_INDEXED_DB;
|
||||||
|
|
||||||
type StorageBackend = {
|
type StorageBackend = {
|
||||||
impl: StorageImplementation;
|
impl: StorageImplementation;
|
||||||
@@ -61,28 +62,154 @@ class HubStorageBackend implements StorageBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IFrameIndexedDbBackend implements StorageBackend {
|
||||||
|
public impl: StorageImplementation;
|
||||||
|
|
||||||
|
private documentElement: HTMLIFrameElement;
|
||||||
|
private iframeWindow: Window;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.impl = IMPL_IFRAME_INDEXED_DB;
|
||||||
|
}
|
||||||
|
|
||||||
|
async ready(): Promise<boolean | null> {
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
const iframeStore = `${Byond.storageCdn}?store=${KEY_NAME}`;
|
||||||
|
iframe.style.display = 'none';
|
||||||
|
this.documentElement = document.body.appendChild(iframe);
|
||||||
|
iframe.src = iframeStore;
|
||||||
|
|
||||||
|
const completePromise: Promise<boolean> = new Promise((resolve) => {
|
||||||
|
fetch(iframeStore, { method: 'HEAD' })
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('message', (message) => {
|
||||||
|
if (message.data === 'ready') {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.documentElement.contentWindow) {
|
||||||
|
return new Promise((res) => res(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.iframeWindow = this.documentElement.contentWindow;
|
||||||
|
|
||||||
|
return completePromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(key: string): Promise<any> {
|
||||||
|
const promise = new Promise((resolve) => {
|
||||||
|
window.addEventListener('message', (message) => {
|
||||||
|
if (message.data.key && message.data.key === key) {
|
||||||
|
resolve(message.data.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.iframeWindow.postMessage({ type: 'get', key: key }, '*');
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(key: string, value: any): Promise<void> {
|
||||||
|
this.iframeWindow.postMessage({ type: 'set', key: key, value: value }, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(key: string): Promise<void> {
|
||||||
|
this.iframeWindow.postMessage({ type: 'remove', key: key }, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
async clear(): Promise<void> {
|
||||||
|
this.iframeWindow.postMessage({ type: 'clear' }, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy(): Promise<void> {
|
||||||
|
document.body.removeChild(this.documentElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web Storage Proxy object, which selects the best backend available
|
* Web Storage Proxy object, which selects the best backend available
|
||||||
* depending on the environment.
|
* depending on the environment.
|
||||||
*/
|
*/
|
||||||
class StorageProxy implements StorageBackend {
|
class StorageProxy implements StorageBackend {
|
||||||
private backendPromise: Promise<StorageBackend>;
|
private backendPromise: Promise<StorageBackend>;
|
||||||
public impl: StorageImplementation = IMPL_MEMORY;
|
public impl: StorageImplementation = IMPL_IFRAME_INDEXED_DB;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.backendPromise = (async () => {
|
this.backendPromise = (async () => {
|
||||||
|
// If we have not enabled byondstorage yet, we need to check
|
||||||
|
// if we can use the IFrame, or if we need to enable byondstorage
|
||||||
|
console.log(`testHubStorage ${testHubStorage()}`);
|
||||||
if (!testHubStorage()) {
|
if (!testHubStorage()) {
|
||||||
|
// If we have an IFrame URL we can use, and we haven't already enabled
|
||||||
|
// byondstorage, we should use the IFrame backend
|
||||||
|
console.log(`storageCdn: ${Byond.storageCdn}`);
|
||||||
|
if (Byond.storageCdn) {
|
||||||
|
const iframe = new IFrameIndexedDbBackend();
|
||||||
|
|
||||||
|
if ((await iframe.ready()) === true) {
|
||||||
|
if (await iframe.get('byondstorage-migrated')) return iframe;
|
||||||
|
|
||||||
|
Byond.winset(null, 'browser-options', '+byondstorage');
|
||||||
|
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
document.addEventListener('byondstorageupdated', async () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const hub = new HubStorageBackend();
|
||||||
|
|
||||||
|
// Migrate these existing settings from byondstorage to the IFrame
|
||||||
|
for (const setting of [
|
||||||
|
'panel-settings',
|
||||||
|
'chat-state',
|
||||||
|
'chat-messages',
|
||||||
|
]) {
|
||||||
|
hub
|
||||||
|
.get(setting)
|
||||||
|
.then((settings) => iframe.set(setting, settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe.set('byondstorage-migrated', true);
|
||||||
|
Byond.winset(null, 'browser-options', '-byondstorage');
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return iframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// IFrame hasn't worked out for us, we'll need to enable byondstorage
|
||||||
|
Byond.winset(null, 'browser-options', '+byondstorage');
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const listener = () => {
|
const listener = () => {
|
||||||
document.removeEventListener('byondstorageupdated', listener);
|
document.removeEventListener('byondstorageupdated', listener);
|
||||||
resolve(new HubStorageBackend());
|
|
||||||
|
// This event is emitted *before* byondstorage is actually created
|
||||||
|
// so we have to wait a little bit before we can use it
|
||||||
|
setTimeout(() => resolve(new HubStorageBackend()), 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('byondstorageupdated', listener);
|
document.addEventListener('byondstorageupdated', listener);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// byondstorage is already enabled, we can use it straight away
|
||||||
return new HubStorageBackend();
|
return new HubStorageBackend();
|
||||||
})() as Promise<StorageBackend>;
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(key: string): Promise<any> {
|
async get(key: string): Promise<any> {
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ export const chatMiddleware = (store) => {
|
|||||||
next(action);
|
next(action);
|
||||||
const page = selectCurrentChatPage(store.getState());
|
const page = selectCurrentChatPage(store.getState());
|
||||||
chatRenderer.changePage(page);
|
chatRenderer.changePage(page);
|
||||||
|
needsUpdate = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type === rebuildChat.type) {
|
if (type === rebuildChat.type) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
// Expose inlined metadata
|
// Expose inlined metadata
|
||||||
Byond.windowId = parseMetaTag('tgui:windowId');
|
Byond.windowId = parseMetaTag('tgui:windowId');
|
||||||
|
Byond.storageCdn = parseMetaTag('tgui:storagecdn');
|
||||||
|
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
window.__windowId__ = Byond.windowId;
|
window.__windowId__ = Byond.windowId;
|
||||||
@@ -397,32 +398,17 @@
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
window
|
||||||
window
|
.showSaveFilePicker(opts)
|
||||||
.showSaveFilePicker(opts)
|
.then(function (file) {
|
||||||
.then((fileHandle) => {
|
return file.createWritable();
|
||||||
fileHandle
|
})
|
||||||
.createWritable()
|
.then(function (file) {
|
||||||
.then((writeableFileHandle) => {
|
return file.write(blob).then(function () {
|
||||||
writeableFileHandle
|
return file.close();
|
||||||
.write(blob)
|
|
||||||
.then(() => {
|
|
||||||
writeableFileHandle.close();
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
})
|
||||||
console.error(e);
|
.catch(function () {});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
tgui/public/helpers.min.js
vendored
2
tgui/public/helpers.min.js
vendored
File diff suppressed because one or more lines are too long
105
tgui/public/iframe.html
Normal file
105
tgui/public/iframe.html
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<!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 = 1;
|
||||||
|
const INDEXED_DB_NAME = 'tgui';
|
||||||
|
const INDEXED_DB_STORE_NAME = 'storage';
|
||||||
|
|
||||||
|
const READ_ONLY = 'readonly';
|
||||||
|
const READ_WRITE = 'readwrite';
|
||||||
|
|
||||||
|
const MAX_MESSAGES = 1000;
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const storeValue = `${urlParams.get('store')}-${INDEXED_DB_NAME}`;
|
||||||
|
|
||||||
|
const dbPromise = new Promise((resolve, reject) => {
|
||||||
|
const indexedDB = window.indexedDB;
|
||||||
|
const req = indexedDB.open(storeValue, INDEXED_DB_VERSION);
|
||||||
|
req.onupgradeneeded = (event) => {
|
||||||
|
try {
|
||||||
|
if (event.oldVersion < 1) {
|
||||||
|
req.result.createObjectStore(INDEXED_DB_STORE_NAME);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
reject(new Error('Failed to upgrade IDB: ' + req.error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
req.onsuccess = () => resolve(req.result);
|
||||||
|
|
||||||
|
req.onerror = () => {
|
||||||
|
reject(new Error('Failed to open IDB: ' + req.error));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
window.parent.postMessage('ready', '*');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<!-- Inlined metadata -->
|
<!-- Inlined metadata -->
|
||||||
<meta id="tgui:windowId" content="[tgui:windowId]" />
|
<meta id="tgui:windowId" content="[tgui:windowId]" />
|
||||||
<meta id="tgui:strictMode" content="[tgui:strictMode]" />
|
<meta id="tgui:strictMode" content="[tgui:strictMode]" />
|
||||||
|
<meta id="tgui:storagecdn" content="[tgui:storagecdn]" />
|
||||||
|
|
||||||
<!-- Early setup -->
|
<!-- Early setup -->
|
||||||
<!-- tgui:helpers -->
|
<!-- tgui:helpers -->
|
||||||
|
|||||||
Reference in New Issue
Block a user