Revert formatting changes to make PR less noisy
This commit is contained in:
@@ -15,226 +15,226 @@
|
||||
// ─── Worker client ──────────────────────────────────────────────────────────
|
||||
|
||||
class WebWorkerClient {
|
||||
worker = null;
|
||||
worker = null;
|
||||
|
||||
constructor() {
|
||||
this.worker = new Worker("./worker.js");
|
||||
constructor() {
|
||||
this.worker = new Worker('./worker.js');
|
||||
|
||||
this.worker.onmessage = (ev) => {
|
||||
if (!ev.data || !ev.data.kind) return;
|
||||
switch (ev.data.kind) {
|
||||
case "DisplayString":
|
||||
appendFetchLog(ev.data.args.rawString);
|
||||
console.log("[mixfetch response]", ev.data.args.rawString);
|
||||
break;
|
||||
case "Log": {
|
||||
const { message, level } = ev.data.args;
|
||||
const fn = level === "error" ? console.error
|
||||
: level === "warn" ? console.warn
|
||||
: console.log;
|
||||
fn(`[worker/${level}]`, message);
|
||||
break;
|
||||
}
|
||||
case "MixFetchReady":
|
||||
onMixFetchReady();
|
||||
break;
|
||||
case "MixFetchError":
|
||||
onMixFetchError(ev.data.args.error);
|
||||
break;
|
||||
case "StressTestFetchResult":
|
||||
onStressTestFetchResult(ev.data.args);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
startMixFetch = (preferredGateway, setupOpts) => {
|
||||
this.worker.postMessage({ kind: "StartMixFetch", args: { preferredGateway, setupOpts } });
|
||||
};
|
||||
|
||||
doFetch = (target) => {
|
||||
this.worker.postMessage({ kind: "FetchPayload", args: { target } });
|
||||
};
|
||||
|
||||
setGoTimeout = (timeoutMs) => {
|
||||
this.worker.postMessage({ kind: "SetGoTimeout", args: { timeoutMs } });
|
||||
};
|
||||
|
||||
doStressTest = (requests) => {
|
||||
for (const req of requests) {
|
||||
this.worker.postMessage({
|
||||
kind: "StressTestFetch",
|
||||
args: { id: req.id, url: req.url, label: req.label },
|
||||
});
|
||||
this.worker.onmessage = (ev) => {
|
||||
if (!ev.data || !ev.data.kind) return;
|
||||
switch (ev.data.kind) {
|
||||
case 'DisplayString':
|
||||
appendFetchLog(ev.data.args.rawString);
|
||||
console.log('[mixfetch response]', ev.data.args.rawString);
|
||||
break;
|
||||
case 'Log': {
|
||||
const { message, level } = ev.data.args;
|
||||
const fn = level === 'error' ? console.error
|
||||
: level === 'warn' ? console.warn
|
||||
: console.log;
|
||||
fn(`[worker/${level}]`, message);
|
||||
break;
|
||||
}
|
||||
case 'MixFetchReady':
|
||||
onMixFetchReady();
|
||||
break;
|
||||
case 'MixFetchError':
|
||||
onMixFetchError(ev.data.args.error);
|
||||
break;
|
||||
case 'StressTestFetchResult':
|
||||
onStressTestFetchResult(ev.data.args);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
startMixFetch = (preferredGateway, setupOpts) => {
|
||||
this.worker.postMessage({ kind: 'StartMixFetch', args: { preferredGateway, setupOpts } });
|
||||
};
|
||||
|
||||
doFetch = (target) => {
|
||||
this.worker.postMessage({ kind: 'FetchPayload', args: { target } });
|
||||
};
|
||||
|
||||
setGoTimeout = (timeoutMs) => {
|
||||
this.worker.postMessage({ kind: 'SetGoTimeout', args: { timeoutMs } });
|
||||
};
|
||||
|
||||
doStressTest = (requests) => {
|
||||
for (const req of requests) {
|
||||
this.worker.postMessage({
|
||||
kind: 'StressTestFetch',
|
||||
args: { id: req.id, url: req.url, label: req.label },
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Startup ────────────────────────────────────────────────────────────────
|
||||
|
||||
let client = null;
|
||||
const DEFAULT_GATEWAY = "q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1";
|
||||
const DEFAULT_GATEWAY = 'q2A2cbooyC16YJzvdYaSMH9X3cSiieZNtfBr8cE8Fi1';
|
||||
|
||||
async function main() {
|
||||
client = new WebWorkerClient();
|
||||
client = new WebWorkerClient();
|
||||
|
||||
document.querySelector("#start-mixfetch").onclick = () => {
|
||||
const gatewayMode = document.querySelector('input[name="gateway-mode"]:checked').value;
|
||||
const preferredGateway = gatewayMode === "default" ? DEFAULT_GATEWAY : undefined;
|
||||
document.querySelector('#start-mixfetch').onclick = () => {
|
||||
const gatewayMode = document.querySelector('input[name="gateway-mode"]:checked').value;
|
||||
const preferredGateway = gatewayMode === 'default' ? DEFAULT_GATEWAY : undefined;
|
||||
|
||||
const setupOpts = {
|
||||
forceTls: document.getElementById("opt-force-tls").checked,
|
||||
clientId: document.getElementById("opt-client-id").value,
|
||||
disablePoisson: document.getElementById("opt-disable-poisson").checked,
|
||||
disableCover: document.getElementById("opt-disable-cover").checked,
|
||||
requestTimeoutMs: parseInt(document.getElementById("opt-request-timeout").value, 10),
|
||||
const setupOpts = {
|
||||
forceTls: document.getElementById('opt-force-tls').checked,
|
||||
clientId: document.getElementById('opt-client-id').value,
|
||||
disablePoisson: document.getElementById('opt-disable-poisson').checked,
|
||||
disableCover: document.getElementById('opt-disable-cover').checked,
|
||||
requestTimeoutMs: parseInt(document.getElementById('opt-request-timeout').value, 10),
|
||||
};
|
||||
|
||||
document.querySelector('#start-mixfetch').disabled = true;
|
||||
document.querySelectorAll('input[name="gateway-mode"]').forEach((r) => (r.disabled = true));
|
||||
updateStatus('mixfetch-status', 'Starting...', 'orange');
|
||||
|
||||
// Sync the stress-test Go timeout to match the configured request timeout
|
||||
document.getElementById('stress-go-timeout').value = setupOpts.requestTimeoutMs;
|
||||
|
||||
console.log(`Starting MixFetch (${gatewayMode} gateway${preferredGateway ? `: ${preferredGateway}` : ''})...`);
|
||||
console.log('Setup options:', setupOpts);
|
||||
client.startMixFetch(preferredGateway, setupOpts);
|
||||
};
|
||||
|
||||
document.querySelector("#start-mixfetch").disabled = true;
|
||||
document.querySelectorAll('input[name="gateway-mode"]').forEach((r) => (r.disabled = true));
|
||||
updateStatus("mixfetch-status", "Starting...", "orange");
|
||||
document.querySelector('#fetch-button-1').onclick = () => doFetch(1);
|
||||
document.querySelector('#fetch-button-2').onclick = () => doFetch(2);
|
||||
|
||||
// Sync the stress-test Go timeout to match the configured request timeout
|
||||
document.getElementById("stress-go-timeout").value = setupOpts.requestTimeoutMs;
|
||||
|
||||
console.log(`Starting MixFetch (${gatewayMode} gateway${preferredGateway ? `: ${preferredGateway}` : ""})...`);
|
||||
console.log("Setup options:", setupOpts);
|
||||
client.startMixFetch(preferredGateway, setupOpts);
|
||||
};
|
||||
|
||||
document.querySelector("#fetch-button-1").onclick = () => doFetch(1);
|
||||
document.querySelector("#fetch-button-2").onclick = () => doFetch(2);
|
||||
|
||||
const stressModeSelect = document.getElementById("stress-test-mode");
|
||||
stressModeSelect.onchange = function () {
|
||||
document.getElementById("stress-uniform-opts").style.display = this.value === "uniform" ? "block" : "none";
|
||||
document.getElementById("stress-mixed-opts").style.display = this.value === "mixed" ? "block" : "none";
|
||||
document.getElementById("stress-drip-opts").style.display = this.value === "drip" ? "block" : "none";
|
||||
};
|
||||
|
||||
document.querySelector("#stress-test-button").onclick = () => {
|
||||
const count = parseInt(document.getElementById("stress-test-count").value, 10);
|
||||
const mode = document.getElementById("stress-test-mode").value;
|
||||
const goTimeoutMs = parseInt(document.getElementById("stress-go-timeout").value, 10);
|
||||
|
||||
document.querySelector("#stress-test-button").disabled = true;
|
||||
updateStatus("stress-test-status", "Running...", "orange");
|
||||
client.setGoTimeout(goTimeoutMs);
|
||||
|
||||
const requests = generateStressRequests(count, mode, goTimeoutMs);
|
||||
stressTest = {
|
||||
count,
|
||||
mode,
|
||||
startTime: performance.now(),
|
||||
results: [],
|
||||
completionOrder: [],
|
||||
profiles: {},
|
||||
const stressModeSelect = document.getElementById('stress-test-mode');
|
||||
stressModeSelect.onchange = function () {
|
||||
document.getElementById('stress-uniform-opts').style.display = this.value === 'uniform' ? 'block' : 'none';
|
||||
document.getElementById('stress-mixed-opts').style.display = this.value === 'mixed' ? 'block' : 'none';
|
||||
document.getElementById('stress-drip-opts').style.display = this.value === 'drip' ? 'block' : 'none';
|
||||
};
|
||||
for (const req of requests) {
|
||||
stressTest.profiles[req.id] = { label: req.label, bytes: req.bytes };
|
||||
}
|
||||
|
||||
initStressTracker(requests);
|
||||
document.querySelector('#stress-test-button').onclick = () => {
|
||||
const count = parseInt(document.getElementById('stress-test-count').value, 10);
|
||||
const mode = document.getElementById('stress-test-mode').value;
|
||||
const goTimeoutMs = parseInt(document.getElementById('stress-go-timeout').value, 10);
|
||||
|
||||
console.log(`%c=== STRESS TEST: ${count} requests, ${mode} mode, timeout=${goTimeoutMs}ms ===`, "font-weight: bold");
|
||||
document.querySelector('#stress-test-button').disabled = true;
|
||||
updateStatus('stress-test-status', 'Running...', 'orange');
|
||||
client.setGoTimeout(goTimeoutMs);
|
||||
|
||||
if (mode === "mixed" || mode === "drip") {
|
||||
const breakdown = {};
|
||||
for (const req of requests) breakdown[req.label] = (breakdown[req.label] || 0) + 1;
|
||||
console.log("Profiles:", breakdown);
|
||||
}
|
||||
const requests = generateStressRequests(count, mode, goTimeoutMs);
|
||||
stressTest = {
|
||||
count,
|
||||
mode,
|
||||
startTime: performance.now(),
|
||||
results: [],
|
||||
completionOrder: [],
|
||||
profiles: {},
|
||||
};
|
||||
for (const req of requests) {
|
||||
stressTest.profiles[req.id] = { label: req.label, bytes: req.bytes };
|
||||
}
|
||||
|
||||
client.doStressTest(requests);
|
||||
};
|
||||
initStressTracker(requests);
|
||||
|
||||
console.log(`%c=== STRESS TEST: ${count} requests, ${mode} mode, timeout=${goTimeoutMs}ms ===`, 'font-weight: bold');
|
||||
|
||||
if (mode === 'mixed' || mode === 'drip') {
|
||||
const breakdown = {};
|
||||
for (const req of requests) breakdown[req.label] = (breakdown[req.label] || 0) + 1;
|
||||
console.log('Profiles:', breakdown);
|
||||
}
|
||||
|
||||
client.doStressTest(requests);
|
||||
};
|
||||
}
|
||||
|
||||
// ─── UI helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
function updateStatus(elementId, text, color) {
|
||||
const el = document.getElementById(elementId);
|
||||
el.textContent = text;
|
||||
el.style.color = color;
|
||||
const el = document.getElementById(elementId);
|
||||
el.textContent = text;
|
||||
el.style.color = color;
|
||||
}
|
||||
|
||||
function onMixFetchReady() {
|
||||
updateStatus("mixfetch-status", "Ready", "green");
|
||||
document.getElementById("fetch-controls").disabled = false;
|
||||
console.log("%cMixFetch ready!", "color: green; font-weight: bold");
|
||||
updateStatus('mixfetch-status', 'Ready', 'green');
|
||||
document.getElementById('fetch-controls').disabled = false;
|
||||
console.log('%cMixFetch ready!', 'color: green; font-weight: bold');
|
||||
}
|
||||
|
||||
function onMixFetchError(error) {
|
||||
updateStatus("mixfetch-status", "Error: " + error, "red");
|
||||
document.querySelector("#start-mixfetch").disabled = false;
|
||||
document.querySelectorAll('input[name="gateway-mode"]').forEach((r) => (r.disabled = false));
|
||||
console.error("MixFetch error:", error);
|
||||
updateStatus('mixfetch-status', 'Error: ' + error, 'red');
|
||||
document.querySelector('#start-mixfetch').disabled = false;
|
||||
document.querySelectorAll('input[name="gateway-mode"]').forEach((r) => (r.disabled = false));
|
||||
console.error('MixFetch error:', error);
|
||||
}
|
||||
|
||||
// ─── Quick fetch ────────────────────────────────────────────────────────────
|
||||
|
||||
function appendFetchLog(text) {
|
||||
const log = document.getElementById("fetch-log");
|
||||
log.style.display = "block";
|
||||
const ts = new Date().toISOString().substr(11, 12);
|
||||
log.textContent += `${ts} ${text}\n`;
|
||||
log.scrollTop = log.scrollHeight;
|
||||
const log = document.getElementById('fetch-log');
|
||||
log.style.display = 'block';
|
||||
const ts = new Date().toISOString().substr(11, 12);
|
||||
log.textContent += `${ts} ${text}\n`;
|
||||
log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
|
||||
async function doFetch(id) {
|
||||
const url = document.getElementById(`fetch_payload_${id}`).value;
|
||||
appendFetchLog(`GET ${url}`);
|
||||
console.log(`GET ${url}`);
|
||||
await client.doFetch(url);
|
||||
const url = document.getElementById(`fetch_payload_${id}`).value;
|
||||
appendFetchLog(`GET ${url}`);
|
||||
console.log(`GET ${url}`);
|
||||
await client.doFetch(url);
|
||||
}
|
||||
|
||||
// ─── Stress test ────────────────────────────────────────────────────────────
|
||||
|
||||
const STRESS_PROFILES = [
|
||||
{ label: "tiny", bytes: 128 },
|
||||
{ label: "small", bytes: 1024 },
|
||||
{ label: "medium", bytes: 10240 },
|
||||
{ label: "large", bytes: 102400 },
|
||||
{ label: "xlarge", bytes: 1048576 },
|
||||
{ label: 'tiny', bytes: 128 },
|
||||
{ label: 'small', bytes: 1024 },
|
||||
{ label: 'medium', bytes: 10240 },
|
||||
{ label: 'large', bytes: 102400 },
|
||||
{ label: 'xlarge', bytes: 1048576 },
|
||||
];
|
||||
|
||||
function buildDripProfiles(timeoutSec) {
|
||||
return [
|
||||
{ label: "safe", dripDuration: Math.round(timeoutSec * 0.50), dripDelay: 0, dripBytes: 100 },
|
||||
{ label: "boundary", dripDuration: Math.round(timeoutSec * 0.92), dripDelay: 0, dripBytes: 100 },
|
||||
{ label: "over", dripDuration: Math.round(timeoutSec * 1.08), dripDelay: 0, dripBytes: 100 },
|
||||
{ label: "slow-start", dripDuration: Math.round(timeoutSec * 0.83), dripDelay: Math.round(timeoutSec * 0.17), dripBytes: 100 },
|
||||
];
|
||||
return [
|
||||
{ label: 'safe', dripDuration: Math.round(timeoutSec * 0.50), dripDelay: 0, dripBytes: 100 },
|
||||
{ label: 'boundary', dripDuration: Math.round(timeoutSec * 0.92), dripDelay: 0, dripBytes: 100 },
|
||||
{ label: 'over', dripDuration: Math.round(timeoutSec * 1.08), dripDelay: 0, dripBytes: 100 },
|
||||
{ label: 'slow-start', dripDuration: Math.round(timeoutSec * 0.83), dripDelay: Math.round(timeoutSec * 0.17), dripBytes: 100 },
|
||||
];
|
||||
}
|
||||
|
||||
function generateStressRequests(count, mode, timeoutMs) {
|
||||
const requests = [];
|
||||
if (mode === "uniform") {
|
||||
const baseUrl = document.getElementById("stress-test-url").value;
|
||||
for (let i = 1; i <= count; i++) {
|
||||
requests.push({ id: i, url: `${baseUrl}${i}`, label: "uniform", bytes: null });
|
||||
const requests = [];
|
||||
if (mode === 'uniform') {
|
||||
const baseUrl = document.getElementById('stress-test-url').value;
|
||||
for (let i = 1; i <= count; i++) {
|
||||
requests.push({ id: i, url: `${baseUrl}${i}`, label: 'uniform', bytes: null });
|
||||
}
|
||||
} else if (mode === 'drip') {
|
||||
const dripProfiles = buildDripProfiles(timeoutMs / 1000);
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const p = dripProfiles[Math.floor(Math.random() * dripProfiles.length)];
|
||||
requests.push({
|
||||
id: i,
|
||||
url: `https://httpbin.org/drip?duration=${p.dripDuration}&numbytes=${p.dripBytes}&delay=${p.dripDelay}&code=200`,
|
||||
label: p.label,
|
||||
bytes: p.dripBytes,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const p = STRESS_PROFILES[Math.floor(Math.random() * STRESS_PROFILES.length)];
|
||||
requests.push({
|
||||
id: i,
|
||||
url: `https://httpbin.org/bytes/${p.bytes}`,
|
||||
label: p.label,
|
||||
bytes: p.bytes,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (mode === "drip") {
|
||||
const dripProfiles = buildDripProfiles(timeoutMs / 1000);
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const p = dripProfiles[Math.floor(Math.random() * dripProfiles.length)];
|
||||
requests.push({
|
||||
id: i,
|
||||
url: `https://httpbin.org/drip?duration=${p.dripDuration}&numbytes=${p.dripBytes}&delay=${p.dripDelay}&code=200`,
|
||||
label: p.label,
|
||||
bytes: p.dripBytes,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const p = STRESS_PROFILES[Math.floor(Math.random() * STRESS_PROFILES.length)];
|
||||
requests.push({
|
||||
id: i,
|
||||
url: `https://httpbin.org/bytes/${p.bytes}`,
|
||||
label: p.label,
|
||||
bytes: p.bytes,
|
||||
});
|
||||
}
|
||||
}
|
||||
return requests;
|
||||
return requests;
|
||||
}
|
||||
|
||||
let stressTest = null;
|
||||
@@ -243,125 +243,125 @@ let stressTest = null;
|
||||
let trackerData = {};
|
||||
|
||||
function initStressTracker(requests) {
|
||||
const tracker = document.getElementById("stress-tracker");
|
||||
tracker.style.display = "block";
|
||||
trackerData = {};
|
||||
const tracker = document.getElementById('stress-tracker');
|
||||
tracker.style.display = 'block';
|
||||
trackerData = {};
|
||||
|
||||
// Count how many of each profile were sent
|
||||
for (const req of requests) {
|
||||
if (!trackerData[req.label]) {
|
||||
trackerData[req.label] = { sent: 0, ok: 0, fail: 0, times: [] };
|
||||
// Count how many of each profile were sent
|
||||
for (const req of requests) {
|
||||
if (!trackerData[req.label]) {
|
||||
trackerData[req.label] = { sent: 0, ok: 0, fail: 0, times: [] };
|
||||
}
|
||||
trackerData[req.label].sent++;
|
||||
}
|
||||
trackerData[req.label].sent++;
|
||||
}
|
||||
|
||||
renderTracker();
|
||||
renderTracker();
|
||||
}
|
||||
|
||||
function renderTracker() {
|
||||
const tracker = document.getElementById("stress-tracker");
|
||||
const rows = Object.entries(trackerData).map(([label, d]) => {
|
||||
const pending = d.sent - d.ok - d.fail;
|
||||
const avg = d.times.length > 0
|
||||
? (d.times.reduce((a, b) => a + b, 0) / d.times.length).toFixed(1) + "s"
|
||||
: "-";
|
||||
const max = d.times.length > 0 ? Math.max(...d.times).toFixed(1) + "s" : "-";
|
||||
const min = d.times.length > 0 ? Math.min(...d.times).toFixed(1) + "s" : "-";
|
||||
const tracker = document.getElementById('stress-tracker');
|
||||
const rows = Object.entries(trackerData).map(([label, d]) => {
|
||||
const pending = d.sent - d.ok - d.fail;
|
||||
const avg = d.times.length > 0
|
||||
? (d.times.reduce((a, b) => a + b, 0) / d.times.length).toFixed(1) + 's'
|
||||
: '-';
|
||||
const max = d.times.length > 0 ? Math.max(...d.times).toFixed(1) + 's' : '-';
|
||||
const min = d.times.length > 0 ? Math.min(...d.times).toFixed(1) + 's' : '-';
|
||||
|
||||
let status = "";
|
||||
if (d.ok > 0) status += `<span style="color: green">${d.ok} ok</span>`;
|
||||
if (d.fail > 0) status += `${status ? " " : ""}<span style="color: red">${d.fail} fail</span>`;
|
||||
if (pending > 0) status += `${status ? " " : ""}<span style="color: gray">${pending} pending</span>`;
|
||||
let status = '';
|
||||
if (d.ok > 0) status += `<span style="color: green">${d.ok} ok</span>`;
|
||||
if (d.fail > 0) status += `${status ? ' ' : ''}<span style="color: red">${d.fail} fail</span>`;
|
||||
if (pending > 0) status += `${status ? ' ' : ''}<span style="color: gray">${pending} pending</span>`;
|
||||
|
||||
let timing = "";
|
||||
if (d.times.length > 0) {
|
||||
timing = `avg ${avg} / min ${min} / max ${max}`;
|
||||
}
|
||||
let timing = '';
|
||||
if (d.times.length > 0) {
|
||||
timing = `avg ${avg} / min ${min} / max ${max}`;
|
||||
}
|
||||
|
||||
return `<tr>
|
||||
<td style="padding: 2px 8px; font-weight: bold">${label}</td>
|
||||
<td style="padding: 2px 8px">${d.sent}</td>
|
||||
<td style="padding: 2px 8px">${status}</td>
|
||||
<td style="padding: 2px 8px; color: #666">${timing}</td>
|
||||
</tr>`;
|
||||
});
|
||||
return `<tr>
|
||||
<td style="padding: 2px 8px; font-weight: bold">${label}</td>
|
||||
<td style="padding: 2px 8px">${d.sent}</td>
|
||||
<td style="padding: 2px 8px">${status}</td>
|
||||
<td style="padding: 2px 8px; color: #666">${timing}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
tracker.innerHTML = `<table style="border-collapse: collapse">
|
||||
<tr style="border-bottom: 1px solid #ccc">
|
||||
<th style="padding: 2px 8px; text-align: left">profile</th>
|
||||
<th style="padding: 2px 8px; text-align: left">sent</th>
|
||||
<th style="padding: 2px 8px; text-align: left">status</th>
|
||||
<th style="padding: 2px 8px; text-align: left">timing</th>
|
||||
</tr>
|
||||
${rows.join("")}
|
||||
</table>`;
|
||||
tracker.innerHTML = `<table style="border-collapse: collapse">
|
||||
<tr style="border-bottom: 1px solid #ccc">
|
||||
<th style="padding: 2px 8px; text-align: left">profile</th>
|
||||
<th style="padding: 2px 8px; text-align: left">sent</th>
|
||||
<th style="padding: 2px 8px; text-align: left">status</th>
|
||||
<th style="padding: 2px 8px; text-align: left">timing</th>
|
||||
</tr>
|
||||
${rows.join('')}
|
||||
</table>`;
|
||||
}
|
||||
|
||||
function onStressTestFetchResult(result) {
|
||||
if (!stressTest) return;
|
||||
if (!stressTest) return;
|
||||
|
||||
const profile = stressTest.profiles[result.id];
|
||||
result.label = profile ? profile.label : "?";
|
||||
const profile = stressTest.profiles[result.id];
|
||||
result.label = profile ? profile.label : '?';
|
||||
|
||||
stressTest.results.push(result);
|
||||
stressTest.completionOrder.push(result.id);
|
||||
stressTest.results.push(result);
|
||||
stressTest.completionOrder.push(result.id);
|
||||
|
||||
// Update tracker
|
||||
const td = trackerData[result.label];
|
||||
if (td) {
|
||||
if (result.ok) {
|
||||
td.ok++;
|
||||
td.times.push(parseFloat(result.elapsed));
|
||||
} else {
|
||||
td.fail++;
|
||||
}
|
||||
renderTracker();
|
||||
}
|
||||
|
||||
const progress = `${stressTest.results.length}/${stressTest.count}`;
|
||||
const tag = `#${result.id} ${result.label}`;
|
||||
|
||||
// Update tracker
|
||||
const td = trackerData[result.label];
|
||||
if (td) {
|
||||
if (result.ok) {
|
||||
td.ok++;
|
||||
td.times.push(parseFloat(result.elapsed));
|
||||
console.log(`%c[${tag}] ${result.status} OK ${result.elapsed}s ${result.textLength}B (${progress})`, 'color: green');
|
||||
} else {
|
||||
td.fail++;
|
||||
}
|
||||
renderTracker();
|
||||
}
|
||||
|
||||
const progress = `${stressTest.results.length}/${stressTest.count}`;
|
||||
const tag = `#${result.id} ${result.label}`;
|
||||
|
||||
if (result.ok) {
|
||||
console.log(`%c[${tag}] ${result.status} OK ${result.elapsed}s ${result.textLength}B (${progress})`, "color: green");
|
||||
} else {
|
||||
console.error(`[${tag}] FAIL ${result.elapsed}s ${result.error} (${progress})`);
|
||||
}
|
||||
|
||||
updateStatus("stress-test-status", progress, "orange");
|
||||
|
||||
// Summary on completion
|
||||
if (stressTest.results.length === stressTest.count) {
|
||||
const totalElapsed = ((performance.now() - stressTest.startTime) / 1000).toFixed(2);
|
||||
const succeeded = stressTest.results.filter((r) => r.ok).length;
|
||||
const failed = stressTest.results.filter((r) => !r.ok).length;
|
||||
|
||||
console.log(`%c=== COMPLETE: ${totalElapsed}s | OK ${succeeded}/${stressTest.count} | Failed ${failed}/${stressTest.count} ===`, "font-weight: bold");
|
||||
console.log("Completion order:", stressTest.completionOrder);
|
||||
|
||||
// Per-profile breakdown in console
|
||||
const profileLabels = Object.keys(trackerData);
|
||||
const profileList = profileLabels.map((label) => ({ label }));
|
||||
if (stressTest.mode === "mixed" || stressTest.mode === "drip") {
|
||||
const table = [];
|
||||
for (const profile of profileList) {
|
||||
const matching = stressTest.results.filter((r) => r.label === profile.label);
|
||||
if (matching.length === 0) continue;
|
||||
const ok = matching.filter((r) => r.ok).length;
|
||||
const times = matching.filter((r) => r.ok).map((r) => parseFloat(r.elapsed));
|
||||
const avg = times.length > 0 ? (times.reduce((a, b) => a + b, 0) / times.length).toFixed(2) : "-";
|
||||
const max = times.length > 0 ? Math.max(...times).toFixed(2) : "-";
|
||||
table.push({ profile: profile.label, ok: `${ok}/${matching.length}`, avg: `${avg}s`, max: `${max}s` });
|
||||
}
|
||||
console.table(table);
|
||||
console.error(`[${tag}] FAIL ${result.elapsed}s ${result.error} (${progress})`);
|
||||
}
|
||||
|
||||
updateStatus("stress-test-status",
|
||||
`Done: ${succeeded}/${stressTest.count} OK, ${failed} failed (${totalElapsed}s)`,
|
||||
failed > 0 ? "red" : "green"
|
||||
);
|
||||
document.querySelector("#stress-test-button").disabled = false;
|
||||
stressTest = null;
|
||||
}
|
||||
updateStatus('stress-test-status', progress, 'orange');
|
||||
|
||||
// Summary on completion
|
||||
if (stressTest.results.length === stressTest.count) {
|
||||
const totalElapsed = ((performance.now() - stressTest.startTime) / 1000).toFixed(2);
|
||||
const succeeded = stressTest.results.filter((r) => r.ok).length;
|
||||
const failed = stressTest.results.filter((r) => !r.ok).length;
|
||||
|
||||
console.log(`%c=== COMPLETE: ${totalElapsed}s | OK ${succeeded}/${stressTest.count} | Failed ${failed}/${stressTest.count} ===`, 'font-weight: bold');
|
||||
console.log('Completion order:', stressTest.completionOrder);
|
||||
|
||||
// Per-profile breakdown in console
|
||||
const profileLabels = Object.keys(trackerData);
|
||||
const profileList = profileLabels.map((label) => ({ label }));
|
||||
if (stressTest.mode === 'mixed' || stressTest.mode === 'drip') {
|
||||
const table = [];
|
||||
for (const profile of profileList) {
|
||||
const matching = stressTest.results.filter((r) => r.label === profile.label);
|
||||
if (matching.length === 0) continue;
|
||||
const ok = matching.filter((r) => r.ok).length;
|
||||
const times = matching.filter((r) => r.ok).map((r) => parseFloat(r.elapsed));
|
||||
const avg = times.length > 0 ? (times.reduce((a, b) => a + b, 0) / times.length).toFixed(2) : '-';
|
||||
const max = times.length > 0 ? Math.max(...times).toFixed(2) : '-';
|
||||
table.push({ profile: profile.label, ok: `${ok}/${matching.length}`, avg: `${avg}s`, max: `${max}s` });
|
||||
}
|
||||
console.table(table);
|
||||
}
|
||||
|
||||
updateStatus('stress-test-status',
|
||||
`Done: ${succeeded}/${stressTest.count} OK, ${failed} failed (${totalElapsed}s)`,
|
||||
failed > 0 ? 'red' : 'green'
|
||||
);
|
||||
document.querySelector('#stress-test-button').disabled = false;
|
||||
stressTest = null;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
@@ -15,28 +15,28 @@
|
||||
const RUST_WASM_URL = "mix_fetch_wasm_bg.wasm";
|
||||
const GO_WASM_URL = "go_conn.wasm";
|
||||
|
||||
importScripts("mix_fetch_wasm.js");
|
||||
importScripts("wasm_exec.js");
|
||||
importScripts('mix_fetch_wasm.js');
|
||||
importScripts('wasm_exec.js');
|
||||
|
||||
console.log("Initializing worker");
|
||||
console.log('Initializing worker');
|
||||
|
||||
// wasm_bindgen creates a global variable (with the exports attached) that is in scope after `importScripts`
|
||||
const {
|
||||
default_debug,
|
||||
no_cover_debug,
|
||||
NymClient,
|
||||
set_panic_hook,
|
||||
Config,
|
||||
GatewayEndpointConfig,
|
||||
ClientStorage,
|
||||
MixFetchConfig,
|
||||
send_client_data,
|
||||
start_new_mixnet_connection,
|
||||
setupMixFetch,
|
||||
disconnectMixFetch,
|
||||
setupMixFetchWithConfig,
|
||||
mix_fetch_initialised,
|
||||
finish_mixnet_connection,
|
||||
default_debug,
|
||||
no_cover_debug,
|
||||
NymClient,
|
||||
set_panic_hook,
|
||||
Config,
|
||||
GatewayEndpointConfig,
|
||||
ClientStorage,
|
||||
MixFetchConfig,
|
||||
send_client_data,
|
||||
start_new_mixnet_connection,
|
||||
setupMixFetch,
|
||||
disconnectMixFetch,
|
||||
setupMixFetchWithConfig,
|
||||
mix_fetch_initialised,
|
||||
finish_mixnet_connection,
|
||||
} = wasm_bindgen;
|
||||
|
||||
let client = null;
|
||||
@@ -45,43 +45,43 @@ const go = new Go(); // Defined in wasm_exec.js
|
||||
var goWasm;
|
||||
let mixFetchReady = false;
|
||||
|
||||
function sendLog(message, level = "info") {
|
||||
self.postMessage({
|
||||
kind: "Log",
|
||||
args: { message, level },
|
||||
});
|
||||
function sendLog(message, level = 'info') {
|
||||
self.postMessage({
|
||||
kind: 'Log',
|
||||
args: { message, level },
|
||||
});
|
||||
}
|
||||
|
||||
function sendReady() {
|
||||
self.postMessage({ kind: "MixFetchReady" });
|
||||
self.postMessage({ kind: 'MixFetchReady' });
|
||||
}
|
||||
|
||||
function sendError(error) {
|
||||
self.postMessage({
|
||||
kind: "MixFetchError",
|
||||
args: { error: String(error) },
|
||||
});
|
||||
self.postMessage({
|
||||
kind: 'MixFetchError',
|
||||
args: { error: String(error) },
|
||||
});
|
||||
}
|
||||
|
||||
async function logFetchResult(res) {
|
||||
console.log(res);
|
||||
let text = await res.text();
|
||||
console.log("HEADERS: ", ...res.headers);
|
||||
console.log("STATUS: ", res.status);
|
||||
console.log("STATUS TEXT: ", res.statusText);
|
||||
console.log("OK: ", res.ok);
|
||||
console.log("TYPE: ", res.type);
|
||||
console.log("URL: ", res.url);
|
||||
console.log("BODYUSED: ", res.bodyUsed);
|
||||
console.log("REDIRECTED: ", res.redirected);
|
||||
console.log("TEXT: ", text);
|
||||
console.log(res);
|
||||
let text = await res.text();
|
||||
console.log("HEADERS: ", ...res.headers);
|
||||
console.log("STATUS: ", res.status);
|
||||
console.log("STATUS TEXT: ", res.statusText);
|
||||
console.log("OK: ", res.ok);
|
||||
console.log("TYPE: ", res.type);
|
||||
console.log("URL: ", res.url);
|
||||
console.log("BODYUSED: ", res.bodyUsed);
|
||||
console.log("REDIRECTED: ", res.redirected);
|
||||
console.log("TEXT: ", text);
|
||||
|
||||
self.postMessage({
|
||||
kind: "DisplayString",
|
||||
args: {
|
||||
rawString: text,
|
||||
},
|
||||
});
|
||||
self.postMessage({
|
||||
kind: 'DisplayString',
|
||||
args: {
|
||||
rawString: text,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -110,205 +110,201 @@ async function logFetchResult(res) {
|
||||
*/
|
||||
|
||||
async function nativeSetup(preferredGateway, setupOpts = {}) {
|
||||
sendLog("Setting up MixFetch...");
|
||||
if (preferredGateway) {
|
||||
sendLog(`Using preferred gateway: ${preferredGateway}`);
|
||||
} else {
|
||||
sendLog("Using random gateway selection");
|
||||
}
|
||||
sendLog('Setting up MixFetch...');
|
||||
if (preferredGateway) {
|
||||
sendLog(`Using preferred gateway: ${preferredGateway}`);
|
||||
} else {
|
||||
sendLog('Using random gateway selection');
|
||||
}
|
||||
|
||||
const {
|
||||
forceTls = true,
|
||||
clientId = "my-client",
|
||||
disablePoisson = true,
|
||||
disableCover = true,
|
||||
requestTimeoutMs = 60000,
|
||||
} = setupOpts;
|
||||
const {
|
||||
forceTls = true,
|
||||
clientId = 'my-client',
|
||||
disablePoisson = true,
|
||||
disableCover = true,
|
||||
requestTimeoutMs = 60000,
|
||||
} = setupOpts;
|
||||
|
||||
const noCoverTrafficOverride = {
|
||||
traffic: { disableMainPoissonPacketDistribution: disablePoisson },
|
||||
coverTraffic: { disableLoopCoverTrafficStream: disableCover },
|
||||
};
|
||||
const mixFetchOverride = {
|
||||
requestTimeoutMs,
|
||||
};
|
||||
const noCoverTrafficOverride = {
|
||||
traffic: { disableMainPoissonPacketDistribution: disablePoisson },
|
||||
coverTraffic: { disableLoopCoverTrafficStream: disableCover },
|
||||
};
|
||||
const mixFetchOverride = {
|
||||
requestTimeoutMs,
|
||||
};
|
||||
|
||||
const opts = {
|
||||
forceTls,
|
||||
clientId,
|
||||
clientOverride: noCoverTrafficOverride,
|
||||
mixFetchOverride,
|
||||
};
|
||||
const opts = {
|
||||
forceTls,
|
||||
clientId,
|
||||
clientOverride: noCoverTrafficOverride,
|
||||
mixFetchOverride,
|
||||
};
|
||||
|
||||
if (preferredGateway) {
|
||||
opts.preferredGateway = preferredGateway;
|
||||
}
|
||||
if (preferredGateway) {
|
||||
opts.preferredGateway = preferredGateway;
|
||||
}
|
||||
|
||||
sendLog(
|
||||
`Setup config: forceTls=${forceTls}, clientId=${clientId}, disablePoisson=${disablePoisson}, disableCover=${disableCover}, timeout=${requestTimeoutMs}ms`
|
||||
);
|
||||
sendLog("Calling setupMixFetch...");
|
||||
await setupMixFetch(opts);
|
||||
sendLog("setupMixFetch completed");
|
||||
sendLog(
|
||||
`Setup config: forceTls=${forceTls}, clientId=${clientId}, disablePoisson=${disablePoisson}, disableCover=${disableCover}, timeout=${requestTimeoutMs}ms`
|
||||
);
|
||||
sendLog('Calling setupMixFetch...');
|
||||
await setupMixFetch(opts);
|
||||
sendLog('setupMixFetch completed');
|
||||
}
|
||||
|
||||
async function startMixFetch(preferredGateway, setupOpts) {
|
||||
sendLog("Instantiating MixFetch...");
|
||||
sendLog('Instantiating MixFetch...');
|
||||
|
||||
try {
|
||||
await nativeSetup(preferredGateway, setupOpts);
|
||||
mixFetchReady = true;
|
||||
sendLog("MixFetch client running!");
|
||||
sendReady();
|
||||
} catch (e) {
|
||||
sendLog("Failed to start MixFetch: " + e, "error");
|
||||
sendError(e);
|
||||
}
|
||||
try {
|
||||
await nativeSetup(preferredGateway, setupOpts);
|
||||
mixFetchReady = true;
|
||||
sendLog('MixFetch client running!');
|
||||
sendReady();
|
||||
} catch (e) {
|
||||
sendLog('Failed to start MixFetch: ' + e, 'error');
|
||||
sendError(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFetchPayload(target) {
|
||||
if (!mixFetchReady) {
|
||||
sendLog("MixFetch not ready yet", "error");
|
||||
return;
|
||||
}
|
||||
if (!mixFetchReady) {
|
||||
sendLog('MixFetch not ready yet', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = target;
|
||||
const args = { mode: "unsafe-ignore-cors" };
|
||||
const url = target;
|
||||
const args = { mode: "unsafe-ignore-cors" };
|
||||
|
||||
try {
|
||||
sendLog(`Fetching: ${url}`);
|
||||
const mixFetchRes = await mixFetch(url, args);
|
||||
sendLog("Fetch completed");
|
||||
await logFetchResult(mixFetchRes);
|
||||
} catch (e) {
|
||||
sendLog("Fetch request failure: " + e, "error");
|
||||
console.error("mix fetch request failure: ", e);
|
||||
}
|
||||
try {
|
||||
sendLog(`Fetching: ${url}`);
|
||||
const mixFetchRes = await mixFetch(url, args);
|
||||
sendLog('Fetch completed');
|
||||
await logFetchResult(mixFetchRes);
|
||||
} catch (e) {
|
||||
sendLog('Fetch request failure: ' + e, 'error');
|
||||
console.error("mix fetch request failure: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleStressTestFetch(id, url, label) {
|
||||
if (!mixFetchReady) {
|
||||
sendLog("MixFetch not ready yet", "error");
|
||||
return;
|
||||
}
|
||||
if (!mixFetchReady) {
|
||||
sendLog('MixFetch not ready yet', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const tag = `[stress #${id} ${label}]`;
|
||||
const start = performance.now();
|
||||
const args = { mode: "unsafe-ignore-cors" };
|
||||
const tag = `[stress #${id} ${label}]`;
|
||||
const start = performance.now();
|
||||
const args = { mode: "unsafe-ignore-cors" };
|
||||
|
||||
try {
|
||||
sendLog(`${tag} Fetching: ${url}`);
|
||||
const res = await mixFetch(url, args);
|
||||
const text = await res.text();
|
||||
const elapsed = ((performance.now() - start) / 1000).toFixed(2);
|
||||
sendLog(`${tag} ${res.status} OK in ${elapsed}s (${text.length} bytes)`);
|
||||
self.postMessage({
|
||||
kind: "StressTestFetchResult",
|
||||
args: {
|
||||
id,
|
||||
ok: true,
|
||||
status: res.status,
|
||||
elapsed,
|
||||
textLength: text.length,
|
||||
body: text,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
const elapsed = ((performance.now() - start) / 1000).toFixed(2);
|
||||
sendLog(`${tag} FAILED in ${elapsed}s: ${e}`, "error");
|
||||
self.postMessage({
|
||||
kind: "StressTestFetchResult",
|
||||
args: { id, ok: false, elapsed, error: String(e) },
|
||||
});
|
||||
}
|
||||
try {
|
||||
sendLog(`${tag} Fetching: ${url}`);
|
||||
const res = await mixFetch(url, args);
|
||||
const text = await res.text();
|
||||
const elapsed = ((performance.now() - start) / 1000).toFixed(2);
|
||||
sendLog(`${tag} ${res.status} OK in ${elapsed}s (${text.length} bytes)`);
|
||||
self.postMessage({
|
||||
kind: 'StressTestFetchResult',
|
||||
args: {
|
||||
id,
|
||||
ok: true,
|
||||
status: res.status,
|
||||
elapsed,
|
||||
textLength: text.length,
|
||||
body: text,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
const elapsed = ((performance.now() - start) / 1000).toFixed(2);
|
||||
sendLog(`${tag} FAILED in ${elapsed}s: ${e}`, 'error');
|
||||
self.postMessage({
|
||||
kind: 'StressTestFetchResult',
|
||||
args: { id, ok: false, elapsed, error: String(e) },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setupMessageHandler() {
|
||||
self.onmessage = async (event) => {
|
||||
if (event.data && event.data.kind) {
|
||||
switch (event.data.kind) {
|
||||
case "StartMixFetch": {
|
||||
const { preferredGateway, setupOpts } = event.data.args;
|
||||
await startMixFetch(preferredGateway, setupOpts);
|
||||
break;
|
||||
self.onmessage = async (event) => {
|
||||
if (event.data && event.data.kind) {
|
||||
switch (event.data.kind) {
|
||||
case 'StartMixFetch': {
|
||||
const { preferredGateway, setupOpts } = event.data.args;
|
||||
await startMixFetch(preferredGateway, setupOpts);
|
||||
break;
|
||||
}
|
||||
case 'FetchPayload': {
|
||||
const { target } = event.data.args;
|
||||
await handleFetchPayload(target);
|
||||
break;
|
||||
}
|
||||
case 'SetGoTimeout': {
|
||||
const { timeoutMs } = event.data.args;
|
||||
sendLog(`Setting Go-side request timeout to ${timeoutMs}ms`);
|
||||
self.__go_rs_bridge__.goWasmSetMixFetchRequestTimeout(timeoutMs);
|
||||
break;
|
||||
}
|
||||
case 'StressTestFetch': {
|
||||
const { id, url, label } = event.data.args;
|
||||
// NOT awaited — each request runs independently,
|
||||
// just like separate callers in a real app
|
||||
handleStressTestFetch(id, url, label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case "FetchPayload": {
|
||||
const { target } = event.data.args;
|
||||
await handleFetchPayload(target);
|
||||
break;
|
||||
}
|
||||
case "SetGoTimeout": {
|
||||
const { timeoutMs } = event.data.args;
|
||||
sendLog(`Setting Go-side request timeout to ${timeoutMs}ms`);
|
||||
self.__go_rs_bridge__.goWasmSetMixFetchRequestTimeout(timeoutMs);
|
||||
break;
|
||||
}
|
||||
case "StressTestFetch": {
|
||||
const { id, url, label } = event.data.args;
|
||||
// NOT awaited — each request runs independently,
|
||||
// just like separate callers in a real app
|
||||
handleStressTestFetch(id, url, label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: look into https://www.aaron-powell.com/posts/2019-02-08-golang-wasm-5-compiling-with-webpack/
|
||||
async function loadGoWasm() {
|
||||
const resp = await fetch(GO_WASM_URL);
|
||||
const resp = await fetch(GO_WASM_URL);
|
||||
|
||||
if ("instantiateStreaming" in WebAssembly) {
|
||||
const wasmObj = await WebAssembly.instantiateStreaming(
|
||||
resp,
|
||||
go.importObject
|
||||
);
|
||||
goWasm = wasmObj.instance;
|
||||
go.run(goWasm);
|
||||
} else {
|
||||
const bytes = await resp.arrayBuffer();
|
||||
const wasmObj = await WebAssembly.instantiate(bytes, go.importObject);
|
||||
goWasm = wasmObj.instance;
|
||||
go.run(goWasm);
|
||||
}
|
||||
if ('instantiateStreaming' in WebAssembly) {
|
||||
const wasmObj = await WebAssembly.instantiateStreaming(resp, go.importObject);
|
||||
goWasm = wasmObj.instance;
|
||||
go.run(goWasm);
|
||||
} else {
|
||||
const bytes = await resp.arrayBuffer();
|
||||
const wasmObj = await WebAssembly.instantiate(bytes, go.importObject);
|
||||
goWasm = wasmObj.instance;
|
||||
go.run(goWasm);
|
||||
}
|
||||
}
|
||||
|
||||
function setupRsGoBridge() {
|
||||
// (note: reason for intermediate `__rs_go_bridge__` object is to decrease global scope bloat
|
||||
// and to discourage users from trying to call those methods directly)
|
||||
self.__rs_go_bridge__ = {};
|
||||
self.__rs_go_bridge__.send_client_data = send_client_data;
|
||||
self.__rs_go_bridge__.start_new_mixnet_connection =
|
||||
start_new_mixnet_connection;
|
||||
self.__rs_go_bridge__.mix_fetch_initialised = mix_fetch_initialised;
|
||||
self.__rs_go_bridge__.finish_mixnet_connection = finish_mixnet_connection;
|
||||
// (note: reason for intermediate `__rs_go_bridge__` object is to decrease global scope bloat
|
||||
// and to discourage users from trying to call those methods directly)
|
||||
self.__rs_go_bridge__ = {};
|
||||
self.__rs_go_bridge__.send_client_data = send_client_data;
|
||||
self.__rs_go_bridge__.start_new_mixnet_connection = start_new_mixnet_connection;
|
||||
self.__rs_go_bridge__.mix_fetch_initialised = mix_fetch_initialised;
|
||||
self.__rs_go_bridge__.finish_mixnet_connection = finish_mixnet_connection;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
sendLog("Worker starting...");
|
||||
sendLog('Worker starting...');
|
||||
|
||||
// load rust WASM package
|
||||
sendLog("Loading Rust WASM...");
|
||||
await wasm_bindgen(RUST_WASM_URL);
|
||||
sendLog("Loaded Rust WASM");
|
||||
// load rust WASM package
|
||||
sendLog('Loading Rust WASM...');
|
||||
await wasm_bindgen(RUST_WASM_URL);
|
||||
sendLog('Loaded Rust WASM');
|
||||
|
||||
// load go WASM package
|
||||
sendLog("Loading Go WASM...");
|
||||
await loadGoWasm();
|
||||
sendLog("Loaded Go WASM");
|
||||
// load go WASM package
|
||||
sendLog('Loading Go WASM...');
|
||||
await loadGoWasm();
|
||||
sendLog('Loaded Go WASM');
|
||||
|
||||
// sets up better stack traces in case of in-rust panics
|
||||
set_panic_hook();
|
||||
// sets up better stack traces in case of in-rust panics
|
||||
set_panic_hook();
|
||||
|
||||
setupRsGoBridge();
|
||||
setupRsGoBridge();
|
||||
|
||||
goWasmSetLogging("trace");
|
||||
goWasmSetLogging("trace");
|
||||
|
||||
// Set up message handler (MixFetch will be started on demand)
|
||||
setupMessageHandler();
|
||||
// Set up message handler (MixFetch will be started on demand)
|
||||
setupMessageHandler();
|
||||
|
||||
sendLog("Worker ready - click Start MixFetch to begin");
|
||||
sendLog('Worker ready - click Start MixFetch to begin');
|
||||
}
|
||||
|
||||
// Let's get started!
|
||||
|
||||
Reference in New Issue
Block a user