/**
 * workerpool.js
 * https://github.com/josdejong/workerpool
 *
 * Offload tasks to a pool of workers on node.js and in the browser.
 *
 * @version 9.1.1
 * @date    2024-04-06
 *
 * @license
 * Copyright (C) 2014-2022 Jos de Jong <wjosdejong@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
	typeof define === 'function' && define.amd ? define(factory) :
	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.worker = factory());
})(this, (function () { 'use strict';

	function getDefaultExportFromCjs (x) {
		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
	}

	var worker$1 = {};

	/**
	 * The helper class for transferring data from the worker to the main thread.
	 *
	 * @param {Object} message The object to deliver to the main thread.
	 * @param {Object[]} transfer An array of transferable Objects to transfer ownership of.
	 */
	function Transfer(message, transfer) {
	  this.message = message;
	  this.transfer = transfer;
	}
	var transfer = Transfer;

	/**
	 * worker must be started as a child process or a web worker.
	 * It listens for RPC messages from the parent process.
	 */
	(function (exports) {
	  var Transfer = transfer;

	  /**
	   * Special message sent by parent which causes the worker to terminate itself.
	   * Not a "message object"; this string is the entire message.
	   */
	  var TERMINATE_METHOD_ID = '__workerpool-terminate__';

	  // var nodeOSPlatform = require('./environment').nodeOSPlatform;

	  // create a worker API for sending and receiving messages which works both on
	  // node.js and in the browser
	  var worker = {
	    exit: function () {}
	  };
	  if (typeof self !== 'undefined' && typeof postMessage === 'function' && typeof addEventListener === 'function') {
	    // worker in the browser
	    worker.on = function (event, callback) {
	      addEventListener(event, function (message) {
	        callback(message.data);
	      });
	    };
	    worker.send = function (message) {
	      postMessage(message);
	    };
	  } else if (typeof process !== 'undefined') {
	    // node.js

	    var WorkerThreads;
	    try {
	      WorkerThreads = require('worker_threads');
	    } catch (error) {
	      if (typeof error === 'object' && error !== null && error.code === 'MODULE_NOT_FOUND') ; else {
	        throw error;
	      }
	    }
	    if (WorkerThreads && /* if there is a parentPort, we are in a WorkerThread */
	    WorkerThreads.parentPort !== null) {
	      var parentPort = WorkerThreads.parentPort;
	      worker.send = parentPort.postMessage.bind(parentPort);
	      worker.on = parentPort.on.bind(parentPort);
	      worker.exit = process.exit.bind(process);
	    } else {
	      worker.on = process.on.bind(process);
	      // ignore transfer argument since it is not supported by process
	      worker.send = function (message) {
	        process.send(message);
	      };
	      // register disconnect handler only for subprocess worker to exit when parent is killed unexpectedly
	      worker.on('disconnect', function () {
	        process.exit(1);
	      });
	      worker.exit = process.exit.bind(process);
	    }
	  } else {
	    throw new Error('Script must be executed as a worker');
	  }
	  function convertError(error) {
	    return Object.getOwnPropertyNames(error).reduce(function (product, name) {
	      return Object.defineProperty(product, name, {
	        value: error[name],
	        enumerable: true
	      });
	    }, {});
	  }

	  /**
	   * Test whether a value is a Promise via duck typing.
	   * @param {*} value
	   * @returns {boolean} Returns true when given value is an object
	   *                    having functions `then` and `catch`.
	   */
	  function isPromise(value) {
	    return value && typeof value.then === 'function' && typeof value.catch === 'function';
	  }

	  // functions available externally
	  worker.methods = {};

	  /**
	   * Execute a function with provided arguments
	   * @param {String} fn     Stringified function
	   * @param {Array} [args]  Function arguments
	   * @returns {*}
	   */
	  worker.methods.run = function run(fn, args) {
	    var f = new Function('return (' + fn + ').apply(null, arguments);');
	    return f.apply(f, args);
	  };

	  /**
	   * Get a list with methods available on this worker
	   * @return {String[]} methods
	   */
	  worker.methods.methods = function methods() {
	    return Object.keys(worker.methods);
	  };

	  /**
	   * Custom handler for when the worker is terminated.
	   */
	  worker.terminationHandler = undefined;

	  /**
	   * Cleanup and exit the worker.
	   * @param {Number} code 
	   * @returns 
	   */
	  worker.cleanupAndExit = function (code) {
	    var _exit = function () {
	      worker.exit(code);
	    };
	    if (!worker.terminationHandler) {
	      return _exit();
	    }
	    var result = worker.terminationHandler(code);
	    if (isPromise(result)) {
	      result.then(_exit, _exit);
	    } else {
	      _exit();
	    }
	  };
	  var currentRequestId = null;
	  worker.on('message', function (request) {
	    if (request === TERMINATE_METHOD_ID) {
	      return worker.cleanupAndExit(0);
	    }
	    try {
	      var method = worker.methods[request.method];
	      if (method) {
	        currentRequestId = request.id;

	        // execute the function
	        var result = method.apply(method, request.params);
	        if (isPromise(result)) {
	          // promise returned, resolve this and then return
	          result.then(function (result) {
	            if (result instanceof Transfer) {
	              worker.send({
	                id: request.id,
	                result: result.message,
	                error: null
	              }, result.transfer);
	            } else {
	              worker.send({
	                id: request.id,
	                result: result,
	                error: null
	              });
	            }
	            currentRequestId = null;
	          }).catch(function (err) {
	            worker.send({
	              id: request.id,
	              result: null,
	              error: convertError(err)
	            });
	            currentRequestId = null;
	          });
	        } else {
	          // immediate result
	          if (result instanceof Transfer) {
	            worker.send({
	              id: request.id,
	              result: result.message,
	              error: null
	            }, result.transfer);
	          } else {
	            worker.send({
	              id: request.id,
	              result: result,
	              error: null
	            });
	          }
	          currentRequestId = null;
	        }
	      } else {
	        throw new Error('Unknown method "' + request.method + '"');
	      }
	    } catch (err) {
	      worker.send({
	        id: request.id,
	        result: null,
	        error: convertError(err)
	      });
	    }
	  });

	  /**
	   * Register methods to the worker
	   * @param {Object} [methods]
	   * @param {import('./types.js').WorkerRegisterOptions} [options]
	   */
	  worker.register = function (methods, options) {
	    if (methods) {
	      for (var name in methods) {
	        if (methods.hasOwnProperty(name)) {
	          worker.methods[name] = methods[name];
	        }
	      }
	    }
	    if (options) {
	      worker.terminationHandler = options.onTerminate;
	    }
	    worker.send('ready');
	  };
	  worker.emit = function (payload) {
	    if (currentRequestId) {
	      if (payload instanceof Transfer) {
	        worker.send({
	          id: currentRequestId,
	          isEvent: true,
	          payload: payload.message
	        }, payload.transfer);
	        return;
	      }
	      worker.send({
	        id: currentRequestId,
	        isEvent: true,
	        payload
	      });
	    }
	  };
	  {
	    exports.add = worker.register;
	    exports.emit = worker.emit;
	  }
	})(worker$1);
	var worker = /*@__PURE__*/getDefaultExportFromCjs(worker$1);

	return worker;

}));
//# sourceMappingURL=worker.js.map
