feat: add configurator (Web Serial config via AT commands)
Some checks failed
Build and deploy Docs site to GitHub Pages / github-pages (push) Has been cancelled
Some checks failed
Build and deploy Docs site to GitHub Pages / github-pages (push) Has been cancelled
This commit is contained in:
118
flasher/lib/vanity-key-generator.js
Normal file
118
flasher/lib/vanity-key-generator.js
Normal file
@@ -0,0 +1,118 @@
|
||||
export class VanityKeyGenerator {
|
||||
constructor() {
|
||||
this.workers = [];
|
||||
this.running = false;
|
||||
this._resolve = null;
|
||||
this._reject = null;
|
||||
this._totalAttempts = 0;
|
||||
this.onProgress = null;
|
||||
}
|
||||
|
||||
static get numCores() {
|
||||
return navigator.hardwareConcurrency || 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate time for a given hex prefix length
|
||||
* @param {number} prefixLen - number of hex chars
|
||||
* @param {number} keysPerSec - estimated throughput
|
||||
* @returns {string} human-readable estimate
|
||||
*/
|
||||
static estimateTime(prefixLen, keysPerSec) {
|
||||
if (prefixLen === 0) return 'instant';
|
||||
const expected = Math.pow(16, prefixLen);
|
||||
const seconds = expected / keysPerSec;
|
||||
|
||||
if (seconds < 1) return 'less than a second';
|
||||
if (seconds < 60) return `~${Math.ceil(seconds)} seconds`;
|
||||
if (seconds < 3600) return `~${Math.ceil(seconds / 60)} minutes`;
|
||||
if (seconds < 86400) return `~${Math.ceil(seconds / 3600)} hours`;
|
||||
return `~${Math.ceil(seconds / 86400)} days`;
|
||||
}
|
||||
|
||||
get attempts() {
|
||||
return this._totalAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start generating a vanity key
|
||||
* @param {string} prefix - hex prefix to match (1-6 chars)
|
||||
* @returns {Promise<{ privKey: string, pubKey: string, attempts: number } | null>}
|
||||
*/
|
||||
generate(prefix) {
|
||||
if (this.running) throw new Error('Already running');
|
||||
|
||||
prefix = prefix.replace(/[^0-9a-fA-F]/g, '');
|
||||
if (prefix.length === 0 || prefix.length > 6) {
|
||||
throw new Error('Prefix must be 1-6 hex characters');
|
||||
}
|
||||
|
||||
this.running = true;
|
||||
this._totalAttempts = 0;
|
||||
const numWorkers = VanityKeyGenerator.numCores;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
|
||||
for (let i = 0; i < numWorkers; i++) {
|
||||
const worker = new Worker(
|
||||
new URL('./vanity-key-worker.js', import.meta.url),
|
||||
{ type: 'module' }
|
||||
);
|
||||
|
||||
worker.onmessage = (e) => {
|
||||
if (!this.running) return;
|
||||
const data = e.data;
|
||||
|
||||
if (data.type === 'progress') {
|
||||
this._totalAttempts += data.attempts;
|
||||
if (this.onProgress) this.onProgress(this._totalAttempts);
|
||||
} else if (data.type === 'match') {
|
||||
this._totalAttempts += data.attempts;
|
||||
const result = {
|
||||
privKey: data.privKey,
|
||||
pubKey: data.pubKey,
|
||||
attempts: this._totalAttempts,
|
||||
};
|
||||
this._stopWorkers();
|
||||
this.running = false;
|
||||
resolve(result);
|
||||
} else if (data.type === 'error') {
|
||||
this._stopWorkers();
|
||||
this.running = false;
|
||||
reject(new Error(data.message));
|
||||
} else if (data.type === 'stopped') {
|
||||
this._totalAttempts += data.attempts;
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = (err) => {
|
||||
this._stopWorkers();
|
||||
this.running = false;
|
||||
reject(new Error(err.message || 'Worker error'));
|
||||
};
|
||||
|
||||
worker.postMessage({ type: 'start', prefix, progressInterval: 200 });
|
||||
this.workers.push(worker);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_stopWorkers() {
|
||||
for (const worker of this.workers) {
|
||||
try { worker.postMessage({ type: 'stop' }); } catch (e) {}
|
||||
setTimeout(() => worker.terminate(), 500);
|
||||
}
|
||||
this.workers = [];
|
||||
}
|
||||
|
||||
cancel() {
|
||||
const reject = this._reject;
|
||||
this._stopWorkers();
|
||||
this.running = false;
|
||||
if (reject) reject(new Error('Cancelled'));
|
||||
this._resolve = null;
|
||||
this._reject = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user