Feat: proxy
This commit is contained in:
parent
a0baded584
commit
2cfdf7fbae
10 changed files with 260 additions and 11 deletions
27
public/sw.js
Normal file
27
public/sw.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
importScripts(
|
||||
"/vu/uv.bundle.js",
|
||||
"/vu/uv.config.js",
|
||||
"/marcs/scramjet.shared.js",
|
||||
"/marcs/scramjet.worker.js"
|
||||
);
|
||||
importScripts(__uv$config.sw || "/vu/uv.sw.js");
|
||||
|
||||
const uv = new UVServiceWorker();
|
||||
const sj = new ScramjetServiceWorker();
|
||||
|
||||
self.addEventListener("fetch", function (event) {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
await sj.loadConfig();
|
||||
if (event.request.url.startsWith(location.origin + __uv$config.prefix)) {
|
||||
return await uv.fetch(event);
|
||||
}
|
||||
else if (sj.route(event)) {
|
||||
return await sj.fetch(event);
|
||||
}
|
||||
else {
|
||||
return await fetch(event.request);
|
||||
}
|
||||
})()
|
||||
);
|
||||
});
|
||||
29
public/vu/uv.config.js
Normal file
29
public/vu/uv.config.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
self.__uv$config = {
|
||||
prefix: "/~/uv/",
|
||||
encodeUrl: function encode(str) {
|
||||
if (!str) return str;
|
||||
return encodeURIComponent(
|
||||
str
|
||||
.toString()
|
||||
.split("")
|
||||
.map((char, ind) => (ind % 2 ? String.fromCharCode(char.charCodeAt() ^ 3) : char))
|
||||
.join("")
|
||||
);
|
||||
},
|
||||
decodeUrl: function decode(str) {
|
||||
if (!str) return str;
|
||||
let [input, ...search] = str.split("?");
|
||||
|
||||
return (
|
||||
decodeURIComponent(input)
|
||||
.split("")
|
||||
.map((char, ind) => (ind % 2 ? String.fromCharCode(char.charCodeAt(0) ^ 3) : char))
|
||||
.join("") + (search.length ? "?" + search.join("?") : "")
|
||||
);
|
||||
},
|
||||
handler: "/vu/uv.handler.js",
|
||||
client: "/vu/uv.client.js",
|
||||
bundle: "/vu/uv.bundle.js",
|
||||
config: "/vu/uv.config.js",
|
||||
sw: "/vu/uv.sw.js"
|
||||
};
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
[
|
||||
{
|
||||
"splash": "Join to our community! https://discord.gg/qsXnhSPtAK"
|
||||
"splash": "Join our community! https://discord.gg/qsXnhSPtAK"
|
||||
},
|
||||
{
|
||||
"splash": "Browse safely!"
|
||||
},
|
||||
{
|
||||
"splash": "Hello World!"
|
||||
},
|
||||
{
|
||||
"splash": "Access with ease!"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ const path = Astro.url.pathname;
|
|||
<h1 class="text-xl font-bold text-(--foreground)"> Radius </h1>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed w-full h-full z-10 flex flex-row pointer-events-auto invisible transition duration-500" id="navigation">
|
||||
<div id="innerNav" class="flex flex-col gap-6 w-72 h-full bg-(--background) border-r border-r-(--border) p-6 transition duration-250 shadow-lg">
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<script>
|
||||
import { Settings } from "@utils/settings.ts";
|
||||
import { SW } from "@utils/proxy.ts";
|
||||
const settings = new Settings();
|
||||
const sw = new SW();
|
||||
|
||||
|
||||
document.addEventListener('astro:after-swap', async () => {
|
||||
//const settings = await Settings.getInstance();
|
||||
settings.theme();
|
||||
});
|
||||
</script>
|
||||
45
src/env.d.ts
vendored
Normal file
45
src/env.d.ts
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
/// <reference types="@titaniumnetwork-dev/ultraviolet/client" />
|
||||
interface SJOptions {
|
||||
prefix: string;
|
||||
globals?: {
|
||||
wrapfn: string;
|
||||
wrapthisfn: string;
|
||||
trysetfn: string;
|
||||
importfn: string;
|
||||
rewritefn: string;
|
||||
metafn: string;
|
||||
setrealmfn: string;
|
||||
pushsourcemapfn: string;
|
||||
};
|
||||
files: {
|
||||
wasm: string;
|
||||
shared: string;
|
||||
worker: string;
|
||||
client: string;
|
||||
sync: string;
|
||||
};
|
||||
flags?: {
|
||||
serviceworkers?: boolean;
|
||||
syncxhr?: boolean;
|
||||
naiiveRewriter?: boolean;
|
||||
strictRewrites?: boolean;
|
||||
rewriterLogs?: boolean;
|
||||
captureErrors?: boolean;
|
||||
cleanErrors?: boolean;
|
||||
scramitize?: boolean;
|
||||
sourcemaps?: boolean;
|
||||
};
|
||||
siteFlags?: {};
|
||||
codec?: {
|
||||
encode: string;
|
||||
decode: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare class ScramjetController {
|
||||
constructor(opts: SJOptions);
|
||||
init(): Promise<void>;
|
||||
encodeUrl(term: string): string;
|
||||
}
|
||||
|
|
@ -3,13 +3,13 @@ import "@styles/themes/default.css";
|
|||
import "@styles/global.css";
|
||||
import "@fontsource/inter";
|
||||
import { ClientRouter } from "astro:transitions";
|
||||
import SettingsLoader from "@components/SettingsLoader.astro";
|
||||
import Loader from "@components/Loader.astro";
|
||||
import Header from "@components/Header.astro";
|
||||
---
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<SettingsLoader transition:persist />
|
||||
<Loader transition:persist />
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
|
|
|
|||
|
|
@ -21,9 +21,35 @@ const randomSplash = genSplash();
|
|||
</div>
|
||||
<div class="flex flex-row items-center gap-2 w-4/5 md:w-[26rem] border border-(--input) rounded-lg h-12 p-2">
|
||||
<Icon name="lucide:search" />
|
||||
<input type="text" name="Search" class="text-md md:text-sm focus-visible:outline-none w-full h-full placeholder:text-(--muted-foreground)" id="search" placeholder="Search the web">
|
||||
<input id="input" type="text" name="Search" class="text-md md:text-sm focus-visible:outline-none w-full h-full placeholder:text-(--muted-foreground)" id="search" placeholder="Search the web">
|
||||
</div>
|
||||
<p class="text-base"> { randomSplash } </p>
|
||||
<p class="text-sm text-center sm:text-base whitespace-nowrap"> { randomSplash } </p>
|
||||
</div>
|
||||
<iframe id="iframe" class="fixed h-[calc(100%-3.5rem)] mt-14 w-full hidden" src="https://example.com" />
|
||||
</div>
|
||||
</Layout>
|
||||
<script>
|
||||
import { SW } from "@utils/proxy.ts";
|
||||
import { Settings } from "@utils/settings.ts";
|
||||
|
||||
const init = async () => {
|
||||
const input = document.getElementById("input") as HTMLInputElement;
|
||||
const iframe = document.getElementById("iframe") as HTMLIFrameElement;
|
||||
input.addEventListener("keypress", async (event: any) => {
|
||||
if (event.key === "Enter") {
|
||||
const sw = SW.getInstance().next().value!;
|
||||
const settings = await Settings.getInstance();
|
||||
await sw.setTransport();
|
||||
iframe.classList.remove("hidden");
|
||||
iframe.src = sw.encodeURL(input.value, 'uv');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("astro:page-load", async () => {
|
||||
try {
|
||||
await init();
|
||||
}
|
||||
catch (_) {}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
119
src/utils/proxy.ts
Normal file
119
src/utils/proxy.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import { BareMuxConnection } from "@mercuryworkshop/bare-mux";
|
||||
import { StoreManager } from "./storage";
|
||||
|
||||
const createScript = (src: string, defer?: boolean) => {
|
||||
const script = document.createElement('script') as HTMLScriptElement;
|
||||
script.src = src;
|
||||
if (defer) script.defer = defer;
|
||||
return document.body.appendChild(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class automatically sets up and handles lots of stuff for us.
|
||||
*
|
||||
* It registers/fixes errors with SW reg
|
||||
* It creates our bareMux worker
|
||||
* And other stuff.
|
||||
*
|
||||
* @example
|
||||
* import { SW } from "@utils/proxy.ts";
|
||||
* const handler = new SW();
|
||||
* //Consume the methods
|
||||
* // Or if an instance is already running
|
||||
* import { SW } from "@utils/proxy.ts";
|
||||
* const handler = SW.getInstance();
|
||||
* //Consume the methods
|
||||
*/
|
||||
class SW {
|
||||
#baremuxConn?: BareMuxConnection;
|
||||
#scramjetController?: ScramjetController;
|
||||
#serviceWorker?: ServiceWorkerRegistration;
|
||||
#storageManager: StoreManager<"radius||settings">;
|
||||
static #instance = new Set();
|
||||
|
||||
static *getInstance() {
|
||||
for (const val of SW.#instance.keys()) {
|
||||
yield val as SW;
|
||||
}
|
||||
}
|
||||
|
||||
#search(input: string, template: string) {
|
||||
try { return new URL(input).toString() } catch (_) {};
|
||||
|
||||
try {
|
||||
const url = new URL(`http://${input}`);
|
||||
if (url.hostname.includes(".")) return url.toString();
|
||||
} catch (_) {};
|
||||
|
||||
return template.replace("%s", encodeURIComponent(input));
|
||||
}
|
||||
|
||||
encodeURL(string: string, proxy: 'uv' | 'scram'): string {
|
||||
const input = this.#search(string, "https://google.com/search?q=%s");
|
||||
return proxy === 'uv' ? `${__uv$config.prefix}${__uv$config.encodeUrl!(input)}` : this.#scramjetController!.encodeUrl(input)
|
||||
}
|
||||
|
||||
async setTransport(transport?: 'epoxy' | 'libcurl') {
|
||||
this.#storageManager.setVal("transport", transport || this.#storageManager.getVal("transport") || 'epoxy');
|
||||
switch(transport) {
|
||||
case 'epoxy': {
|
||||
await this.#baremuxConn!.setTransport("/epoxy/index.mjs", [ { wisp: 'ws://localhost:4321/wisp/' }]);
|
||||
}
|
||||
case 'libcurl': {
|
||||
await this.#baremuxConn!.setTransport("/libcurl/index.mjs", [ { wisp: 'ws://localhost:4321/wisp/' }]);
|
||||
}
|
||||
default: {
|
||||
await this.#baremuxConn!.setTransport("/epoxy/index.mjs", [ { wisp: 'ws://localhost:4321/wisp/' }]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
SW.#instance.add(this);
|
||||
this.#storageManager = new StoreManager("radius||settings");
|
||||
const checkScripts = (): Promise<void> => {
|
||||
return new Promise((resolve) => {
|
||||
const t = setInterval(() => {
|
||||
if (typeof __uv$config !== 'undefined' && typeof ScramjetController !== 'undefined') {
|
||||
clearInterval(t);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
createScript('/vu/uv.bundle.js', true);
|
||||
createScript('/vu/uv.config.js', true);
|
||||
createScript('/marcs/scramjet.controller.js', true);
|
||||
|
||||
checkScripts().then(async () => {
|
||||
this.#baremuxConn = new BareMuxConnection("/erab/worker.js");
|
||||
await this.setTransport();
|
||||
this.#scramjetController = new ScramjetController({
|
||||
prefix: '/~/scramjet/',
|
||||
files: {
|
||||
wasm: "/marcs/scramjet.wasm.wasm",
|
||||
worker: "/marcs/scramjet.worker.js",
|
||||
client: "/marcs/scramjet.client.js",
|
||||
shared: "/marcs/scramjet.shared.js",
|
||||
sync: "/marcs/scramjet.sync.js"
|
||||
},
|
||||
flags: {
|
||||
rewriterLogs: false
|
||||
}
|
||||
});
|
||||
if ("serviceWorker" in navigator) {
|
||||
await this.#scramjetController.init();
|
||||
navigator.serviceWorker.ready.then(async (reg) => {
|
||||
console.log('SW ready to go!');
|
||||
this.#serviceWorker = reg;
|
||||
});
|
||||
navigator.serviceWorker.register("/sw.js", { scope: '/' });
|
||||
}
|
||||
else {
|
||||
throw new Error('Your browser is not supported! This website uses Service Workers heavily.');
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export { SW };
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { StoreManager } from "./storage";
|
||||
|
||||
import { BareMuxConnection } from "@mercuryworkshop/bare-mux";
|
||||
import { SW } from "@utils/proxy.ts";
|
||||
/**
|
||||
* The settings class
|
||||
* Initializes it's own StorageManager, and handles everything within the class itself
|
||||
|
|
@ -22,7 +23,6 @@ class Settings {
|
|||
#storageManager: StoreManager<"radius||settings">;
|
||||
static #instance = new Set();
|
||||
|
||||
|
||||
/**
|
||||
* Method to get the current or other Settings instance(s)
|
||||
*
|
||||
|
|
@ -70,7 +70,7 @@ class Settings {
|
|||
? document.documentElement.className = ''
|
||||
: document.documentElement.className = theme || this.#storageManager.getVal('theme');
|
||||
}
|
||||
|
||||
|
||||
async *#init() {
|
||||
yield this.theme(this.#storageManager.getVal('theme') || 'default');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue