No more silly globals

This commit is contained in:
MotorTruck1221 2025-01-10 01:27:22 -07:00
parent 1616fa21f2
commit 1bd272ec8d
No known key found for this signature in database
GPG key ID: 08F417E2B8B61EA4
8 changed files with 234 additions and 21 deletions

View file

@ -27,6 +27,7 @@
import { SW, createProxyScripts, checkProxyScripts, createBareMuxConn, setTransport } from "@utils/serviceWorker";
import { Settings } from "@utils/settings";
import { log } from "@utils/index";
import { Marketplace } from "@utils/marketplace";
const titleText = `
_ _ _ _ ____ _
| \\ | | ___| |__ _ _| | __ _ / ___| ___ _ ____ _(_) ___ ___ ___
@ -46,9 +47,11 @@
}
await checkProxyScripts();
const conn = await createBareMuxConn("/baremux/worker.js");
window.sw = new SW(conn);
for await (const _ of Settings.initDefaults()) {};
const { serviceWorker, bareMuxConn, sj } = await window.sw.getSWInfo();
const sw = new SW(conn);
new Marketplace();
// We don't do anything with the values (they aren't even any), so we just are iterating.
for await (const _ of Settings.initDefaults());
const { serviceWorker, bareMuxConn, sj } = await sw.getSWInfo();
log({ type: 'info', bg: true, prefix: true }, `General init completed! \n\nServiceWorker: ${serviceWorker.active?.state} \nBareMuxConn: ${bareMuxConn ? 'Active': 'Not active'} \nScramjetController: ${sj ? 'Active' : 'Not active'}`);
}
const initSettings = async () => {

2
src/global.d.ts vendored
View file

@ -1,10 +1,10 @@
// LEGIT here for ONE global.
import type { Marketplace } from "@utils/marketplace";
import type { SW } from "@utils/serviceWorker";
declare global {
interface Window {
sw: SW;
}
};

View file

@ -49,7 +49,7 @@ import { VERSION } from "astro:env/client";
import { BareClient } from "@mercuryworkshop/bare-mux";
import { defaultStore } from "@utils/storage";
import { Settings } from "@utils/settings";
import { setTransport } from "@utils/serviceWorker";
import { setTransport, SW } from "@utils/serviceWorker";
type Suggestion = {
phrase: string;
@ -81,7 +81,8 @@ import { VERSION } from "astro:env/client";
iframe.src = `${__uv$config.prefix}${__uv$config.encodeUrl!(val)}`;
break;
case "sj":
const { sj } = await window.sw.getSWInfo();
const sw = SW.getInstances().next().value as SW;
const { sj } = await sw.getSWInfo();
iframe.src = sj.encodeUrl(val);
break;
}

View file

@ -1,4 +1,4 @@
import { log } from "./index";
import { Elements, log } from "./index";
import { StoreManager } from "./storage";
import { SettingsVals } from "./values";
@ -54,25 +54,71 @@ interface Theme {
bgImage?: string;
};
/**
* A class where for all of the Marketplace handlers.
* It creates it's own StoreManager where all of it's values will live.
* And it has 2 static items. instances and getInstances.
*
* @example
* //Create a new Marketplace instance
* const mp = new Marketplace();
* //Use one of the very many methods available.
*
* //Get all instances of a Marketplace is as easy as:
* // const mp = Marketplace.getInstances.next().value;
* // Consume and use the class.
*/
class Marketplace {
//create our own subsidized StoreManager with it's own prefix so the marketplace stuff NEVER touches the other data
#storage: StoreManager<"nebula||marketplace">;
static #instances = new Set();
constructor() {
this.#storage = new StoreManager("nebula||marketplace");
log({ type: 'info', bg: true, prefix: true }, 'Marketplace instance created and ready!');
Marketplace.#instances.add(this);
}
/**
* A static method to aquire an instance of a marketplace object.
*
* @example
* //Get the first insatnce available.
* const mp = Marketplace.getInstances.next().value
*
* @example
* // Iterate over every instance
* for (const instance of Marketplace.getInstances()) {
* // Do some work
* }
*/
static *getInstances() {
//Marketplace.instances.forEach((val) => yield val);
for (const item of Marketplace.#instances.keys()) {
yield item;
}
}
/**
* Install a theme into both localstorage AND set the theme.
*
* @example
* const mp = new Marketplace() // OR get an instances from getInstances()
* mp.installTheme({
* name: "testTheme",
* payload: "/packages/testTheme/index.css",
* // video: if you have a bg video, pass it here.
* //bgImage: pass the BG image here if you have one
* });
*/
async installTheme(theme: Theme) {
const themes = this.#storage.getVal(SettingsVals.marketPlace.themes)
? JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.themes))
: [];
const themes = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.themes)) || [];
if (themes.find((t: any) => t === theme.name)) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${theme.name} is already installed!`)
themes.push(theme.name);
this.#storage.setVal(SettingsVals.marketPlace.themes, JSON.stringify(themes));
}
async installPlugin(plugin: Plug) {
const plugins = this.#storage.getVal(SettingsVals.marketPlace.plugins)
? JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins))
: [];
const plugins = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
const plug = plugins.find(({ name }: { name: string }) => name === plugin.name);
if (plug && plug.remove === false) return log({ type: 'error', bg: false, prefix: false, throw: true }, `${plugin.name} is already installed!`);
@ -80,8 +126,140 @@ class Marketplace {
plugins.push({ name: plugin.name, src: plugin.src, type: plugin.type } as unknown as Plug);
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins));
}
async uninstallTheme(theme: Theme) {
const items = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
if (!items.find((th: string) => th === theme.name)) {
return log({ type: 'error', bg: false, prefix: false, throw: true }, `Theme: ${theme.name} is not installed!`);
}
const idx = items.indexOf(theme.name.toLowerCase());
items.splice(idx, 1);
this.#storage.setVal(SettingsVals.marketPlace.themes, JSON.stringify(items));
}
window.mp = Marketplace
async uninstallPlugin(plug: Plug) {
const items = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
const plugin = items.find(({ name }: { name: string }) => name === plug.name.toLowerCase());
if (!plugin) return log({ type: 'error', bg: false, prefix: false, throw: true }, `Plugin: ${plug.name} is not installed!`);
plugin.remove = true;
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(items));
}
async handlePlugins(worker: ServiceWorkerRegistration) {
let plugins = JSON.parse(this.#storage.getVal(SettingsVals.marketPlace.plugins)) || [];
const pagePlugins: SWPagePlugin[] = [];
const swPlugins: SWPlugin[] = [];
if (plugins.length === 0) return log({ type: 'info', bg: false, prefix: true }, 'No plugins to add! Exiting.');
plugins.map(async (plugin: Plug) => {
if (plugin.type === "page") {
const script = await fetch(`/packages/${plugin.name.toLowerCase()}/${plugin.src}`);
const scriptRes = await script.text();
const evaledScript = eval(scriptRes);
const inject = (await evaledScript()) as unknown as SWPagePlugin;
if (!plugin.remove) {
pagePlugins.push({
host: inject.host,
html: inject.html,
injectTo: inject.injectTo,
type: 'page'
});
}
else {
plugins = plugins.filter(({ name }: { name: string }) => name !== plugin.name.toLowerCase());
pagePlugins.push({
remove: true,
host: inject.host,
html: inject.html,
injectTo: inject.injectTo,
type: 'page'
});
}
worker.active?.postMessage(pagePlugins);
}
if (plugin.type === "serviceWorker") {
const s = await fetch(`/packages/${plugin.name.toLowerCase()}/${plugin.src}`);
const sRes = await s.text();
const eScript = eval(sRes);
const inject = (await eScript()) as unknown as SWPlugin;
if (!plugin.remove) {
swPlugins.push({
function: inject.function.toString(),
name: plugin.name,
events: inject.events,
type: 'serviceWorker'
});
}
else {
plugins = plugins.filter(({ name }: { name: string }) => name !== plugin.name.toLowerCase());
swPlugins.push({
remove: true,
function: inject.function.toString(),
name: plugin.name,
events: inject.events,
type: 'serviceWorker'
});
}
worker.active?.postMessage(swPlugins);
}
this.#storage.setVal(SettingsVals.marketPlace.plugins, JSON.stringify(plugins));
});
}
async theme(opts: { type: 'normal', payload: string, sources?: { video?: string, bg?: string }, name: string } | { type: 'remove', payload?: string, sources?: { video?: string, bg?: string }, name?: string }) {
const elems = Elements.select([
{ type: 'id', val: 'stylesheet' },
{ type: 'id', val: 'nebulaVideo' },
{ type: 'id', val: 'nebulaImage' }
]);
const s = Elements.exists<HTMLLinkElement>(await elems.next());
const nv = Elements.exists<HTMLVideoElement>(await elems.next());
const ni = Elements.exists<HTMLImageElement>(await elems.next());
const nvl = this.#storage.getVal(SettingsVals.marketPlace.appearance.video);
const nil = this.#storage.getVal(SettingsVals.marketPlace.appearance.image);
const tsp = this.#storage.getVal(SettingsVals.marketPlace.appearance.theme.payload);
const tsn = this.#storage.getVal(SettingsVals.marketPlace.appearance.theme.name);
const reset = (style: boolean) => {
const st = this.#storage;
if (style) {
st.removeVal(SettingsVals.marketPlace.appearance.theme.name);
st.removeVal(SettingsVals.marketPlace.appearance.theme.payload);
s.href = "/nebula.css";
}
st.removeVal(SettingsVals.marketPlace.appearance.video);
nv.src = "";
st.removeVal(SettingsVals.marketPlace.appearance.image);
ni.style.display = "none";
ni.src = "";
}
if (opts.type === 'remove') return reset(true);
if (opts.sources?.video || nvl) {
reset(false);
if (!nvl) this.#storage.setVal(SettingsVals.marketPlace.appearance.video, opts.sources?.video || nvl);
nv.src = `/packages/${opts.name}/${opts.sources?.video ? opts.sources.video : nvl}`
}
if (opts.sources?.bg || nil) {
reset(false);
if (!nil) this.#storage.setVal(SettingsVals.marketPlace.appearance.image, opts.sources?.bg || nil);
ni.style.display = "block";
ni.src = `/packages/${opts.name}/${opts.sources?.bg ? opts.sources.bg : nil}`
}
if (opts.payload) {
if (tsp !== opts.payload) {
this.#storage.setVal(SettingsVals.marketPlace.appearance.theme.payload, opts.payload);
this.#storage.setVal(SettingsVals.marketPlace.appearance.theme.name, opts.name);
s.href = `/packages/${opts.name}/${opts.payload}`;
}
}
else {
if (tsp) return s.href = `/packages/${tsn}/${tsp}`;
}
}
}
export { Marketplace }

View file

@ -101,7 +101,9 @@ type SWInit = {
class SW {
#init!: SWInit;
#ready: boolean = false;
static #instances = new Set();
constructor(conn: BareMuxConnection) {
SW.#instances.add(this);
const sj = (): ScramjetController => {
const sj = new ScramjetController({
prefix: '/~/scramjet',
@ -134,6 +136,24 @@ class SW {
}
}
/**
* Static method to get an already existing SW class
*
*
* @example
* SW.getInstances.next().value // Get the first instance.
*
* @example
* // Loop through every instance
* for (const sw of SW.getInstances()) {
* console.log(sw) // DO some real work
* }
*/
static *getInstances() {
for (const value of SW.#instances.keys()) {
yield value as SW;
}
}
/**
* Allows you to overrid the items set. Should be used sparingly or never.
*/

View file

@ -1,7 +1,7 @@
import { defaultStore } from "./storage";
import { SettingsVals, WispServers } from "./values";
import { Marketplace } from "./marketplace";
import { setTransport } from "./serviceWorker";
import { setTransport, SW } from "./serviceWorker";
const tab = {
ab: (redirect: string) => {
@ -86,7 +86,8 @@ const proxy = {
defaultStore.setVal(SettingsVals.proxy.wispServer, s);
},
transport: async (t: "libcurl" | "epoxy") => {
const { bareMuxConn } = await window.sw.getSWInfo();
const sw = SW.getInstances().next().value!;
const { bareMuxConn } = await sw.getSWInfo();
await setTransport(bareMuxConn, t as "libcurl" | "epoxy");
defaultStore.setVal(SettingsVals.proxy.transport.key, t);
}

View file

@ -25,9 +25,13 @@ class StoreManager<Prefix extends string /* This is here so I know what prefix i
return localStorage.getItem(`${this.#prefix}||${key}`) as string;
}
setVal(key: string, val: string): void {
log({ type: 'info', bg: false, prefix: true }, `Setting ${key} with value: ${val}`);
localStorage.setItem(`${this.#prefix}||${key}`, val);
}
removeVal(key: string): void {
log({ type: 'info', bg: true, prefix: true }, `Removing ${this.#prefix}||${key}`);
localStorage.removeItem(`${this.#prefix}||${key}`);
}
}
//this is done so I can see the prefix used.

View file

@ -62,7 +62,10 @@ interface SettingsVals {
appearance: {
video: string;
image: string;
themeName: string;
theme: {
payload: string;
name: string;
}
}
}
}
@ -105,7 +108,10 @@ const SettingsVals: SettingsVals = {
appearance: {
video: "video",
image: "image",
themeName: "themeName"
theme: {
name: "themeName",
payload: "themePayload"
}
}
}
}