UNPKG

tyo-mq

Version:

Distributed Message Pub/Sub Service with socket.io

1,920 lines (1,633 loc) 295 kB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ function Constants() { this.ANONYMOUS = 'ANONYMOUS'; this.EVENT_DEFAULT = 'tyo-mq-mt-default'; this.EVENT_ALL = 'TM-ALL'; this.SYSTEM = 'TYO-MQ-SYSTEM'; this.ALL_PUBLISHERS = 'TYO-MQ-ALL'; this.SCOPE_ALL = "all"; this.SCOPE_DEFAULT = "default"; this.DEFAULT_PORT = 17352; } var constants = constants || new Constants(); module.exports = constants; },{}],2:[function(require,module,exports){ /** * @file events.js */ const constants = require( "./constants"); function Events () { } /** * Normailise event string */ Events.prototype.toEventString = function (event, prefix, suffix) { var eventStr; if (typeof event === 'string') { eventStr = event; } else if (typeof event === 'object' && event.event) { eventStr = event.event; } else throw new Error ('Unknown event object: should be a string or object with event string'); return (prefix ? (prefix + '-') : '') + eventStr + (suffix ? ('-' + suffix) : ''); }; /** * This is different to the cosume event * this is the event name that the consumer socker will listen to */ Events.prototype.toConsumerEvent = function (event, producer, scope_all) { if (scope_all) this.toEventString(event, producer.toLowerCase()); return this.toEventString(event, producer).toLowerCase(); } /** * To Consume Event */ Events.prototype.toConsumeEvent = function (event) { /** * COSUMER EVENT = "CONSUME" + Lower(event) * System event or defined Event are all capitalized */ //var capEvent = event.toUpperCase(); return this.toEventString(event, 'CONSUME'); }; /** * */ Events.prototype.toOnDisconnectEvent = function (id) { return 'DISCONNECT-' + id; }; /** * */ Events.prototype.toOnUnsubscribeEvent =function (event, id) { // var eventStr = this.toEventString(event); // return 'UNSUBSCRIBE-' + eventStr + '-' + id; return this.toEventString(event, 'UNSUBSCRIBE', id); }; /** * */ Events.prototype.toOnSubscribeEvent = function (id) { return 'SUBSCRIBE-TO' + ((id) ? "-" + id : ""); }; Events.prototype.toConsumeEventAll = function (producer) { // return 'CONSUME-' + producer + "-ALL"; return this.toEventString('CONSUME', this.toConsumerEventAll(producer)); }; Events.prototype.toConsumerEventAll = function (producer) { // return 'producer + "-ALL"; return this.toEventString(producer.toLowerCase(), null, constants.EVENT_ALL); }; var events = events || new Events(); module.exports = events; },{"./constants":1}],3:[function(require,module,exports){ /** * @file message-queue.js * * It may not be a good idea to name it message queue here, but for now leave it as it is */ var Socket = require('./socket'), Subscriber = require('./subscriber'), Producer = require('./publisher'); function Factory (options) { options = options || {}; /** * for log */ this.logger = options.logger || console; this.port = options.port || null; this.host = options.host || null; this.protocol = options.protocol || null; this.args = options.args || {}; var mq = this; /** * Create the comminucation channel (e.g. socket) */ this.createSocket = function (callback, port, host, protocol, args) { var mySocket = new Socket(); if (this.logger) mySocket.logger = this.logger; if (callback) { mySocket.connect(function () { callback(mySocket); }, port || mq.port, host || mq.host, protocol || mq.protocol, args || mq.args ); } return mySocket; }; /** * private function */ this.createConsumerPrivate = function (context, name, callback, port, host, protocol, args, onErrorCallback) { var consumer = new Subscriber(name); if (context && context.logger) consumer.logger = context.logger; if (callback) { consumer.connect(function () { onErrorCallback = onErrorCallback || function (message) { if (mq.logger) mq.logger.error("Error message received: " + message); }; if (onErrorCallback) { var oldOnError = consumer.onError; consumer.on('ERROR', function () { oldOnError.call(consumer); onErrorCallback(); }); } callback(consumer); }, port, host, protocol, args ); } return consumer; }; /** * Create a consumer */ this.createConsumer = function (context, name, callback, port, host, protocol, args, onErrorCallback) { var self = this; if (context && typeof context === 'string') { onErrorCallback = args; args = protocol; protocol = host; host = port; port = callback; callback = name; name = context; context = this; } if (!callback) { return new Promise(function (resolve, reject) { try { mq.createConsumerPrivate.call( self, context, name, function (consumer) { resolve(consumer); }, port || mq.port, host || mq.host, protocol || mq.protocol, args || mq.args, onErrorCallback); } catch (err) { reject(err); } }); } else mq.createConsumerPrivate(context, name, callback, port || mq.port, host || mq.host, protocol || mq.protocol, args || mq.args, onErrorCallback); }; /** * Alias of createConsumer */ this.createSubscriber = this.createConsumer; /** * private function */ this.createProducerPrivate = function (context, name, eventDefault, callback, port, host, protocol, args) { if (!callback && typeof eventDefault === 'function') { args = protocol; protocol = host; host = port; port = callback; callback = eventDefault; eventDefault = null; } var producer = new Producer(name, eventDefault); if (context && context.logger) producer.logger = context.logger; if (callback) return producer.connect(function () { callback(producer); }, port, host, protocol, args ); return producer; }; /** * Create a producer */ this.createProducer = function (name, eventDefault, callback, port, host, protocol, args) { var self = this; if (eventDefault && typeof eventDefault === 'function') { args = protocol; protocol = host; host = port; port = callback; callback = eventDefault; eventDefault = null; } if (!callback) { return new Promise(function (resolve, reject) { try { mq.createProducerPrivate.call( self, self, name, eventDefault, function (producer) { resolve(producer); }, port || mq.port, host || mq.host, protocol || mq.protocol, args || mq.args); } catch (err) { reject(err); } }); } else mq.createProducerPrivate(self, name, eventDefault, callback, port || mq.port, host || mq.host, protocol || mq.protocol, args || mq.args ); }; } Factory.Producer = Producer; Factory.Consumer = Subscriber; Factory.Publisher = Producer; Factory.Subscriber = Subscriber; module.exports = Factory; },{"./publisher":4,"./socket":5,"./subscriber":6}],4:[function(require,module,exports){ /** * @file producer.js */ const util = require('util'), events = require('./events'), Constants = require('./constants'); var Subscriber = require('./subscriber'); function SubscriberInfo (name) { this.name = name; } function Publisher (name, event) { // call parent constructor Subscriber.call(this, name); var producer = this; this.eventDefault = event || Constants.EVENT_DEFAULT; this.subscribers = {}; this.onSubscriptionListener = null; /** * @override * */ this.sendIdentificationInfo = function () { this.sendMessage.call(producer, 'PRODUCER', {name: name}); }; /** * Event produce function * @param event * @param data * @param validFor, the valid time (lifespan of the message) */ this.produce = function (event, data, validFor, to) { var self = this; if (!data) { data = event; event = this.eventDefault; if (!event) throw new Error('Default event name is not set.'); } /** * @todo * 1) make an encryption option * 2) Encrypt the message when a cryto algorithm is negotiated */ var message = {event:event, message:data, from:self.name, lifespan: validFor || -1}; // Maybe we could delay a bit self.sendMessage.call(self, 'PRODUCE', message, self.name); }; /** * On Subscribe */ this.setOnSubscriptionListener = function (callback) { var event = events.toOnSubscribeEvent(this.getId()); this.on(event, function (data) { producer.logger.log("Received subscription information: " + JSON.stringify(data)); producer.subscribers[data.id] = data; // further listener if (producer.onSubscriptionListener) producer.onSubscriptionListener.call(producer, data); if (callback) callback(data); }); }; this.onSubscribed = this.setOnSubscriptionListener; /** * On Lost connections with subscriber(s) */ this.setOnSubscriberLostListener = function (callback) { var event = events.toOnDisconnectEvent(this.getId()); this.on(event, function(data) { producer.logger.log("Lost subscriber's connection"); if (callback) callback(data); }); }; this.onSubscriberLost = this.setOnSubscriberLostListener; /** * On Unsubsribe */ this.setOnUnsubscribedListener = function (callback) { var event = events.toOnUnsubscribeEvent(this.getId()); this.on(event, function() { if (callback) callback(); }); }; this.onUnsubscribed = this.setOnUnsubscribedListener; // Initialisation this.addConnectionListener(function () { var producerName = producer.name || Constants.ANONYMOUS; // producer.sendMessage.call(producer, 'PRODUCER', {name: producerName}); producer.setOnSubscriptionListener(); }); this.setOnSubscriberLostListener = function (callback) { var event = events.toOnDisconnectEvent(this.getId()); this.on(event, function(data) { producer.logger.log("Lost subscriber's connection"); if (callback) callback(data); }); }; this.setOnSubscriberLost = this.setOnSubscriberLostListener; this.setOnSubscriberOnlineListener = function (callback) { var event = events.toOnConnectEvent(this.getId()); this.on(event, function(data) { producer.logger.log("Subscriber is online"); if (callback) callback(data); }); } this.whenSubscriberOnline = this.setOnSubscriberOnline = this.setOnSubscriberOnlineListener; } /** * Inherits from Socket */ util.inherits(Publisher, Subscriber); module.exports = Publisher; },{"./constants":1,"./events":2,"./subscriber":6,"util":62}],5:[function(require,module,exports){ (function (process){(function (){ /** * @file socket.js * * A Socket.io connection * */ const Constants = require('./constants'); /** * Socket Class */ function Socket() { /** * Autoconnect */ this.autoreconnect = true; /** * SocketIO instance */ this.io = require('socket.io-client'); /** * Socket Instance from socket.io */ this.socket = null; this.connected = false; /** * Socket Id */ this.id = function () { return this.socket.id; }; this.logger = this.logger || /* (process.env.NODE_ENV === 'production') ? null : */console; this.onConnectListeners = null; /** * Add on connect listener */ this.addConnectionListener = function (listener) { this.onConnectListeners = this.onConnectListeners || []; this.onConnectListeners.push(listener); }; var self = this; this.onDisconnectListener = function(socket) { self.connected = false; if (self.logger) self.logger.log("connection lost"); }; // Only available from the server side // this.disable = function (what) { // this.io.disable(what); // } /** * The name of the socket such as a name of an App */ this.name = Constants.ANONYMOUS; /** * Alias */ this.alias = null; /** this.serial_id = -1; this.sendIdentificationInfo = function () { // do nothing yet } */ /** * Check if it is connected */ this.isConnected = function () { return this.connected; } /** * On Error */ this.onError = function (message) { if (this.logger && this.logger.error && this.logger.error.apply) this.logger.error(message); } /** * On Connect */ this.onConnect = function () { this.sendIdentificationInfo(); this.on("ERROR", function (message) { if (self.onError) self.onError.call(self, message); }); } /** * On Disconnect */ this.onDisconnect = function () { this.connected = false; this.logger.log("Socket (" + this.getId() + ") is disconnected"); } } /** * */ Socket.prototype.generateConnectionUrl = function() { var host_url = this.protocol + "://" + this.host + ":" + this.port + "/"; return host_url; }; /** * Disconnect */ Socket.prototype.disconnect = function (callback) { if (this.socket && this.socket.connected) { this.socket.disconnect(); } }; /** * Flush */ Socket.prototype.flush = function (callback) { this.socket.flush(); setTimeout(function() { callback(); }, 10); }; /** * Connect to the Socket.io server */ Socket.prototype.connect = function (callback, port, host, protocol, args) { var self = this; if (this.socket && this.socket.connected) { if (callback) { return callback(); } return; } this.host = this.host || host || process.env.TYO_MQ_HOST || 'localhost'; this.port = this.port || port || process.env.TYO_MQ_PORT || '17352'; this.protocol = this.protocol || protocol || 'http'; /** */ this.connectString = this.connectString || (this.protocol + "://" + this.host + ':' + this.port); this.connectWith(callback, this.connectString, args); }; /** * Connect to ther server with connection string */ Socket.prototype.connectWith = function (callback, connectString, args) { var self = this; this.callback = callback; if (self.logger) self.logger.log(this.name + " connecting to " + connectString + "..."); this.socket = this.io.connect(connectString, args || { transports: ["websocket"] }); this.socket.on('connect', function(socket) { self.connected = true; if (self.logger) self.logger.log(self.name + " connected to message queue server"); self.onConnect(); if (self.onConnectListeners && self.onConnectListeners.length > 0) { self.onConnectListeners.forEach(function (listener) { listener(); }); } if (self.callback) { self.callback(); // callback = null; } }); // let self has a chance to register a custom onDisconnectListener this.socket.on('disconnect', (() => { if (self.onDisconnectListener && typeof self.onDisconnectListener === 'function') self.onDisconnectListener(); })); }; /** * Send Event Message */ Socket.prototype.sendMessage = function (event, msg, from, callback) { if (!this.socket) throw new Error("Socket isn't initialized yet"); if (!this.socket.connected) { var futureFunc = this.socket.emit.bind(this.socket, event, msg); if (this.autoreconnect) this.connect(function (){ futureFunc.call(); }); else throw new Error("Socket is created but not connected"); return; } this.socket.emit(event, msg); if (callback && typeof callback === 'function') { callback(); } }; /** * On Event */ Socket.prototype.on = function (event, callback) { if (event === 'connect') { this.addConnectionListener(callback); return; } this.socket.on(event, callback); }; /** * Get Socket Id */ Socket.prototype.getSocketId = function () { return this.socket ? this.socket.id : null; }; Socket.prototype.getId = Socket.prototype.getSocketId; module.exports = Socket; }).call(this)}).call(this,require('_process')) },{"./constants":1,"_process":59,"socket.io-client":32}],6:[function(require,module,exports){ /** * @file subscriber.js */ const util = require('util'), events = require('./events'), Constants = require('./constants'); var Socket = require('./socket'); const { constants } = require('buffer'); /** * */ function Subscriber (name) { this.context = null; Socket.call(this); this.name = name || Constants.ANONYMOUS; var subscriber = this; /** * @override * */ this.sendIdentificationInfo = function () { this.sendMessage.call(subscriber, 'CONSUMER', {name: name}); } /** * Resend the subscription message after a connection is lost (particularily when server is gone) and reconnected */ this.resubscribeWhenReconnect = function (context, who, event, onConsumeCallback, reSubscribe) { var self = this; if (reSubscribe === null) reSubscribe = true; if (!onConsumeCallback) { onConsumeCallback = event; event = who; who = context; context = self; } function resubscribeListener() { subscribeInternal(); } function subscribeInternal() { if ((typeof event) !== "string") { onConsumeCallback = event; event = null; } var eventStr; var scope; var scope_all = true; if (event) eventStr = events.toEventString(event); else { eventStr = constants.EVENT_ALL; // who + "-ALL"; scope = Constants.SCOPE_ALL; scope_all = true; } /** * @todo * * deal with the ALL events later */ function sendSubscritionMessage () { self.sendMessage('SUBSCRIBE', {event:eventStr, producer: who, consumer:self.name, scope: scope}); } // On Connect Message will be trigger by system sendSubscritionMessage(); // the connection should be ready before we subscribe the message // this.on('connect', function () { // sendSubscritionMessage(); // }); if (!self.consumes) self.consumes = {}; var consumerEventStr = events.toConsumerEvent(eventStr, who, scope_all); var targetEventStr = events.toEventString(event, who).toLowerCase(); self.consumes[consumerEventStr] = function (obj) { //var intendedEvent = obj.event; // if the message is encrypted, then it needs to be decrypted first var message = obj.message; var from = obj.from || message.from; //if (intendedEvent === targetEventStr) { onConsumeCallback(message, from); //} }; var consumeEventStr = events.toConsumeEvent(consumerEventStr); self.on(consumeEventStr, function (obj) { if (context) self.consumes[consumerEventStr].call(context, obj); else self.consumes[consumerEventStr](obj); }); } subscribeInternal(); if (reSubscribe) self.addConnectionListener(resubscribeListener); } /** * Subscribe message * * If an event name is not provided, then we subscribe all the messages from the producer */ this.subscribe = function (context, who, event, onConsumeCallback, reconcect) { this.resubscribeWhenReconnect(context, who, event, onConsumeCallback, reconcect); }; /** * Subscribe only once, if the connection is gone, let it be */ this.subscribeOnce = function (context, who, event, onConsumeCallback) { this.subscribe(context, who, event, onConsumeCallback, false); }; /** * Subscribe all events with this name whatever providers are publishing */ this.subscribeAll = function (context, event, onConsumeCallback) { this.subscribe(context, Constants.ALL_PUBLISHERS, event, onConsumeCallback); } this.unsubscribe = function (event, who) { var eventStr = events.toConsumerEvent(event, who); // this.sendMessage('UNSUBSCRIBE', {event:eventStr}); this.socket.off(eventStr); } this.unsubscribeAll = function () { this.socket.removeAllListeners(); } this.setOnProducerOnlineListener = function (producer, callback) { var eventStr = events.toEventString(producer, null, "ONLINE"); this.on(eventStr, callback); } this.whenProducerOnline = this.setOnProducerOnline = this.setOnProducerOnlineListener; } /** * Inherits from Socket */ util.inherits(Subscriber, Socket); module.exports = Subscriber; },{"./constants":1,"./events":2,"./socket":5,"buffer":44,"util":62}],7:[function(require,module,exports){ /** * Expose `Emitter`. */ exports.Emitter = Emitter; /** * Initialize a new `Emitter`. * * @api public */ function Emitter(obj) { if (obj) return mixin(obj); } /** * Mixin the emitter properties. * * @param {Object} obj * @return {Object} * @api private */ function mixin(obj) { for (var key in Emitter.prototype) { obj[key] = Emitter.prototype[key]; } return obj; } /** * Listen on the given `event` with `fn`. * * @param {String} event * @param {Function} fn * @return {Emitter} * @api public */ Emitter.prototype.on = Emitter.prototype.addEventListener = function(event, fn){ this._callbacks = this._callbacks || {}; (this._callbacks['$' + event] = this._callbacks['$' + event] || []) .push(fn); return this; }; /** * Adds an `event` listener that will be invoked a single * time then automatically removed. * * @param {String} event * @param {Function} fn * @return {Emitter} * @api public */ Emitter.prototype.once = function(event, fn){ function on() { this.off(event, on); fn.apply(this, arguments); } on.fn = fn; this.on(event, on); return this; }; /** * Remove the given callback for `event` or all * registered callbacks. * * @param {String} event * @param {Function} fn * @return {Emitter} * @api public */ Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function(event, fn){ this._callbacks = this._callbacks || {}; // all if (0 == arguments.length) { this._callbacks = {}; return this; } // specific event var callbacks = this._callbacks['$' + event]; if (!callbacks) return this; // remove all handlers if (1 == arguments.length) { delete this._callbacks['$' + event]; return this; } // remove specific handler var cb; for (var i = 0; i < callbacks.length; i++) { cb = callbacks[i]; if (cb === fn || cb.fn === fn) { callbacks.splice(i, 1); break; } } // Remove event specific arrays for event types that no // one is subscribed for to avoid memory leak. if (callbacks.length === 0) { delete this._callbacks['$' + event]; } return this; }; /** * Emit `event` with the given args. * * @param {String} event * @param {Mixed} ... * @return {Emitter} */ Emitter.prototype.emit = function(event){ this._callbacks = this._callbacks || {}; var args = new Array(arguments.length - 1) , callbacks = this._callbacks['$' + event]; for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } if (callbacks) { callbacks = callbacks.slice(0); for (var i = 0, len = callbacks.length; i < len; ++i) { callbacks[i].apply(this, args); } } return this; }; // alias used for reserved events (protected method) Emitter.prototype.emitReserved = Emitter.prototype.emit; /** * Return array of callbacks for `event`. * * @param {String} event * @return {Array} * @api public */ Emitter.prototype.listeners = function(event){ this._callbacks = this._callbacks || {}; return this._callbacks['$' + event] || []; }; /** * Check if this emitter has `event` handlers. * * @param {String} event * @return {Boolean} * @api public */ Emitter.prototype.hasListeners = function(event){ return !! this.listeners(event).length; }; },{}],8:[function(require,module,exports){ (function (process){(function (){ /* eslint-env browser */ /** * This is the web browser implementation of `debug()`. */ exports.formatArgs = formatArgs; exports.save = save; exports.load = load; exports.useColors = useColors; exports.storage = localstorage(); exports.destroy = (() => { let warned = false; return () => { if (!warned) { warned = true; console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); } }; })(); /** * Colors. */ exports.colors = [ '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33' ]; /** * Currently only WebKit-based Web Inspectors, Firefox >= v31, * and the Firebug extension (any Firefox version) are known * to support "%c" CSS customizations. * * TODO: add a `localStorage` variable to explicitly enable/disable colors */ // eslint-disable-next-line complexity function useColors() { // NB: In an Electron preload script, document will be defined but not fully // initialized. Since we know we're in Chrome, we'll just detect this case // explicitly if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { return true; } // Internet Explorer and Edge do not support colors. if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { return false; } // Is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // Is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // Is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || // Double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); } /** * Colorize log arguments if enabled. * * @api public */ function formatArgs(args) { args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff); if (!this.useColors) { return; } const c = 'color: ' + this.color; args.splice(1, 0, c, 'color: inherit'); // The final "%c" is somewhat tricky, because there could be other // arguments passed either before or after the %c, so we need to // figure out the correct index to insert the CSS into let index = 0; let lastC = 0; args[0].replace(/%[a-zA-Z%]/g, match => { if (match === '%%') { return; } index++; if (match === '%c') { // We only are interested in the *last* %c // (the user may have provided their own) lastC = index; } }); args.splice(lastC, 0, c); } /** * Invokes `console.debug()` when available. * No-op when `console.debug` is not a "function". * If `console.debug` is not available, falls back * to `console.log`. * * @api public */ exports.log = console.debug || console.log || (() => {}); /** * Save `namespaces`. * * @param {String} namespaces * @api private */ function save(namespaces) { try { if (namespaces) { exports.storage.setItem('debug', namespaces); } else { exports.storage.removeItem('debug'); } } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? } } /** * Load `namespaces`. * * @return {String} returns the previously persisted debug modes * @api private */ function load() { let r; try { r = exports.storage.getItem('debug'); } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? } // If debug isn't set in LS, and we're in Electron, try to load $DEBUG if (!r && typeof process !== 'undefined' && 'env' in process) { r = process.env.DEBUG; } return r; } /** * Localstorage attempts to return the localstorage. * * This is necessary because safari throws * when a user disables cookies/localstorage * and you attempt to access it. * * @return {LocalStorage} * @api private */ function localstorage() { try { // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context // The Browser also has localStorage in the global context. return localStorage; } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? } } module.exports = require('./common')(exports); const {formatters} = module.exports; /** * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. */ formatters.j = function (v) { try { return JSON.stringify(v); } catch (error) { return '[UnexpectedJSONParseError]: ' + error.message; } }; }).call(this)}).call(this,require('_process')) },{"./common":9,"_process":59}],9:[function(require,module,exports){ /** * This is the common logic for both the Node.js and web browser * implementations of `debug()`. */ function setup(env) { createDebug.debug = createDebug; createDebug.default = createDebug; createDebug.coerce = coerce; createDebug.disable = disable; createDebug.enable = enable; createDebug.enabled = enabled; createDebug.humanize = require('ms'); createDebug.destroy = destroy; Object.keys(env).forEach(key => { createDebug[key] = env[key]; }); /** * The currently active debug mode names, and names to skip. */ createDebug.names = []; createDebug.skips = []; /** * Map of special "%n" handling functions, for the debug "format" argument. * * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". */ createDebug.formatters = {}; /** * Selects a color for a debug namespace * @param {String} namespace The namespace string for the debug instance to be colored * @return {Number|String} An ANSI color code for the given namespace * @api private */ function selectColor(namespace) { let hash = 0; for (let i = 0; i < namespace.length; i++) { hash = ((hash << 5) - hash) + namespace.charCodeAt(i); hash |= 0; // Convert to 32bit integer } return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; } createDebug.selectColor = selectColor; /** * Create a debugger with the given `namespace`. * * @param {String} namespace * @return {Function} * @api public */ function createDebug(namespace) { let prevTime; let enableOverride = null; let namespacesCache; let enabledCache; function debug(...args) { // Disabled? if (!debug.enabled) { return; } const self = debug; // Set `diff` timestamp const curr = Number(new Date()); const ms = curr - (prevTime || curr); self.diff = ms; self.prev = prevTime; self.curr = curr; prevTime = curr; args[0] = createDebug.coerce(args[0]); if (typeof args[0] !== 'string') { // Anything else let's inspect with %O args.unshift('%O'); } // Apply any `formatters` transformations let index = 0; args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => { // If we encounter an escaped % then don't increase the array index if (match === '%%') { return '%'; } index++; const formatter = createDebug.formatters[format]; if (typeof formatter === 'function') { const val = args[index]; match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format` args.splice(index, 1); index--; } return match; }); // Apply env-specific formatting (colors, etc.) createDebug.formatArgs.call(self, args); const logFn = self.log || createDebug.log; logFn.apply(self, args); } debug.namespace = namespace; debug.useColors = createDebug.useColors(); debug.color = createDebug.selectColor(namespace); debug.extend = extend; debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release. Object.defineProperty(debug, 'enabled', { enumerable: true, configurable: false, get: () => { if (enableOverride !== null) { return enableOverride; } if (namespacesCache !== createDebug.namespaces) { namespacesCache = createDebug.namespaces; enabledCache = createDebug.enabled(namespace); } return enabledCache; }, set: v => { enableOverride = v; } }); // Env-specific initialization logic for debug instances if (typeof createDebug.init === 'function') { createDebug.init(debug); } return debug; } function extend(namespace, delimiter) { const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); newDebug.log = this.log; return newDebug; } /** * Enables a debug mode by namespaces. This can include modes * separated by a colon and wildcards. * * @param {String} namespaces * @api public */ function enable(namespaces) { createDebug.save(namespaces); createDebug.namespaces = namespaces; createDebug.names = []; createDebug.skips = []; let i; const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); const len = split.length; for (i = 0; i < len; i++) { if (!split[i]) { // ignore empty strings continue; } namespaces = split[i].replace(/\*/g, '.*?'); if (namespaces[0] === '-') { createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); } else { createDebug.names.push(new RegExp('^' + namespaces + '$')); } } } /** * Disable debug output. * * @return {String} namespaces * @api public */ function disable() { const namespaces = [ ...createDebug.names.map(toNamespace), ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) ].join(','); createDebug.enable(''); return namespaces; } /** * Returns true if the given mode name is enabled, false otherwise. * * @param {String} name * @return {Boolean} * @api public */ function enabled(name) { if (name[name.length - 1] === '*') { return true; } let i; let len; for (i = 0, len = createDebug.skips.length; i < len; i++) { if (createDebug.skips[i].test(name)) { return false; } } for (i = 0, len = createDebug.names.length; i < len; i++) { if (createDebug.names[i].test(name)) { return true; } } return false; } /** * Convert regexp to namespace * * @param {RegExp} regxep * @return {String} namespace * @api private */ function toNamespace(regexp) { return regexp.toString() .substring(2, regexp.toString().length - 2) .replace(/\.\*\?$/, '*'); } /** * Coerce `val`. * * @param {Mixed} val * @return {Mixed} * @api private */ function coerce(val) { if (val instanceof Error) { return val.stack || val.message; } return val; } /** * XXX DO NOT USE. This is a temporary stub function. * XXX It WILL be removed in the next major release. */ function destroy() { console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); } createDebug.enable(createDebug.load()); return createDebug; } module.exports = setup; },{"ms":30}],10:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.hasCORS = void 0; // imported from https://github.com/component/has-cors let value = false; try { value = typeof XMLHttpRequest !== 'undefined' && 'withCredentials' in new XMLHttpRequest(); } catch (err) { // if XMLHttp support is disabled in IE then it will throw // when trying to create } exports.hasCORS = value; },{}],11:[function(require,module,exports){ "use strict"; // imported from https://github.com/galkn/querystring /** * Compiles a querystring * Returns string representation of the object * * @param {Object} * @api private */ Object.defineProperty(exports, "__esModule", { value: true }); exports.decode = exports.encode = void 0; function encode(obj) { let str = ''; for (let i in obj) { if (obj.hasOwnProperty(i)) { if (str.length) str += '&'; str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); } } return str; } exports.encode = encode; /** * Parses a simple querystring into an object * * @param {String} qs * @api private */ function decode(qs) { let qry = {}; let pairs = qs.split('&'); for (let i = 0, l = pairs.length; i < l; i++) { let pair = pairs[i].split('='); qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); } return qry; } exports.decode = decode; },{}],12:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parse = void 0; // imported from https://github.com/galkn/parseuri /** * Parses a URI * * Note: we could also have used the built-in URL object, but it isn't supported on all platforms. * * See: * - https://developer.mozilla.org/en-US/docs/Web/API/URL * - https://caniuse.com/url * - https://www.rfc-editor.org/rfc/rfc3986#appendix-B * * History of the parse() method: * - first commit: https://github.com/socketio/socket.io-client/commit/4ee1d5d94b3906a9c052b459f1a818b15f38f91c * - export into its own module: https://github.com/socketio/engine.io-client/commit/de2c561e4564efeb78f1bdb1ba39ef81b2822cb3 * - reimport: https://github.com/socketio/engine.io-client/commit/df32277c3f6d622eec5ed09f493cae3f3391d242 * * @author Steven Levithan <stevenlevithan.com> (MIT license) * @api private */ const re = /^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; const parts = [ 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' ]; function parse(str) { const src = str, b = str.indexOf('['), e = str.indexOf(']'); if (b != -1 && e != -1) { str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); } let m = re.exec(str || ''), uri = {}, i = 14; while (i--) { uri[parts[i]] = m[i] || ''; } if (b != -1 && e != -1) { uri.source = src; uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); uri.ipv6uri = true; } uri.pathNames = pathNames(uri, uri['path']); uri.queryKey = queryKey(uri, uri['query']); return uri; } exports.parse = parse; function pathNames(obj, path) { const regx = /\/{2,9}/g, names = path.replace(regx, "/").split("/"); if (path.slice(0, 1) == '/' || path.length === 0) { names.splice(0, 1); } if (path.slice(-1) == '/') { names.splice(names.length - 1, 1); } return names; } function queryKey(uri, query) { const data = {}; query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) { if ($1) { data[$1] = $2; } }); return data; } },{}],13:[function(require,module,exports){ // imported from https://github.com/unshiftio/yeast 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.yeast = exports.decode = exports.encode = void 0; const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split(''), length = 64, map = {}; let seed = 0, i = 0, prev; /** * Return a string representing the specified number. * * @param {Number} num The number to convert. * @returns {String} The string representation of the number. * @api public */ function encode(num) { let encoded = ''; do { encoded = alphabet[num % length] + encoded; num = Math.floor(num / length); } while (num > 0); return encoded; } exports.encode = encode; /** * Return the integer value specified by the given string. * * @param {String} str The string to convert. * @returns {Number} The integer value represented by the string. * @api public */ function decode(str) { let decoded = 0; for (i = 0; i < str.length; i++) { decoded = decoded * length + map[str.charAt(i)]; } return decoded; } exports.decode = decode; /** * Yeast: A tiny growing id generator. * * @returns {String} A unique id. * @api public */ function yeast() { const now = encode(+new Date()); if (now !== prev) return seed = 0, prev = now; return now + '.' + encode(seed++); } exports.yeast = yeast; // // Map each character to its index. // for (; i < length; i++) map[alphabet[i]] = i; },{}],14:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.globalThisShim = void 0; exports.globalThisShim = (() => { if (typeof self !== "undefined") { return self; } else if (typeof window !== "undefined") { return window; } else { return Function("return this")(); } })(); },{}],15:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.nextTick = exports.parse = exports.installTimerFunctions = exports.transports = exports.Transport = exports.protocol = exports.Socket = void 0; const socket_js_1 = require("./socket.js"); Object.defineProperty(exports, "Socket", { enumerable: true, get: function () { return socket_js_1.Socket; } }); exports.protocol = socket_js_1.Socket.protocol; var transport_js_1 = require("./transport.js"); Object.defineProperty(exports, "Transport", { enumerable: true, get: function () { return transport_js_1.Transport; } }); var index_js_1 = require("./transports/index.js"); Object.defineProperty(exports, "transports", { enumerable: true, get: function () { return index_js_1.transports; } }); var util_js_1 = require("./util.js"); Object.defineProperty(exports, "installTimerFunctions", { enumerable: true, get: function () { return util_js_1.installTimerFunctions; } }); var parseuri_js_1 = require("./contrib/parseuri.js"); Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parseuri_js_1.parse; } }); var websocket_constructor_js_1 = require("./transports/websocket-constructor.js"); Object.defineProperty(exports, "nextTick", { enumerable: true, get: function () { return websocket_constructor_js_1.nextTick; } }); },{"./contrib/parseuri.js":12,"./socket.js":16,"./transport.js":17,"./transports/index.js":18,"./transports/websocket-constructor.js":20,"./util.js":24}],16:[function(require,module,exports){ "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Socket = void 0; const index_js_1 = require("./transports/index.js"); const util_js_1 = require("./util.js"); const parseqs_js_1 = require("./contrib/parseqs.js"); const parseuri_js_1 = require("./contrib/parseuri.js"); const debug_1 = __importDefault(require("debug")); // debug() const component_emitter_1 = require("@socket.io/component-emitter"); const engine_io_parser_1 = require("engine.io-parser"); const websocket_constructor_js_1 = require("./transports/websocket-constructor.js"); const debug = (0, debug_1.default)("engine.io-client:socket"); // debug() class Socket extends component_emitter_1.Emitter { /** * Socket constructor. * * @param {String|Object} uri - uri or options * @param {Object} opts - options */ constructor(uri, opts = {}) { super(); this.binaryType = websocket_constructor_js_1.defaultBinaryType; this.writeBuffer = []; if (uri && "object" === typeof uri) { opts = uri; uri = null; } if (uri) { uri = (0, parseuri_js_1.parse)(uri); opts.hostname = uri.host; opts.secure = uri.protocol === "https" || uri.protocol === "wss"; opts.port = uri.port; if (uri.query) opts.query = uri.query; } else if (opts.host) { opts.hostname = (0, parseuri_js_1.parse)(opts.host).host; } (0, util_js_1.installTimerFunctions)(this, opts); this.secure = null != opts.secure ? opts.secure : typeof location !== "undefined" && "https:" === location.protocol; if (opts.hostname && !opts.port) { // if no port is specified manually, use the protocol default opts.port = this.secure ? "443" : "80"; } this.hostname = opts.hostname || (typeof location !== "undefined" ? location.hostname : "localhost"); this.port = opts.port || (typeof location !== "undefined" && location.port ? location.port : this.secure