mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 19:12:25 -05:00
[feature] make client-side nonce calculation multi-threaded (#4219)
# Description Thank you in part to f0x for nerd-sniping me into banging this together :p ## Checklist - [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md). - [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat. - [x] I/we have not leveraged AI to create the proposed changes. - [x] I/we have performed a self-review of added code. - [x] I/we have written code that is legible and maintainable by others. - [x] I/we have commented the added code, particularly in hard-to-understand areas. - [ ] I/we have made any necessary changes to documentation. - [ ] I/we have added tests that cover new code. - [x] I/we have run tests and they pass locally with the changes. - [x] I/we have run `go fmt ./...` and `golangci-lint run`. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4219 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
3b46eb6a9e
commit
a82d574acc
2 changed files with 81 additions and 45 deletions
|
|
@ -45,51 +45,85 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||
// data attributes on the nollamas section.
|
||||
const seed = nollamas.dataset.nollamasSeed;
|
||||
const challenge = nollamas.dataset.nollamasChallenge;
|
||||
const threads = navigator.hardwareConcurrency;
|
||||
if (typeof(threads) != "number" || threads < 1) { threads = 1; }
|
||||
|
||||
console.log("seed:", seed); // eslint-disable-line no-console
|
||||
console.log("challenge:", challenge); // eslint-disable-line no-console
|
||||
console.log("threads:", threads); // eslint-disable-line no-console
|
||||
|
||||
// Prepare the worker with task function.
|
||||
const worker = new Worker("/assets/dist/nollamasworker.js");
|
||||
// Create an array to track
|
||||
// all workers such that we
|
||||
// can terminate them all.
|
||||
const workers = [];
|
||||
const terminateAll = () => { workers.forEach((worker) => worker.terminate() ); };
|
||||
|
||||
// Get time before task completion.
|
||||
const startTime = performance.now();
|
||||
worker.postMessage({
|
||||
challenge: challenge,
|
||||
seed: seed,
|
||||
});
|
||||
|
||||
// Set the main worker function.
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data.done) {
|
||||
const endTime = performance.now();
|
||||
const duration = endTime - startTime;
|
||||
// Prepare and start each worker,
|
||||
// adding them to the workers array.
|
||||
for (let i = 0; i < threads; i++) {
|
||||
const worker = new Worker("/assets/dist/nollamasworker.js");
|
||||
workers.push(worker);
|
||||
|
||||
// Remove spinner and replace it with a tick
|
||||
// and info about how long it took to solve.
|
||||
nollamas.removeChild(spinner);
|
||||
const solutionWrapper = document.createElement("div");
|
||||
solutionWrapper.className = "nollamas-status";
|
||||
// On any error terminate.
|
||||
worker.onerror = (ev) => {
|
||||
console.error("worker error:", ev); // eslint-disable-line no-console
|
||||
terminateAll();
|
||||
};
|
||||
|
||||
const tick = document.createElement("i");
|
||||
tick.className = "fa fa-check fa-2x fa-fw";
|
||||
tick.setAttribute("title","Solved!");
|
||||
tick.setAttribute("aria-label", "Solved!");
|
||||
solutionWrapper.appendChild(tick);
|
||||
// Post worker message, where each
|
||||
// worker will compute nonces in range:
|
||||
// $threadNumber + $totalThreads * n
|
||||
worker.postMessage({
|
||||
challenge: challenge,
|
||||
threads: threads,
|
||||
thread: i,
|
||||
seed: seed,
|
||||
});
|
||||
|
||||
const took = document.createElement("span");
|
||||
const solvedText = `Solved after ${e.data.nonce} iterations, in ${duration.toString()}ms!`;
|
||||
took.appendChild(document.createTextNode(solvedText));
|
||||
solutionWrapper.appendChild(took);
|
||||
// Set main on-success function.
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data.done) {
|
||||
// Stop workers.
|
||||
terminateAll();
|
||||
|
||||
nollamas.appendChild(solutionWrapper);
|
||||
// Log which thread found the solution.
|
||||
console.log("solution from:", e.data.thread); // eslint-disable-line no-console
|
||||
|
||||
// Wait for 500ms before redirecting, to give
|
||||
// visitors a shot at reading the message, but
|
||||
// not so long that they have to wait unduly.
|
||||
setTimeout(() => {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.set("nollamas_solution", e.data.nonce);
|
||||
window.location.replace(url.toString());
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
// Get total computation duration.
|
||||
const endTime = performance.now();
|
||||
const duration = endTime - startTime;
|
||||
|
||||
// Remove spinner and replace it with a tick
|
||||
// and info about how long it took to solve.
|
||||
nollamas.removeChild(spinner);
|
||||
const solutionWrapper = document.createElement("div");
|
||||
solutionWrapper.className = "nollamas-status";
|
||||
|
||||
const tick = document.createElement("i");
|
||||
tick.className = "fa fa-check fa-2x fa-fw";
|
||||
tick.setAttribute("title","Solved!");
|
||||
tick.setAttribute("aria-label", "Solved!");
|
||||
solutionWrapper.appendChild(tick);
|
||||
|
||||
const took = document.createElement("span");
|
||||
const solvedText = `Solved after ${e.data.nonce} iterations by worker ${e.data.thread} of ${threads}, in ${duration.toString()}ms!`;
|
||||
took.appendChild(document.createTextNode(solvedText));
|
||||
solutionWrapper.appendChild(took);
|
||||
|
||||
nollamas.appendChild(solutionWrapper);
|
||||
|
||||
// Wait for 500ms before redirecting, to give
|
||||
// visitors a shot at reading the message, but
|
||||
// not so long that they have to wait unduly.
|
||||
setTimeout(() => {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.set("nollamas_solution", e.data.nonce);
|
||||
window.location.replace(url.toString());
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@
|
|||
|
||||
import sha256 from "./sha256";
|
||||
|
||||
let compute = async function(seedStr, challengeStr) {
|
||||
let compute = async function(seedStr, challengeStr, start, iter) {
|
||||
const textEncoder = new TextEncoder();
|
||||
|
||||
let nonce = 0;
|
||||
let nonce = start;
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
|
||||
// Create possible solution string from challenge string + nonce.
|
||||
|
|
@ -38,17 +38,19 @@ let compute = async function(seedStr, challengeStr) {
|
|||
return nonce;
|
||||
}
|
||||
|
||||
// Iter.
|
||||
nonce++;
|
||||
// Iter nonce.
|
||||
nonce += iter;
|
||||
}
|
||||
};
|
||||
|
||||
onmessage = async function(e) {
|
||||
console.log('worker started'); // eslint-disable-line no-console
|
||||
const thread = e.data.thread;
|
||||
const threads = e.data.threads;
|
||||
console.log("worker started:", thread); // eslint-disable-line no-console
|
||||
|
||||
// Compute nonce value that produces 'challenge' for seed.
|
||||
let nonce = await compute(e.data.seed, e.data.challenge);
|
||||
// Compute nonce value that produces 'challenge', for our allotted thread.
|
||||
let nonce = await compute(e.data.seed, e.data.challenge, thread, threads);
|
||||
|
||||
// Post the solution nonce back to caller.
|
||||
postMessage({ nonce: nonce, done: true });
|
||||
// Post the solution nonce back to caller with thread no.
|
||||
postMessage({ nonce: nonce, done: true, thread: thread });
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue