UNPKG

@mlightcad/data-model

Version:

The data-model package provides the core classes for interacting with AutoCAD's database and entities. This package mimics AutoCAD ObjectARX's AcDb (Database) classes and implements the drawing database structure that AutoCAD developers are familiar with.

360 lines 14.6 kB
/** * Simple worker framework */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; /** * Simple worker framework */ var AcDbWorkerManager = /** @class */ (function () { function AcDbWorkerManager(config) { var _a, _b; this.taskId = 0; this.workers = new Map(); this.pendingTasks = new Map(); this.config = { workerUrl: config.workerUrl, timeout: (_a = config.timeout) !== null && _a !== void 0 ? _a : 30000, maxConcurrentWorkers: (_b = config.maxConcurrentWorkers) !== null && _b !== void 0 ? _b : 4 }; } /** * Execute a task with worker support and fallback */ AcDbWorkerManager.prototype.execute = function (input, workerUrl) { return __awaiter(this, void 0, void 0, function () { var startTime, taskId, error_1, duration; return __generator(this, function (_a) { switch (_a.label) { case 0: startTime = Date.now(); taskId = this.generateTaskId(); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.executeInWorker(taskId, input, workerUrl || this.config.workerUrl)]; case 2: return [2 /*return*/, _a.sent()]; case 3: error_1 = _a.sent(); duration = Date.now() - startTime; return [2 /*return*/, { success: false, error: error_1 instanceof Error ? error_1.message : String(error_1), duration: duration }]; case 4: return [2 /*return*/]; } }); }); }; /** * Execute task in web worker */ AcDbWorkerManager.prototype.executeInWorker = function (taskId, input, workerUrl) { return __awaiter(this, void 0, void 0, function () { var startTime; var _this = this; return __generator(this, function (_a) { startTime = Date.now(); return [2 /*return*/, new Promise(function (resolve, reject) { // Get or create worker var worker = _this.getAvailableWorker(workerUrl); // Set up timeout var timeout = setTimeout(function () { _this.cleanupTask(taskId); _this.releaseWorker(worker); reject(new Error("Worker operation timed out after ".concat(_this.config.timeout, "ms"))); }, _this.config.timeout); // Store task _this.pendingTasks.set(taskId, { resolve: function (result) { clearTimeout(timeout); _this.releaseWorker(worker); resolve(result); }, reject: function (error) { clearTimeout(timeout); _this.releaseWorker(worker); reject(error); }, timeout: timeout }); // Set up message handler var messageHandler = function (event) { var _a = event.data, id = _a.id, success = _a.success, data = _a.data, error = _a.error; if (id !== taskId) return; _this.cleanupTask(taskId); var duration = Date.now() - startTime; if (success) { resolve({ success: true, data: data, duration: duration }); } else { resolve({ success: false, error: error, duration: duration }); } }; var errorHandler = function (error) { _this.cleanupTask(taskId); reject(new Error("Worker error: ".concat(error.message))); }; worker.addEventListener('message', messageHandler); worker.addEventListener('error', errorHandler); // Send task to worker worker.postMessage({ id: taskId, input: input }); })]; }); }); }; /** * Clean up a pending task */ AcDbWorkerManager.prototype.cleanupTask = function (taskId) { var task = this.pendingTasks.get(taskId); if (task) { clearTimeout(task.timeout); this.pendingTasks.delete(taskId); } }; /** * Generate unique task ID */ AcDbWorkerManager.prototype.generateTaskId = function () { return "task_".concat(++this.taskId, "_").concat(Date.now()); }; /** * Detect if web workers are supported */ AcDbWorkerManager.prototype.detectWorkerSupport = function () { return typeof Worker !== 'undefined'; }; /** * Get an available worker or create a new one */ AcDbWorkerManager.prototype.getAvailableWorker = function (workerUrl) { var e_1, _a; try { // Find available worker for (var _b = __values(this.workers), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), _id = _d[0], instance = _d[1]; if (!instance.isBusy) { instance.isBusy = true; return instance.worker; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } // Create new worker if under limit if (this.workers.size < this.config.maxConcurrentWorkers) { var worker = new Worker(workerUrl, { type: 'module' }); var id = this.generateWorkerId(); var instance = { worker: worker, isBusy: true, id: id, createdAt: new Date() }; this.workers.set(id, instance); return worker; } // Reuse oldest worker var oldestWorker = Array.from(this.workers.values()).sort(function (a, b) { return a.createdAt.getTime() - b.createdAt.getTime(); })[0]; oldestWorker.isBusy = true; return oldestWorker.worker; }; /** * Release a worker back to the pool */ AcDbWorkerManager.prototype.releaseWorker = function (worker) { var e_2, _a; try { for (var _b = __values(this.workers), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), _id = _d[0], instance = _d[1]; if (instance.worker === worker) { instance.isBusy = false; break; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } }; /** * Generate unique worker ID */ AcDbWorkerManager.prototype.generateWorkerId = function () { return "worker_".concat(Date.now(), "_").concat(Math.random().toString(36).substr(2, 9)); }; /** * Get framework statistics */ AcDbWorkerManager.prototype.getStats = function () { return { totalWorkers: this.workers.size, busyWorkers: Array.from(this.workers.values()).filter(function (w) { return w.isBusy; }) .length, pendingTasks: this.pendingTasks.size, config: this.config }; }; /** * Clean up all pending tasks and workers */ AcDbWorkerManager.prototype.destroy = function () { var e_3, _a, e_4, _b; try { // Clear all pending requests for (var _c = __values(this.pendingTasks), _d = _c.next(); !_d.done; _d = _c.next()) { var _e = __read(_d.value, 2), _taskId = _e[0], task = _e[1]; clearTimeout(task.timeout); task.reject(new Error('Framework destroyed')); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_3) throw e_3.error; } } this.pendingTasks.clear(); try { // Terminate all workers for (var _f = __values(this.workers), _g = _f.next(); !_g.done; _g = _f.next()) { var _h = __read(_g.value, 2), _id = _h[0], instance = _h[1]; instance.worker.terminate(); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_g && !_g.done && (_b = _f.return)) _b.call(_f); } finally { if (e_4) throw e_4.error; } } this.workers.clear(); }; return AcDbWorkerManager; }()); export { AcDbWorkerManager }; /** * Simple API for executing tasks with worker support */ var AcDbWorkerApi = /** @class */ (function () { function AcDbWorkerApi(config) { this.framework = new AcDbWorkerManager(config); } /** * Execute a task with optional worker support */ AcDbWorkerApi.prototype.execute = function (input, workerUrl) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.framework.execute(input, workerUrl)]; }); }); }; /** * Get framework statistics */ AcDbWorkerApi.prototype.getStats = function () { return this.framework.getStats(); }; /** * Clean up resources */ AcDbWorkerApi.prototype.destroy = function () { this.framework.destroy(); }; return AcDbWorkerApi; }()); export { AcDbWorkerApi }; /** * Create a worker API instance */ export function createWorkerApi(config) { return new AcDbWorkerApi(config); } //# sourceMappingURL=AcDbWorkerManager.js.map