UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

114 lines (113 loc) 4.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const mobx_state_tree_1 = require("mobx-state-tree"); const configuration_1 = require("../configuration"); const util_1 = require("../util"); function isCloneable(thing) { return !(typeof thing === 'function') && !(thing instanceof Error); } function detectHardwareConcurrency() { const mainThread = typeof window !== 'undefined'; const canDetect = mainThread && 'hardwareConcurrency' in window.navigator; return mainThread && canDetect ? window.navigator.hardwareConcurrency : 1; } class LazyWorker { constructor(driver) { this.driver = driver; } async getWorker() { if (!this.workerP) { this.workerP = this.driver.makeWorker().catch((e) => { this.workerP = undefined; throw e; }); } return this.workerP; } } class BaseRpcDriver { constructor(args) { this.lastWorkerAssignment = -1; this.workerAssignments = new Map(); this.maxPingTime = 30000; this.workerCheckFrequency = 5000; this.config = args.config; } filterArgs(thing, sessionId) { if (Array.isArray(thing)) { return thing .filter(thing => isCloneable(thing)) .map(t => this.filterArgs(t, sessionId)); } else if (typeof thing === 'object' && thing !== null) { if ((0, mobx_state_tree_1.isStateTreeNode)(thing) && !(0, mobx_state_tree_1.isAlive)(thing)) { throw new Error('dead state tree node passed to RPC call'); } else if (thing instanceof File) { return thing; } else { return Object.fromEntries(Object.entries(thing) .filter(e => isCloneable(e[1])) .map(([k, v]) => [k, this.filterArgs(v, sessionId)])); } } else { return thing; } } async remoteAbort(sessionId, functionName, stopTokenId) { const worker = await this.getWorker(sessionId); await worker.call(functionName, { stopTokenId }, { timeout: 1000000, rpcDriverClassName: this.name }); } createWorkerPool() { const hardwareConcurrency = detectHardwareConcurrency(); const workerCount = (0, configuration_1.readConfObject)(this.config, 'workerCount') || (0, util_1.clamp)(1, Math.max(1, hardwareConcurrency - 1), 5); const workers = []; for (let i = 0; i < workerCount; i++) { workers.push(new LazyWorker(this)); } return workers; } getWorkerPool() { if (!this.workerPool) { const res = this.createWorkerPool(); this.workerPool = res; return res; } return this.workerPool; } async getWorker(sessionId) { const workers = this.getWorkerPool(); let workerNumber = this.workerAssignments.get(sessionId); if (workerNumber === undefined) { const workerAssignment = (this.lastWorkerAssignment + 1) % workers.length; this.workerAssignments.set(sessionId, workerAssignment); this.lastWorkerAssignment = workerAssignment; workerNumber = workerAssignment; } return workers[workerNumber].getWorker(); } async call(pluginManager, sessionId, functionName, args, options = {}) { if (!sessionId) { throw new TypeError('sessionId is required'); } const unextendedWorker = await this.getWorker(sessionId); const worker = pluginManager.evaluateExtensionPoint('Core-extendWorker', unextendedWorker); const rpcMethod = pluginManager.getRpcMethodType(functionName); if (!rpcMethod) { throw new Error(`unknown RPC method ${functionName}`); } const serializedArgs = await rpcMethod.serializeArguments(args, this.name); const filteredAndSerializedArgs = this.filterArgs(serializedArgs, sessionId); const call = await worker.call(functionName, filteredAndSerializedArgs, { timeout: 5 * 60 * 1000, statusCallback: args.statusCallback, rpcDriverClassName: this.name, ...options, }); return rpcMethod.deserializeReturn(call, args, this.name); } } exports.default = BaseRpcDriver;