cs-element
Version:
Advanced reactive data management library with state machines, blueprints, persistence, compression, networking, and multithreading support
1,189 lines (1,108 loc) • 42.3 kB
JavaScript
'use strict';
var events = require('events');
var worker_threads = require('worker_threads');
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 0x100).toString(16).slice(1));
}
function unsafeStringify(arr, offset = 0) {
return (byteToHex[arr[offset + 0]] +
byteToHex[arr[offset + 1]] +
byteToHex[arr[offset + 2]] +
byteToHex[arr[offset + 3]] +
'-' +
byteToHex[arr[offset + 4]] +
byteToHex[arr[offset + 5]] +
'-' +
byteToHex[arr[offset + 6]] +
byteToHex[arr[offset + 7]] +
'-' +
byteToHex[arr[offset + 8]] +
byteToHex[arr[offset + 9]] +
'-' +
byteToHex[arr[offset + 10]] +
byteToHex[arr[offset + 11]] +
byteToHex[arr[offset + 12]] +
byteToHex[arr[offset + 13]] +
byteToHex[arr[offset + 14]] +
byteToHex[arr[offset + 15]]).toLowerCase();
}
let getRandomValues;
const rnds8 = new Uint8Array(16);
function rng() {
if (!getRandomValues) {
if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
}
getRandomValues = crypto.getRandomValues.bind(crypto);
}
return getRandomValues(rnds8);
}
const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
var native = { randomUUID };
function v4(options, buf, offset) {
if (native.randomUUID && !buf && !options) {
return native.randomUUID();
}
options = options || {};
const rnds = options.random ?? options.rng?.() ?? rng();
if (rnds.length < 16) {
throw new Error('Random bytes length must be >= 16');
}
rnds[6] = (rnds[6] & 0x0f) | 0x40;
rnds[8] = (rnds[8] & 0x3f) | 0x80;
if (buf) {
offset = offset || 0;
if (offset < 0 || offset + 16 > buf.length) {
throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
}
for (let i = 0; i < 16; ++i) {
buf[offset + i] = rnds[i];
}
return buf;
}
return unsafeStringify(rnds);
}
/**
* Интерфейсы для Web Worker поддержки CSElement
*/
// ===== Типы операций для Worker =====
exports.WorkerOperationType = void 0;
(function (WorkerOperationType) {
// Операции с элементами
WorkerOperationType["CREATE_ELEMENT"] = "create_element";
WorkerOperationType["UPDATE_ELEMENT"] = "update_element";
WorkerOperationType["DELETE_ELEMENT"] = "delete_element";
WorkerOperationType["CLONE_ELEMENT"] = "clone_element";
// Операции поиска и запросов
WorkerOperationType["QUERY_ELEMENTS"] = "query_elements";
WorkerOperationType["ADVANCED_QUERY"] = "advanced_query";
WorkerOperationType["FILTER_ELEMENTS"] = "filter_elements";
WorkerOperationType["SORT_ELEMENTS"] = "sort_elements";
// Операции с данными
WorkerOperationType["TRANSFORM_DATA"] = "transform_data";
WorkerOperationType["VALIDATE_DATA"] = "validate_data";
WorkerOperationType["COMPUTE_STATISTICS"] = "compute_statistics";
// Операции сериализации
WorkerOperationType["SERIALIZE_ELEMENT"] = "serialize_element";
WorkerOperationType["DESERIALIZE_ELEMENT"] = "deserialize_element";
WorkerOperationType["SERIALIZE_TREE"] = "serialize_tree";
WorkerOperationType["DESERIALIZE_TREE"] = "deserialize_tree";
// Операции diff и merge
WorkerOperationType["COMPUTE_DIFF"] = "compute_diff";
WorkerOperationType["APPLY_PATCH"] = "apply_patch";
WorkerOperationType["THREE_WAY_MERGE"] = "three_way_merge";
// Операции анализа
WorkerOperationType["ANALYZE_STRUCTURE"] = "analyze_structure";
WorkerOperationType["DETECT_CYCLES"] = "detect_cycles";
WorkerOperationType["COMPUTE_METRICS"] = "compute_metrics";
// Операции валидации
WorkerOperationType["VALIDATE_STRUCTURE"] = "validate_structure";
WorkerOperationType["CHECK_INTEGRITY"] = "check_integrity";
// Пользовательские операции
WorkerOperationType["CUSTOM_OPERATION"] = "custom_operation";
})(exports.WorkerOperationType || (exports.WorkerOperationType = {}));
/**
* Менеджер Web Workers для CSElement
* Управляет пулом воркеров и выполнением тяжелых операций
*/
class WorkerManager extends events.EventEmitter {
constructor(config = {}, poolConfig = {}) {
super();
this.workers = new Map();
this.workerQueue = [];
this.pendingOperations = new Map();
this.operationCounter = 0;
this.isInitialized = false;
this.config = {
maxConcurrentOperations: 4,
timeoutMs: 30000,
memoryLimitMB: 512,
enableLogging: true,
enableProfiling: false,
enableCache: true,
cacheSize: 100,
...config
};
this.poolConfig = {
size: Math.max(1, navigator.hardwareConcurrency || 4),
strategy: 'least-busy',
healthCheck: true,
recycleAfter: 1000,
...poolConfig
};
}
/**
* Инициализация пула воркеров
*/
async initialize() {
if (this.isInitialized) {
return;
}
try {
// Создаем пул воркеров
const workerPromises = Array.from({ length: this.poolConfig.size }, () => this.createWorker());
await Promise.all(workerPromises);
this.isInitialized = true;
if (this.config.enableLogging) {
console.log(`WorkerManager initialized with ${this.poolConfig.size} workers`);
}
this.emit('initialized', { poolSize: this.poolConfig.size });
}
catch (error) {
this.emit('error', { type: 'initialization', error });
throw error;
}
}
/**
* Создание нового воркера
*/
async createWorker(config) {
const workerId = v4();
try {
const worker = new CSElementWorker(workerId, config || this.config);
await worker.initialize();
this.workers.set(workerId, worker);
this.workerQueue.push(worker);
// Настройка обработчиков событий
worker.on('message', (response) => {
this.handleWorkerResponse(response);
});
worker.on('error', (error) => {
this.handleWorkerError(workerId, error);
});
worker.on('terminated', () => {
this.handleWorkerTermination(workerId);
});
if (this.config.enableLogging) {
console.log(`Worker ${workerId} created`);
}
this.emit('worker:created', { workerId });
return worker;
}
catch (error) {
this.emit('worker:error', { workerId, error });
throw error;
}
}
/**
* Завершение работы воркера
*/
async terminateWorker(workerId) {
const worker = this.workers.get(workerId);
if (!worker) {
throw new Error(`Worker ${workerId} not found`);
}
try {
await worker.terminate();
this.workers.delete(workerId);
// Удаляем из очереди
const index = this.workerQueue.findIndex(w => w.id === workerId);
if (index !== -1) {
this.workerQueue.splice(index, 1);
}
if (this.config.enableLogging) {
console.log(`Worker ${workerId} terminated`);
}
this.emit('worker:terminated', { workerId });
}
catch (error) {
this.emit('worker:error', { workerId, error });
throw error;
}
}
/**
* Выполнение операции
*/
async executeOperation(operation) {
if (!this.isInitialized) {
await this.initialize();
}
const worker = this.selectWorker();
if (!worker) {
throw new Error('No available workers');
}
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
this.pendingOperations.delete(operation.id);
reject(new Error(`Operation ${operation.id} timed out`));
}, this.config.timeoutMs);
this.pendingOperations.set(operation.id, {
resolve,
reject,
timeout
});
worker.execute(operation).catch(error => {
this.pendingOperations.delete(operation.id);
clearTimeout(timeout);
reject(error);
});
});
}
/**
* Получение статуса воркера
*/
getWorkerStatus(workerId) {
if (workerId) {
const worker = this.workers.get(workerId);
if (!worker) {
throw new Error(`Worker ${workerId} not found`);
}
return this.createWorkerStatus(worker);
}
// Возвращаем статус первого доступного воркера
const worker = this.workerQueue[0];
if (!worker) {
throw new Error('No workers available');
}
return this.createWorkerStatus(worker);
}
/**
* Получение статуса пула
*/
getPoolStatus() {
const totalWorkers = this.workers.size;
const activeWorkers = Array.from(this.workers.values())
.filter(w => w.status === 'busy').length;
const totalOperations = Array.from(this.workers.values())
.reduce((sum, w) => sum + w.operationsCount, 0);
const averageExecutionTime = totalOperations > 0
? Array.from(this.workers.values())
.reduce((sum, w) => sum + w.totalExecutionTime || 0, 0) / totalOperations
: 0;
const memoryUsage = Array.from(this.workers.values())
.reduce((sum, w) => sum + w.memoryUsage, 0);
return {
totalWorkers,
activeWorkers,
queuedOperations: this.pendingOperations.size,
totalOperations,
averageExecutionTime,
memoryUsage
};
}
/**
* Выбор воркера для выполнения операции
*/
selectWorker() {
const availableWorkers = this.workerQueue.filter(w => w.status === 'idle' || w.status === 'busy');
if (availableWorkers.length === 0) {
return null;
}
switch (this.poolConfig.strategy) {
case 'round-robin':
return this.selectRoundRobin(availableWorkers);
case 'least-busy':
return this.selectLeastBusy(availableWorkers);
case 'random':
return this.selectRandom(availableWorkers);
default:
return availableWorkers[0];
}
}
selectRoundRobin(workers) {
const index = this.operationCounter % workers.length;
this.operationCounter++;
return workers[index];
}
selectLeastBusy(workers) {
return workers.reduce((least, current) => current.operationsCount < least.operationsCount ? current : least);
}
selectRandom(workers) {
const index = Math.floor(Math.random() * workers.length);
return workers[index];
}
/**
* Обработка ответа от воркера
*/
handleWorkerResponse(response) {
const pending = this.pendingOperations.get(response.id);
if (!pending) {
return;
}
clearTimeout(pending.timeout);
this.pendingOperations.delete(response.id);
if (response.success) {
pending.resolve(response.result);
}
else {
pending.reject(new Error(response.error));
}
this.emit('operation:completed', response);
}
/**
* Обработка ошибки воркера
*/
handleWorkerError(workerId, error) {
if (this.config.enableLogging) {
console.error(`Worker ${workerId} error:`, error);
}
this.emit('worker:error', { workerId, error });
// Если воркер критически поврежден, пересоздаем его
if (error.code === 'CRITICAL_ERROR') {
this.recreateWorker(workerId);
}
}
/**
* Обработка завершения воркера
*/
handleWorkerTermination(workerId) {
this.workers.delete(workerId);
const index = this.workerQueue.findIndex(w => w.id === workerId);
if (index !== -1) {
this.workerQueue.splice(index, 1);
}
this.emit('worker:terminated', { workerId });
}
/**
* Пересоздание воркера
*/
async recreateWorker(workerId) {
try {
await this.terminateWorker(workerId);
await this.createWorker();
}
catch (error) {
this.emit('error', { type: 'recreation', workerId, error });
}
}
/**
* Создание объекта статуса воркера
*/
createWorkerStatus(worker) {
return {
id: worker.id,
status: worker.status,
operationsCount: worker.operationsCount,
averageExecutionTime: worker.averageExecutionTime || 0,
memoryUsage: worker.memoryUsage,
lastError: undefined
};
}
/**
* Завершение работы всех воркеров
*/
async shutdown() {
const terminationPromises = Array.from(this.workers.keys()).map(workerId => this.terminateWorker(workerId));
await Promise.all(terminationPromises);
this.isInitialized = false;
this.emit('shutdown');
}
/**
* Проверка здоровья воркеров
*/
async healthCheck() {
if (!this.poolConfig.healthCheck) {
return {};
}
const healthPromises = Array.from(this.workers.entries()).map(async ([workerId, worker]) => {
try {
const healthMessage = {
id: `health-${Date.now()}`,
type: exports.WorkerOperationType.CUSTOM_OPERATION,
timestamp: Date.now(),
payload: { operation: 'health-check' }
};
await worker.execute(healthMessage);
return [workerId, true];
}
catch {
return [workerId, false];
}
});
const results = await Promise.all(healthPromises);
return Object.fromEntries(results);
}
}
/**
* Реализация WorkerInstance
*/
class CSElementWorker extends events.EventEmitter {
constructor(id, _config) {
super();
this.status = 'idle';
this.operationsCount = 0;
this.memoryUsage = 0;
this.worker = null;
this.totalExecutionTime = 0;
this.id = id;
this.createdAt = Date.now();
this.lastActivity = Date.now();
}
async initialize() {
try {
// В тестовой среде используем заглушку
if (typeof jest !== 'undefined' || process.env.NODE_ENV === 'test') {
const listeners = new Map();
this.worker = {
postMessage: (message) => {
// Эмулируем обработку сообщения
setTimeout(() => {
const response = {
id: message.id,
success: true,
result: { processed: true, operation: message.type },
timestamp: Date.now(),
executionTime: 10
};
// Вызываем все слушатели сообщений
const messageListeners = listeners.get('message') || [];
messageListeners.forEach(listener => {
listener({ data: response });
});
}, 10);
},
terminate: () => { },
on: () => { },
off: () => { },
addListener: (event, listener) => {
if (!listeners.has(event)) {
listeners.set(event, []);
}
listeners.get(event).push(listener);
},
removeListener: (event, listener) => {
const eventListeners = listeners.get(event);
if (eventListeners) {
const index = eventListeners.indexOf(listener);
if (index > -1) {
eventListeners.splice(index, 1);
}
}
}
};
}
else {
// Создаем Worker Thread
const workerScript = this.generateWorkerScript();
// В Node.js используем worker_threads
if (typeof worker_threads.Worker !== 'undefined' && worker_threads.Worker.length > 1) {
// Node.js Worker threads - используем временный файл
try {
const fs = require('fs');
const path = require('path');
const os = require('os');
const tempFile = path.join(os.tmpdir(), `cs-worker-${this.id}.js`);
fs.writeFileSync(tempFile, workerScript);
this.worker = new worker_threads.Worker(tempFile);
this.worker.on('message', (data) => {
this.handleMessage(data);
});
this.worker.on('error', (error) => {
this.handleError({
code: 'WORKER_ERROR',
message: error.message,
stack: error.stack || ''
});
});
this.worker.on('exit', (code) => {
// Удаляем временный файл
try {
fs.unlinkSync(tempFile);
}
catch (e) {
// Игнорируем ошибки удаления
}
if (code !== 0) {
this.handleError({
code: 'WORKER_EXIT',
message: `Worker stopped with exit code ${code}`,
stack: ''
});
}
});
}
catch (nodeError) {
// Fallback заглушка для Node.js
this.worker = {
postMessage: () => { },
terminate: () => { },
on: () => { },
addListener: () => { },
removeListener: () => { }
};
}
}
else {
// Fallback для браузеров - Web Workers
const blob = new Blob([workerScript], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
this.worker = new worker_threads.Worker(workerUrl);
this.worker.onmessage = (event) => {
this.handleMessage(event.data);
};
this.worker.onerror = (error) => {
this.handleError({
code: 'WORKER_ERROR',
message: error.message,
stack: error.filename + ':' + error.lineno
});
};
// Очищаем URL после создания воркера
URL.revokeObjectURL(workerUrl);
}
}
this.status = 'idle';
}
catch (error) {
this.status = 'error';
throw error;
}
}
async execute(operation) {
if (!this.worker || this.status === 'terminated') {
throw new Error('Worker is not available');
}
this.status = 'busy';
this.lastActivity = Date.now();
return new Promise((resolve, reject) => {
const startTime = Date.now();
const messageHandler = (event) => {
const response = event.data;
if (response.id === operation.id) {
this.worker.removeListener('message', messageHandler);
const executionTime = Date.now() - startTime;
this.totalExecutionTime += executionTime;
this.operationsCount++;
this.status = 'idle';
if (response.success) {
resolve(response.result);
}
else {
reject(new Error(response.error));
}
this.emit('message', response);
}
};
this.worker.addListener('message', messageHandler);
this.worker.postMessage(operation);
});
}
async terminate() {
if (this.worker) {
this.worker.terminate();
this.worker = null;
}
this.status = 'terminated';
this.emit('terminated');
}
handleMessage(_data) {
this.lastActivity = Date.now();
// Сообщения обрабатываются в execute()
}
handleError(error) {
this.status = 'error';
this.emit('error', error);
}
get averageExecutionTime() {
return this.operationsCount > 0 ? this.totalExecutionTime / this.operationsCount : 0;
}
/**
* Генерация кода для Web Worker
*/
generateWorkerScript() {
return `
// Web Worker script for CSElement operations
const operations = new Map();
// Импорт необходимых функций (будет заменен на реальную реализацию)
${this.getWorkerOperations()}
self.onmessage = async function(event) {
const message = event.data;
const startTime = Date.now();
try {
const result = await executeOperation(message);
self.postMessage({
id: message.id,
success: true,
result: result,
timestamp: Date.now(),
executionTime: Date.now() - startTime
});
} catch (error) {
self.postMessage({
id: message.id,
success: false,
error: error.message,
timestamp: Date.now(),
executionTime: Date.now() - startTime
});
}
};
async function executeOperation(message) {
const { type, payload } = message;
switch (type) {
case 'serialize_element':
return serializeElement(payload);
case 'deserialize_element':
return deserializeElement(payload);
case 'query_elements':
return queryElements(payload);
case 'compute_diff':
return computeDiff(payload);
case 'three_way_merge':
return threeWayMerge(payload);
case 'analyze_structure':
return analyzeStructure(payload);
default:
throw new Error('Unknown operation type: ' + type);
}
}
`;
}
/**
* Получение операций для воркера
*/
getWorkerOperations() {
return `
// Импорт необходимых модулей для воркера
const msgpack = require('msgpack-lite');
// Простая реализация QueryEngine для воркера
class WorkerQueryEngine {
static query(rootData, selector) {
const results = [];
// Базовая реализация поиска по селектору
if (typeof selector === 'string') {
if (selector.startsWith('#')) {
// Поиск по ID
const id = selector.substring(1);
this.findById(rootData, id, results);
} else if (selector.startsWith('.')) {
// Поиск по классу/имени
const className = selector.substring(1);
this.findByName(rootData, className, results);
} else {
// Поиск по имени элемента
this.findByName(rootData, selector, results);
}
} else if (selector && typeof selector === 'object') {
// Объектный селектор
this.findBySelector(rootData, selector, results);
}
return results;
}
static findById(element, id, results) {
if (element.id === id) {
results.push(element);
}
if (element.children) {
Object.values(element.children).forEach(child => {
this.findById(child, id, results);
});
}
}
static findByName(element, name, results) {
if (element.name === name) {
results.push(element);
}
if (element.children) {
Object.values(element.children).forEach(child => {
this.findByName(child, name, results);
});
}
}
static findBySelector(element, selector, results) {
let matches = true;
if (selector.name && element.name !== selector.name) {
matches = false;
}
if (selector.id && element.id !== selector.id) {
matches = false;
}
if (selector.data && selector.data.length > 0) {
for (const key of selector.data) {
if (!element.data || !element.data.hasOwnProperty(key)) {
matches = false;
break;
}
}
}
if (matches) {
results.push(element);
}
if (element.children) {
Object.values(element.children).forEach(child => {
this.findBySelector(child, selector, results);
});
}
}
}
// Простая реализация DiffEngine для воркера
class WorkerDiffEngine {
static computeDiff(source, target) {
const changes = [];
// Сравнение основных свойств
if (source.id !== target.id) {
changes.push({
type: 'modify',
path: ['id'],
oldValue: source.id,
newValue: target.id
});
}
if (source.name !== target.name) {
changes.push({
type: 'modify',
path: ['name'],
oldValue: source.name,
newValue: target.name
});
}
// Сравнение данных
this.compareData(source.data || {}, target.data || {}, ['data'], changes);
// Сравнение дочерних элементов
this.compareChildren(source.children || {}, target.children || {}, ['children'], changes);
return {
changes,
summary: {
additions: changes.filter(c => c.type === 'add').length,
deletions: changes.filter(c => c.type === 'delete').length,
modifications: changes.filter(c => c.type === 'modify').length
}
};
}
static compareData(sourceData, targetData, path, changes) {
const sourceKeys = Object.keys(sourceData);
const targetKeys = Object.keys(targetData);
// Удаленные ключи
for (const key of sourceKeys) {
if (!targetKeys.includes(key)) {
changes.push({
type: 'delete',
path: [...path, key],
oldValue: sourceData[key],
newValue: undefined
});
}
}
// Добавленные ключи
for (const key of targetKeys) {
if (!sourceKeys.includes(key)) {
changes.push({
type: 'add',
path: [...path, key],
oldValue: undefined,
newValue: targetData[key]
});
}
}
// Измененные ключи
for (const key of sourceKeys) {
if (targetKeys.includes(key) && sourceData[key] !== targetData[key]) {
changes.push({
type: 'modify',
path: [...path, key],
oldValue: sourceData[key],
newValue: targetData[key]
});
}
}
}
static compareChildren(sourceChildren, targetChildren, path, changes) {
const sourceKeys = Object.keys(sourceChildren);
const targetKeys = Object.keys(targetChildren);
// Удаленные дочерние элементы
for (const key of sourceKeys) {
if (!targetKeys.includes(key)) {
changes.push({
type: 'delete',
path: [...path, key],
oldValue: sourceChildren[key],
newValue: undefined
});
}
}
// Добавленные дочерние элементы
for (const key of targetKeys) {
if (!sourceKeys.includes(key)) {
changes.push({
type: 'add',
path: [...path, key],
oldValue: undefined,
newValue: targetChildren[key]
});
}
}
// Рекурсивное сравнение существующих дочерних элементов
for (const key of sourceKeys) {
if (targetKeys.includes(key)) {
const childDiff = this.computeDiff(sourceChildren[key], targetChildren[key]);
// Добавляем изменения с обновленными путями
for (const change of childDiff.changes) {
changes.push({
...change,
path: [...path, key, ...change.path]
});
}
}
}
}
static threeWayMerge(base, source, target) {
const sourceChanges = this.computeDiff(base, source);
const targetChanges = this.computeDiff(base, target);
// Простая стратегия слияния
const merged = JSON.parse(JSON.stringify(base));
const conflicts = [];
// Применяем изменения из source
for (const change of sourceChanges.changes) {
this.applyChange(merged, change);
}
// Применяем изменения из target, проверяя конфликты
for (const change of targetChanges.changes) {
const conflictingChange = sourceChanges.changes.find(sc =>
sc.path.join('.') === change.path.join('.') && sc.type === change.type
);
if (conflictingChange && conflictingChange.newValue !== change.newValue) {
conflicts.push({
path: change.path,
sourceValue: conflictingChange.newValue,
targetValue: change.newValue,
baseValue: change.oldValue,
type: 'content',
severity: 'medium',
autoResolvable: false,
suggestions: []
});
} else {
this.applyChange(merged, change);
}
}
return {
merged,
conflicts,
autoResolved: 0,
manualRequired: conflicts.length,
success: conflicts.length === 0,
metadata: {
algorithm: 'simple',
strategy: 'auto',
executionTime: 0
}
};
}
static applyChange(obj, change) {
const path = change.path.slice();
const key = path.pop();
let current = obj;
for (const pathPart of path) {
if (!current[pathPart]) {
current[pathPart] = {};
}
current = current[pathPart];
}
if (change.type === 'delete') {
delete current[key];
} else {
current[key] = change.newValue;
}
}
}
// Утилиты для сериализации
function serializeWithMessagePack(data) {
try {
return msgpack.encode(data);
} catch (error) {
// Fallback на JSON
return JSON.stringify(data);
}
}
function deserializeWithMessagePack(data) {
try {
if (typeof data === 'string') {
return JSON.parse(data);
}
return msgpack.decode(data);
} catch (error) {
// Fallback на JSON
return typeof data === 'string' ? JSON.parse(data) : data;
}
}
function serializeElement(payload) {
// Используем встроенную сериализацию CSElement
if (payload && typeof payload.serialize === 'function') {
const serialized = payload.serialize({
includeChildren: true,
includeData: true,
includeMetadata: true
});
return serializeWithMessagePack(serialized);
}
// Fallback для простых объектов
return serializeWithMessagePack(payload);
}
function deserializeElement(payload) {
// Используем встроенную десериализацию CSElement
const data = deserializeWithMessagePack(payload.data);
if (data && typeof CSElement !== 'undefined' && CSElement.deserialize) {
return CSElement.deserialize(data);
}
// Fallback для простых объектов
return data;
}
function queryElements(payload) {
const { rootData, selector, options = {} } = payload;
const startTime = Date.now();
try {
const results = WorkerQueryEngine.query(rootData, selector);
const total = results.length;
const limit = options.limit || 100;
const offset = options.offset || 0;
const paginatedResults = results.slice(offset, offset + limit);
return {
elements: paginatedResults,
total,
hasMore: offset + limit < total,
executionTime: Date.now() - startTime,
metadata: {
selector: typeof selector === 'string' ? selector : JSON.stringify(selector),
algorithm: 'worker-query-engine',
cacheHit: false
}
};
} catch (error) {
return {
elements: [],
total: 0,
hasMore: false,
executionTime: Date.now() - startTime,
error: error.message
};
}
}
function computeDiff(payload) {
const { source, target, options = {} } = payload;
const startTime = Date.now();
try {
const result = WorkerDiffEngine.computeDiff(source, target);
return {
...result,
executionTime: Date.now() - startTime,
metadata: {
algorithm: options.algorithm || 'simple',
includeVisualization: options.includeVisualization || false
}
};
} catch (error) {
return {
changes: [],
summary: { additions: 0, deletions: 0, modifications: 0 },
executionTime: Date.now() - startTime,
error: error.message
};
}
}
function threeWayMerge(payload) {
const { base, source, target, options = {} } = payload;
const startTime = Date.now();
try {
const result = WorkerDiffEngine.threeWayMerge(base, source, target);
return {
...result,
metadata: {
...result.metadata,
executionTime: Date.now() - startTime,
strategy: options.strategy || 'auto'
}
};
} catch (error) {
return {
merged: base,
conflicts: [],
autoResolved: 0,
manualRequired: 1,
success: false,
metadata: {
algorithm: 'simple',
strategy: 'auto',
executionTime: Date.now() - startTime
},
error: error.message
};
}
}
function analyzeStructure(payload) {
const { element, options = {} } = payload;
const startTime = Date.now();
try {
const metrics = {
totalElements: 0,
maxDepth: 0,
avgChildrenPerElement: 0,
dataFields: new Set(),
elementTypes: new Set()
};
function analyzeElement(elem, depth = 0) {
metrics.totalElements++;
metrics.maxDepth = Math.max(metrics.maxDepth, depth);
if (elem.name) {
metrics.elementTypes.add(elem.name);
}
if (elem.data) {
Object.keys(elem.data).forEach(key => metrics.dataFields.add(key));
}
let childCount = 0;
if (elem.children) {
childCount = Object.keys(elem.children).length;
Object.values(elem.children).forEach(child => {
analyzeElement(child, depth + 1);
});
}
return childCount;
}
const totalChildren = analyzeElement(element);
metrics.avgChildrenPerElement = metrics.totalElements > 0 ? totalChildren / metrics.totalElements : 0;
const insights = [];
const recommendations = [];
// Генерируем инсайты
if (metrics.maxDepth > 10) {
insights.push({
type: 'warning',
message: 'Глубокая вложенность элементов может влиять на производительность',
value: metrics.maxDepth
});
recommendations.push({
type: 'optimization',
message: 'Рассмотрите возможность уплощения структуры',
priority: 'medium'
});
}
if (metrics.totalElements > 1000) {
insights.push({
type: 'info',
message: 'Большое количество элементов',
value: metrics.totalElements
});
recommendations.push({
type: 'performance',
message: 'Используйте пагинацию для больших структур',
priority: 'high'
});
}
return {
metrics: {
...metrics,
dataFields: Array.from(metrics.dataFields),
elementTypes: Array.from(metrics.elementTypes)
},
insights,
recommendations,
executionTime: Date.now() - startTime,
metadata: {
algorithm: 'worker-structure-analyzer',
options
}
};
} catch (error) {
return {
metrics: {},
insights: [],
recommendations: [],
executionTime: Date.now() - startTime,
error: error.message
};
}
}
`;
}
}
exports.WorkerManager = WorkerManager;
//# sourceMappingURL=nodejs.js.map