dashboard/shell/plugins/steve/web-worker.steve-sub-worker.js

119 lines
3.5 KiB
JavaScript

import { SCHEMA } from '@shell/config/types';
const SCHEMA_FLUSH_TIMEOUT = 2500;
const state = {
store: '', // Store name
flushTimer: undefined, // Timer to flush the schema chaneg queue
queue: [], // Schema change queue
schemas: {} // Map of schema id to hash to track when a schema actually changes
};
// Quick, simple hash function
function hash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash &= hash;
}
return new Uint32Array([hash])[0].toString(36);
}
// Quick, simple hash function to generate hash for an object
function hashObj(obj) {
return hash(JSON.stringify(obj, null, 2));
}
function flush() {
state.queue.forEach((schema) => {
const hash = hashObj(schema);
const existing = state.schemas[schema.id];
if (!existing || (existing && existing !== hash)) {
// console.log(`${ schema.id } CHANGED ${ hash } > ${ existing }`);
state.schemas[schema.id] = hash;
const msg = {
data: schema,
resourceType: SCHEMA,
type: 'resource.change'
};
load(msg);
}
});
state.queue = [];
state.flushTimer = setTimeout(flush, SCHEMA_FLUSH_TIMEOUT);
}
state.flushTimer = setTimeout(flush, SCHEMA_FLUSH_TIMEOUT);
// Callback to the store's load function (in the main thread) to process a load
function load(data) {
self.postMessage({ load: data });
}
const workerActions = {
onmessage: (e) => {
/* on the off chance there's more than key in the message, we handle them in the order that they "keys" method provides which is
// good enough for now considering that we never send more than one message action at a time right now */
const messageActions = Object.keys(e?.data);
messageActions.forEach((action) => {
if (workerActions[action]) {
workerActions[action](e?.data[action]);
} else {
console.warn('no associated action for:', action); // eslint-disable-line no-console
}
});
},
initWorker: ({ storeName }) => {
state.store = storeName;
},
destroyWorker: () => {
clearTimeout(state.flushTimer);
self.postMessage({ destroyWorker: true }); // we're only passing the boolean here because the key needs to be something truthy to ensure it's passed on the object.
// Web worker global function to terminate the web worker
close();
},
// Called to load schema
loadSchemas: (schemas) => {
schemas.forEach((schema) => {
// These properties are added to the object, but aren't on the raw object, so remove them
// otherwise our comparison will show changes when there aren't any
delete schema._id;
delete schema._group;
state.schemas[schema.id] = hashObj(schema);
});
// console.log(JSON.parse(JSON.stringify(state.resources.schemas)));
},
// Called when schema is updated
updateSchema: (schema) => {
// Add the schema to the queue to be checked to see if the schema really changed
state.queue.push(schema);
},
// Remove the cached schema
removeSchema: (id) => {
// Remove anything in the queue related to the schema - we don't want to send any pending updates later for a schema that has been removed
state.queue = state.queue.filter(schema => schema.id !== id);
// Delete the schema from the map, so if it comes back we don't ignore it if the hash is the same
delete state.schemas[id];
}
};
onmessage = workerActions.onmessage; // bind everything to the worker's onmessage handler via the workerAction