robosats/frontend/src/components/RobotAvatar/RobohashGenerator.ts
2023-12-02 20:01:11 +00:00

74 lines
2.4 KiB
TypeScript

class RoboGenerator {
private assetsCache: Record<string, string> = {};
private assetsPromises: Record<string, Promise<string>> = {};
private readonly workers: Worker[] = [];
constructor() {
// limit to 8 workers
const numCores = Math.min(navigator.hardwareConcurrency || 1, 8);
for (let i = 0; i < numCores; i++) {
const worker = new Worker(new URL('./robohash.worker.ts', import.meta.url));
this.workers.push(worker);
}
}
public generate: (hash: string, size: 'small' | 'large') => Promise<string> = async (
hash,
size,
) => {
const cacheKey = `${size}px;${hash}`;
if (this.assetsCache[cacheKey]) {
return this.assetsCache[cacheKey];
} else if (cacheKey in this.assetsPromises) {
return await this.assetsPromises[cacheKey];
}
const workerIndex = Object.keys(this.assetsPromises).length % this.workers.length;
const worker = this.workers[workerIndex];
this.assetsPromises[cacheKey] = new Promise<string>((resolve, reject) => {
// const avatarB64 = async_generate_robohash(hash, size == 'small' ? 80 : 256).then((avatarB64)=> resolve(`data:image/png;base64,${avatarB64}`));
// Create a message object with the necessary data
const message = { hash, size, cacheKey, workerIndex };
// Listen for messages from the worker
const handleMessage = (event: MessageEvent) => {
const { cacheKey, imageUrl } = event.data;
// Update the cache and resolve the promise
this.assetsCache[cacheKey] = imageUrl;
delete this.assetsPromises[cacheKey];
resolve(imageUrl);
};
// Add the event listener for messages
worker.addEventListener('message', handleMessage);
// Send the message to the worker
worker.postMessage(message);
// Clean up the event listener after receiving the result
const cleanup = () => {
worker.removeEventListener('message', handleMessage);
};
// Reject the promise if an error occurs
worker.addEventListener('error', (error) => {
cleanup();
reject(error);
});
// Reject the promise if the worker times out
setTimeout(() => {
cleanup();
reject(new Error('Generation timed out'));
}, 5000); // Adjust the timeout duration as needed
});
return await this.assetsPromises[cacheKey];
};
}
export const robohash = new RoboGenerator();