@logic-pad/core
Version:
72 lines (71 loc) • 2.41 kB
JavaScript
import debounce from 'lodash/debounce.js';
import { Serializer } from './serializer/allSerializers.js';
import validateGrid from './validate.js';
const SYNC_VALIDATION_THRESHOLD = 10000;
export class GridValidator {
worker = null;
stateListeners = new Set();
loadListeners = new Set();
validateGridDebounced = debounce((grid, solution) => {
this.worker?.terminate();
this.worker = new Worker(new URL('./validateAsyncWorker.js', import.meta.url), { type: 'module' });
this.worker.onmessage = (event) => {
if (event.data) {
this.notifyState(event.data);
}
this.worker?.terminate();
this.worker = null;
this.notifyLoad();
};
this.worker.onmessageerror = (error) => {
console.error('Validation worker error:', error);
this.worker?.terminate();
this.worker = null;
this.notifyLoad();
};
this.worker.postMessage({
grid: Serializer.stringifyGrid(grid),
solution: solution ? Serializer.stringifyGrid(solution) : null,
});
this.notifyLoad();
}, 300, { leading: true, trailing: true });
validateGrid = (grid, solution) => {
if (grid.width * grid.height <= SYNC_VALIDATION_THRESHOLD) {
// Synchronous validation for small grids
// to avoid the overhead of worker communication.
const state = validateGrid(grid, solution);
this.notifyState(state);
}
else {
this.validateGridDebounced(grid, solution);
}
};
notifyState = (state) => {
this.stateListeners.forEach(listener => listener(state));
};
subscribeToState = (listener) => {
this.stateListeners.add(listener);
return () => {
this.stateListeners.delete(listener);
};
};
notifyLoad = () => {
this.loadListeners.forEach(listener => listener());
};
subscribeToLoad = (listener) => {
this.loadListeners.add(listener);
return () => {
this.loadListeners.delete(listener);
};
};
isLoading = () => {
return this.worker !== null;
};
delete = () => {
if (this.worker) {
this.worker.terminate();
this.worker = null;
}
this.stateListeners.clear();
};
}