mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 14:30:02 -04:00
threads 🚀🚀🚀
This commit is contained in:
parent
b06605dc52
commit
d433f67d67
8 changed files with 179 additions and 26 deletions
|
@ -7,10 +7,11 @@ const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// change to production when needed
|
// change to production when needed
|
||||||
mode: "production",
|
mode: "development",
|
||||||
entry: {
|
entry: {
|
||||||
shared: join(__dirname, "src/shared/index.ts"),
|
shared: join(__dirname, "src/shared/index.ts"),
|
||||||
worker: join(__dirname, "src/worker/index.ts"),
|
worker: join(__dirname, "src/worker/index.ts"),
|
||||||
|
thread: join(__dirname, "src/thread/thread.ts"),
|
||||||
client: join(__dirname, "src/client/index.ts"),
|
client: join(__dirname, "src/client/index.ts"),
|
||||||
config: join(__dirname, "src/scramjet.config.ts"),
|
config: join(__dirname, "src/scramjet.config.ts"),
|
||||||
codecs: join(__dirname, "src/codecs/index.ts"),
|
codecs: join(__dirname, "src/codecs/index.ts"),
|
||||||
|
|
|
@ -8,6 +8,7 @@ self.$scramjet.config = {
|
||||||
config: "/scram/scramjet.config.js",
|
config: "/scram/scramjet.config.js",
|
||||||
shared: "/scram/scramjet.shared.js",
|
shared: "/scram/scramjet.shared.js",
|
||||||
worker: "/scram/scramjet.worker.js",
|
worker: "/scram/scramjet.worker.js",
|
||||||
|
thread: "/scram/scramjet.thread.js",
|
||||||
client: "/scram/scramjet.client.js",
|
client: "/scram/scramjet.client.js",
|
||||||
codecs: "/scram/scramjet.codecs.js",
|
codecs: "/scram/scramjet.codecs.js",
|
||||||
};
|
};
|
||||||
|
|
46
src/thread/thread.ts
Normal file
46
src/thread/thread.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { rewriteJs } from "../shared/rewriters/js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
onconnect = (e) => {
|
||||||
|
const port = e.ports[0];
|
||||||
|
|
||||||
|
|
||||||
|
console.log("thread: connected to port", port)
|
||||||
|
port.postMessage("ready");
|
||||||
|
|
||||||
|
let syncToken = 0;
|
||||||
|
port.onmessage = ({ data }) => {
|
||||||
|
console.log("thread: received message", data)
|
||||||
|
const [task, ...args] = data;
|
||||||
|
let token = syncToken++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = tasks[task](...args);
|
||||||
|
console.log("thread: task", task, "completed with token", token)
|
||||||
|
port.postMessage({
|
||||||
|
token,
|
||||||
|
result: res
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
port.postMessage({
|
||||||
|
token,
|
||||||
|
error: e.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
port.postMessage("idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const tasks = {
|
||||||
|
"rewriteJs": taskRewriteJs,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function taskRewriteJs(js: ArrayBuffer, origin: string): string {
|
||||||
|
return rewriteJs(js, new URL(origin));
|
||||||
|
}
|
1
src/types.d.ts
vendored
1
src/types.d.ts
vendored
|
@ -37,6 +37,7 @@ declare global {
|
||||||
config: string;
|
config: string;
|
||||||
shared: string;
|
shared: string;
|
||||||
worker: string;
|
worker: string;
|
||||||
|
thread: string;
|
||||||
client: string;
|
client: string;
|
||||||
codecs: string;
|
codecs: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,8 +115,7 @@ export async function swfetch(this: ScramjetServiceWorker, { request }: FetchEve
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "script":
|
case "script":
|
||||||
// responseBody = rewriteJs(await response.text(), url);
|
responseBody = await this.threadpool.rewriteJs(await response.arrayBuffer(), url.toString());
|
||||||
responseBody = rewriteJs(await response.text());
|
|
||||||
break;
|
break;
|
||||||
case "style":
|
case "style":
|
||||||
responseBody = rewriteCss(await response.text(), url);
|
responseBody = rewriteCss(await response.text(), url);
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import { swfetch } from "./fetch";
|
import { swfetch } from "./fetch";
|
||||||
|
import { ScramjetThreadpool } from "./threadpool";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
ScramjetServiceWorker;
|
ScramjetServiceWorker;
|
||||||
ScramjetThread;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ScramjetServiceWorker {
|
export class ScramjetServiceWorker {
|
||||||
client: typeof self.$scramjet.shared.util.BareClient.prototype;
|
client: typeof self.$scramjet.shared.util.BareClient.prototype;
|
||||||
config: typeof self.$scramjet.config;
|
config: typeof self.$scramjet.config;
|
||||||
|
threadpool: ScramjetThreadpool;
|
||||||
|
|
||||||
constructor(config = self.$scramjet.config) {
|
constructor(config = self.$scramjet.config) {
|
||||||
this.client = new self.$scramjet.shared.util.BareClient();
|
this.client = new self.$scramjet.shared.util.BareClient();
|
||||||
if (!config.prefix) config.prefix = "/scramjet/";
|
if (!config.prefix) config.prefix = "/scramjet/";
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
|
||||||
|
this.threadpool = new ScramjetThreadpool();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
route({ request }: FetchEvent) {
|
route({ request }: FetchEvent) {
|
||||||
|
@ -27,6 +31,4 @@ export class ScramjetServiceWorker {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.ScramjetServiceWorker = ScramjetServiceWorker;
|
self.ScramjetServiceWorker = ScramjetServiceWorker;
|
||||||
|
|
92
src/worker/threadpool.ts
Normal file
92
src/worker/threadpool.ts
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
|
||||||
|
type Thread = {
|
||||||
|
handle: MessagePort;
|
||||||
|
ready: boolean;
|
||||||
|
busy: boolean;
|
||||||
|
syncToken: number;
|
||||||
|
promises: Map<number, { resolve, reject }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScramjetThreadpool {
|
||||||
|
threads: Thread[] = [];
|
||||||
|
constructor() {
|
||||||
|
self.addEventListener("message", ({ data }) => {
|
||||||
|
if (data.scramjet$type == "add") {
|
||||||
|
this.spawn(data.handle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn(handle) {
|
||||||
|
const thread = {
|
||||||
|
handle,
|
||||||
|
ready: false,
|
||||||
|
busy: false,
|
||||||
|
syncToken: 0,
|
||||||
|
promises: new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.threads.push(thread);
|
||||||
|
|
||||||
|
thread.handle.onmessage = (e) => {
|
||||||
|
if (e.data === "ready") {
|
||||||
|
thread.ready = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.data === "idle") {
|
||||||
|
thread.busy = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { token, result, error } = e.data;
|
||||||
|
const { resolve, reject } = thread.promises.get(token);
|
||||||
|
thread.promises.delete(token);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.handle.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
pick(): Thread | undefined {
|
||||||
|
const alive = this.threads.filter(t => t.ready);
|
||||||
|
const idle = alive.filter(t => !t.busy);
|
||||||
|
|
||||||
|
// no threads
|
||||||
|
if (!alive.length) return;
|
||||||
|
|
||||||
|
// there is a thread, but it's busy
|
||||||
|
if (!idle.length) return alive[Math.floor(Math.random() * alive.length)];
|
||||||
|
|
||||||
|
// there's an open thread
|
||||||
|
return idle[Math.floor(Math.random() * idle.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
run(task: string, args: any[], transferrable: any[]): Promise<any> {
|
||||||
|
const thread = this.pick();
|
||||||
|
if (!thread) throw new Error("No threads available");
|
||||||
|
thread.busy = true;
|
||||||
|
|
||||||
|
|
||||||
|
let token = thread.syncToken++;
|
||||||
|
|
||||||
|
// console.log("runthread: dispatching task", task, "to thread", thread, "of token", token)
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
thread.promises.set(token, { resolve, reject });
|
||||||
|
|
||||||
|
thread.handle.postMessage([
|
||||||
|
task,
|
||||||
|
...args
|
||||||
|
], transferrable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async rewriteJs(js: ArrayBuffer, origin: string): Promise<string> {
|
||||||
|
return await this.run("rewriteJs", [js, origin], [js]);
|
||||||
|
}
|
||||||
|
}
|
51
static/ui.js
51
static/ui.js
|
@ -1,10 +1,21 @@
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker
|
||||||
.register("./sw.js", {
|
.register("./sw.js")
|
||||||
scope: $scramjet.config.prefix,
|
.then((reg) => {
|
||||||
})
|
reg.update();
|
||||||
.then((reg) => {
|
});
|
||||||
reg.update();
|
|
||||||
});
|
navigator.serviceWorker.ready.then((reg) => {
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
const thread = new SharedWorker($scramjet.config.thread, { name: "thread" + i });
|
||||||
|
|
||||||
|
reg.active.postMessage({
|
||||||
|
scramjet$type: "add",
|
||||||
|
handle: thread.port
|
||||||
|
}, [thread.port]);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const connection = new BareMux.BareMuxConnection("/baremux/worker.js");
|
const connection = new BareMux.BareMuxConnection("/baremux/worker.js");
|
||||||
const flex = css`
|
const flex = css`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -13,21 +24,21 @@ const col = css`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
const store = $store(
|
const store = $store(
|
||||||
{
|
{
|
||||||
url: "https://google.com",
|
url: "https://google.com",
|
||||||
wispurl: "wss://wisp.mercurywork.shop/",
|
wispurl: "wss://wisp.mercurywork.shop/",
|
||||||
bareurl:
|
bareurl:
|
||||||
(location.protocol === "https:" ? "https" : "http") +
|
(location.protocol === "https:" ? "https" : "http") +
|
||||||
"://" +
|
"://" +
|
||||||
location.host +
|
location.host +
|
||||||
"/bare/",
|
"/bare/",
|
||||||
},
|
},
|
||||||
{ ident: "settings", backing: "localstorage", autosave: "auto" }
|
{ ident: "settings", backing: "localstorage", autosave: "auto" }
|
||||||
);
|
);
|
||||||
connection.setTransport("/baremod/index.mjs", [store.bareurl]);
|
connection.setTransport("/baremod/index.mjs", [store.bareurl]);
|
||||||
function App() {
|
function App() {
|
||||||
this.urlencoded = "";
|
this.urlencoded = "";
|
||||||
this.css = `
|
this.css = `
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: #e0def4;
|
color: #e0def4;
|
||||||
|
@ -86,7 +97,7 @@ function App() {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<h1>Percury Unblocker</h1>
|
<h1>Percury Unblocker</h1>
|
||||||
<p>surf the unblocked and mostly buggy web</p>
|
<p>surf the unblocked and mostly buggy web</p>
|
||||||
|
@ -110,5 +121,5 @@ function App() {
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
document.body.appendChild(h(App));
|
document.body.appendChild(h(App));
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue