UNPKG

@skylineos/videojs-clsp

Version:

Video JS plugin for Skyline Technology Solutions' CLSP Player - https://github.com/skylineos/clsp-player

1,592 lines (1,394 loc) 807 kB
/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 478: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; /** * This file needs to use `require` rather than `import` to be able to be used * by webpack. */ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var clspPlayerUtils = __webpack_require__(863); var Logger = __webpack_require__(764); var _require = __webpack_require__(330), version = _require.version, name = _require.name; module.exports = _objectSpread({}, clspPlayerUtils, { version: version, name: name.split('/').pop(), // The name that will be used to register this plugin with videojs, which in // practice will be used as `player.clsp()` pluginName: 'clsp', Logger: Logger, // This gives us access to the clsp player version and name (and of course, it // duplicates the utils) clspPlayerUtils: clspPlayerUtils }); /***/ }), /***/ 764: /***/ ((module) => { "use strict"; /* eslint no-console: off */ /** * This file needs to use `require` rather than `import` to be able to be used * by webpack. * * We use this in the router as well, so keep it light and ES5 only! */ module.exports = function (version, logLevel, disableLogging) { function Logger(prefix, prefixStyle) { if (logLevel === undefined && typeof window !== 'undefined') { var storedVersion = window.localStorage.getItem('skylineos.clsp-player.version'); // Always reset the log level when the version changes if (storedVersion !== version) { window.localStorage.setItem('skylineos.clsp-player.logLevel', 0); window.localStorage.setItem('skylineos.clsp-player.version', version); } var storedLogLevel = Number(window.localStorage.getItem('skylineos.clsp-player.logLevel')); // The logLevel may be set in localstorage // e.g. localStorage.setItem('skylineos.clsp-player.logLevel', 3), then refresh logLevel = isNaN(storedLogLevel) || storedLogLevel < 0 ? 0 : storedLogLevel; window.localStorage.setItem('skylineos.clsp-player.logLevel', logLevel); } this.logLevel = logLevel; this.prefix = prefix; this.prefixStyle = prefixStyle; } Logger.logLevels = ['critical', 'error', 'warn', 'info', 'debug', 'silly']; Logger.factory = function (prefix, prefixStyle) { return new Logger(prefix || '', prefixStyle); }; Logger.prototype._constructMessage = function (type, message) { var logMessage = '(' + type + ')' + ' --> ' + message; // @see - https://developers.google.com/web/tools/chrome-devtools/console/console-write#string_substitution_and_formatting if (this.prefix && this.prefixStyle && this.logLevel > 1) { return ['%c' + this.prefix, this.prefixStyle, logMessage]; } if (this.prefix) { return [this.prefix, logMessage]; } return [logMessage]; }; var sillyIndex = 5; var debugIndex = 4; var infoIndex = 3; var warnIndex = 2; var errorIndex = 1; var criticalIndex = 0; Logger.prototype.silly = function (message) { if (this.logLevel < sillyIndex || disableLogging) { return; } console.log.apply(console, this._constructMessage(Logger.logLevels[sillyIndex], message)); }; Logger.prototype.debug = function (message) { if (this.logLevel < debugIndex || disableLogging) { return; } console.log.apply(console, this._constructMessage(Logger.logLevels[debugIndex], message)); }; Logger.prototype.info = function (message) { if (this.logLevel < infoIndex || disableLogging) { return; } console.log.apply(console, this._constructMessage(Logger.logLevels[infoIndex], message)); }; Logger.prototype.warn = function (message) { if (this.logLevel < warnIndex || disableLogging) { return; } console.warn.apply(console, this._constructMessage(Logger.logLevels[warnIndex], message)); }; Logger.prototype.error = function (message) { if (this.logLevel < errorIndex || disableLogging) { return; } console.error.apply(console, this._constructMessage(Logger.logLevels[errorIndex], message)); }; Logger.prototype.critical = function (message) { if (disableLogging) { return; } console.error.apply(console, this._constructMessage(Logger.logLevels[criticalIndex], message)); }; return Logger; }; /***/ }), /***/ 863: /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; /** * This file needs to use `require` rather than `import` to be able to be used * by webpack. */ var packageJson = __webpack_require__(814); var Logger = __webpack_require__(764); var _isPlayerLoggingEnabled = true; // CLSP default port for SFS >= 5.2.0 is 80 // CLSP default port for SFS < 5.2.0 is 9001 var DEFAULT_CLSP_PORT = 80; var DEFAULT_CLSPS_PORT = 443; // Locally-scoped value that maintains the clsp and clsps port states. // // @see - getDefaultStreamPort // @see - setDefaultStreamPort // // @todo - state / config could be managed better than this var streamPorts = { clsp: DEFAULT_CLSP_PORT, clsps: DEFAULT_CLSPS_PORT }; /** * The name of the CLSP Player library as defined in `package.json` without the * group name. * * @type {String} */ var name = packageJson.name.split('/').pop(); /** * The version of the CLSP Player library. Follows semver. * * @type {String} */ var version = packageJson.version; // @todo - remove this side-effect var logger = Logger(version).factory(); /** * The oldest Chrome browser version supported by CLSP Player. * * @type {Number} */ var MINIMUM_CHROME_VERSION = 53; /** * The MIME type required for CLSP Player to be able to play the stream. * * @todo - this mime type, though used in the videojs plugin, and * seemingly enforced, is not actually enforced. The only enforcement * done is requiring the user provide this string on the video element * in the DOM. The codecs that are supplied by the SFS's vary. Here * are some "valid", though not enforced mimeCodec values I have come * across: * - video/mp4; codecs="avc1.4DE016" * - video/mp4; codecs="avc1.42E00C" * - video/mp4; codecs="avc1.42E00D" * * @type {String} */ var SUPPORTED_MIME_TYPE = "video/mp4; codecs='avc1.42E01E'"; /** * The amount of time (in seconds) before a stream times out. * * Note that this timeout value should be treated as the minimum value to * support Vero tours and high-quality streams. * * @type {Number} */ var DEFAULT_STREAM_TIMEOUT = 20; /** * Determine whether or not the CLSP Player is supported in the current browser. * * @todo - we are currently manually checking useragentstring - we should find a * library that can check browser type for us * * @returns {Boolean} * `true` if the browser is supported by CLSP Player * `false` if the browser is not supported by CLSP Player */ function isBrowserCompatable() { // @todo - at one time, this was needed for browsers on MacOS - is this still // necessary? window.MediaSource = window.MediaSource || window.WebKitMediaSource; if (!window.MediaSource) { console.error('Media Source Extensions not supported in your browser, unable to load CLSP Player'); return false; } var isInternetExplorer = navigator.userAgent.toLowerCase().indexOf('trident') > -1; if (isInternetExplorer) { logger.debug('Detected Internet Explorer browser, which is not supported.'); return false; } var isEdge = navigator.userAgent.toLowerCase().indexOf('edge') > -1; if (isEdge) { logger.debug('Detected older Edge browser, which is not supported'); return false; } var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; if (isFirefox) { logger.debug('Detected Firefox browser'); return true; } // Most browsers have "Chrome" in their user agent. The above filters rule // out Internet Explorer and Edge, so we are going to assume that if we're at // this point, we're really dealing with Chrome. var isChrome = Boolean(window.chrome); if (!isChrome) { return false; } try { // Rather than accounting for match returning null, we'll catch the error var chromeVersion = parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); logger.debug("Detected Chrome version ".concat(chromeVersion)); return chromeVersion >= MINIMUM_CHROME_VERSION; } catch (error) { logger.critical('Unable to detect Chrome version'); logger.critical(error); return false; } } /** * Check to see if the passed mimeType is supported by CLSP Player. * * @param {String} mimeType * Will check to see if this mimeType is supported * * @returns {Boolean} * `true` if the mimeType is supported by CLSP Player * `false` if the mimeType is not supported by CLSP Player */ function isSupportedMimeType(mimeType) { return mimeType === SUPPORTED_MIME_TYPE; } /** * @typedef {Object} PageVisibilityApiPropertyNames * @property {String} hiddenStateName * The property name used for the `document.hidden` property * @property {String} visibilityChangeEventName * The property name used for the `document.visibilityChange` event name */ /** * Get the property names used by this browser for the Page Visibility API. * * @returns {PageVisibilityApiPropertyNames} */ function getWindowStateNames() { logger.debug('Determining Page_Visibility_API property names.'); // @todo - this check is needed to support these utils being imported by // webpack. there is probably a more elegant way to handle this scenario. if (typeof document === 'undefined') { return { hiddenStateName: '', visibilityChangeEventName: '' }; } // @see - https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API if (typeof document.hidden !== 'undefined') { logger.debug('Using standard Page_Visibility_API property names.'); return { hiddenStateName: 'hidden', visibilityChangeEventName: 'visibilitychange' }; } // @todo - do we need this since we don't support IE or old Edge? if (typeof document.msHidden !== 'undefined') { logger.debug('Using Microsoft Page_Visibility_API property names.'); return { hiddenStateName: 'msHidden', visibilityChangeEventName: 'msvisibilitychange' }; } if (typeof document.webkitHidden !== 'undefined') { logger.debug('Using Webkit Page_Visibility_API property names.'); return { hiddenStateName: 'webkitHidden', visibilityChangeEventName: 'webkitvisibilitychange' }; } logger.critical('Unable to use the page visibility api - switching tabs and minimizing the page may result in slow downs and page crashes.'); return { hiddenStateName: '', visibilityChangeEventName: '' }; } /** * Get the default port number for the given protocol. * * @param {String} protocol * The protocol to get the default port for. Must be a known protocol (e.g. * `clsp` or `clsps`) */ function getDefaultStreamPort(protocol) { return streamPorts[protocol]; } /** * Set the default port number for the given protocol. * * @param {String} protocol * The protocol to set the default port for. Must be a known protocol (e.g. * `clsp` or `clsps`) */ function setDefaultStreamPort(protocol, port) { streamPorts[protocol] = port; } function enablePlayerLogging() { _isPlayerLoggingEnabled = true; } function disablePlayerLogging() { _isPlayerLoggingEnabled = false; } function isPlayerLoggingDisabled() { return !_isPlayerLoggingEnabled; } var windowStateNames = getWindowStateNames(); function isDocumentHidden() { return document[windowStateNames.hiddenStateName]; } function isOnline() { return window.navigator.onLine; } module.exports = { name: name, version: version, MINIMUM_CHROME_VERSION: MINIMUM_CHROME_VERSION, SUPPORTED_MIME_TYPE: SUPPORTED_MIME_TYPE, DEFAULT_STREAM_TIMEOUT: DEFAULT_STREAM_TIMEOUT, supported: isBrowserCompatable, isSupportedMimeType: isSupportedMimeType, windowStateNames: windowStateNames, isDocumentHidden: isDocumentHidden, isOnline: isOnline, getDefaultStreamPort: getDefaultStreamPort, setDefaultStreamPort: setDefaultStreamPort, enablePlayerLogging: enablePlayerLogging, disablePlayerLogging: disablePlayerLogging, isPlayerLoggingDisabled: isPlayerLoggingDisabled }; /***/ }), /***/ 228: /***/ ((module) => { "use strict"; var has = Object.prototype.hasOwnProperty , prefix = '~'; /** * Constructor to create a storage for our `EE` objects. * An `Events` instance is a plain object whose properties are event names. * * @constructor * @private */ function Events() {} // // We try to not inherit from `Object.prototype`. In some engines creating an // instance in this way is faster than calling `Object.create(null)` directly. // If `Object.create(null)` is not supported we prefix the event names with a // character to make sure that the built-in object properties are not // overridden or used as an attack vector. // if (Object.create) { Events.prototype = Object.create(null); // // This hack is needed because the `__proto__` property is still inherited in // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. // if (!new Events().__proto__) prefix = false; } /** * Representation of a single event listener. * * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} [once=false] Specify if the listener is a one-time listener. * @constructor * @private */ function EE(fn, context, once) { this.fn = fn; this.context = context; this.once = once || false; } /** * Add a listener for a given event. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} context The context to invoke the listener with. * @param {Boolean} once Specify if the listener is a one-time listener. * @returns {EventEmitter} * @private */ function addListener(emitter, event, fn, context, once) { if (typeof fn !== 'function') { throw new TypeError('The listener must be a function'); } var listener = new EE(fn, context || emitter, once) , evt = prefix ? prefix + event : event; if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); else emitter._events[evt] = [emitter._events[evt], listener]; return emitter; } /** * Clear event by name. * * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. * @param {(String|Symbol)} evt The Event name. * @private */ function clearEvent(emitter, evt) { if (--emitter._eventsCount === 0) emitter._events = new Events(); else delete emitter._events[evt]; } /** * Minimal `EventEmitter` interface that is molded against the Node.js * `EventEmitter` interface. * * @constructor * @public */ function EventEmitter() { this._events = new Events(); this._eventsCount = 0; } /** * Return an array listing the events for which the emitter has registered * listeners. * * @returns {Array} * @public */ EventEmitter.prototype.eventNames = function eventNames() { var names = [] , events , name; if (this._eventsCount === 0) return names; for (name in (events = this._events)) { if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); } if (Object.getOwnPropertySymbols) { return names.concat(Object.getOwnPropertySymbols(events)); } return names; }; /** * Return the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Array} The registered listeners. * @public */ EventEmitter.prototype.listeners = function listeners(event) { var evt = prefix ? prefix + event : event , handlers = this._events[evt]; if (!handlers) return []; if (handlers.fn) return [handlers.fn]; for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) { ee[i] = handlers[i].fn; } return ee; }; /** * Return the number of listeners listening to a given event. * * @param {(String|Symbol)} event The event name. * @returns {Number} The number of listeners. * @public */ EventEmitter.prototype.listenerCount = function listenerCount(event) { var evt = prefix ? prefix + event : event , listeners = this._events[evt]; if (!listeners) return 0; if (listeners.fn) return 1; return listeners.length; }; /** * Calls each of the listeners registered for a given event. * * @param {(String|Symbol)} event The event name. * @returns {Boolean} `true` if the event had listeners, else `false`. * @public */ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return false; var listeners = this._events[evt] , len = arguments.length , args , i; if (listeners.fn) { if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); switch (len) { case 1: return listeners.fn.call(listeners.context), true; case 2: return listeners.fn.call(listeners.context, a1), true; case 3: return listeners.fn.call(listeners.context, a1, a2), true; case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; } for (i = 1, args = new Array(len -1); i < len; i++) { args[i - 1] = arguments[i]; } listeners.fn.apply(listeners.context, args); } else { var length = listeners.length , j; for (i = 0; i < length; i++) { if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); switch (len) { case 1: listeners[i].fn.call(listeners[i].context); break; case 2: listeners[i].fn.call(listeners[i].context, a1); break; case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; default: if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { args[j - 1] = arguments[j]; } listeners[i].fn.apply(listeners[i].context, args); } } } return true; }; /** * Add a listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.on = function on(event, fn, context) { return addListener(this, event, fn, context, false); }; /** * Add a one-time listener for a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn The listener function. * @param {*} [context=this] The context to invoke the listener with. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.once = function once(event, fn, context) { return addListener(this, event, fn, context, true); }; /** * Remove the listeners of a given event. * * @param {(String|Symbol)} event The event name. * @param {Function} fn Only remove the listeners that match this function. * @param {*} context Only remove the listeners that have this context. * @param {Boolean} once Only remove one-time listeners. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { var evt = prefix ? prefix + event : event; if (!this._events[evt]) return this; if (!fn) { clearEvent(this, evt); return this; } var listeners = this._events[evt]; if (listeners.fn) { if ( listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context) ) { clearEvent(this, evt); } } else { for (var i = 0, events = [], length = listeners.length; i < length; i++) { if ( listeners[i].fn !== fn || (once && !listeners[i].once) || (context && listeners[i].context !== context) ) { events.push(listeners[i]); } } // // Reset the array, or remove it completely if we have no more listeners. // if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; else clearEvent(this, evt); } return this; }; /** * Remove all listeners, or those of the specified event. * * @param {(String|Symbol)} [event] The event name. * @returns {EventEmitter} `this`. * @public */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { var evt; if (event) { evt = prefix ? prefix + event : event; if (this._events[evt]) clearEvent(this, evt); } else { this._events = new Events(); this._eventsCount = 0; } return this; }; // // Alias methods names because people roll like that. // EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.addListener = EventEmitter.prototype.on; // // Expose the prefix. // EventEmitter.prefixed = prefix; // // Allow `EventEmitter` to be imported as module namespace. // EventEmitter.EventEmitter = EventEmitter; // // Expose the module. // if (true) { module.exports = EventEmitter; } /***/ }), /***/ 973: /***/ ((module) => { /** * @param {*} val - value to check * * @returns {boolean} true if the value is then-able */ function isPromise(val) { return val != null && typeof val.then === 'function' } /** * @param {function} func - function to execute * @param {number|function(number):number} intervalLength - length in ms to wait before executing again * @param {{iterations: Infinity|number, stopOnError: boolean}} [options] * * @returns {Promise} Promise object with no result */ function interval(func, intervalLength, options = {}) { validateArgs(func, intervalLength, options) const defaults = { iterations: Infinity, stopOnError: true } const settings = Object.assign(defaults, options) return new Promise((rootPromiseResolve, rootPromiseReject) => { const callFunction = currentIteration => { // Set up a way to track if a "stop" was requested by the user function let stopRequested = false const stop = () => { stopRequested = true } // Set up a function to call the next iteration. This is abstracted so it can be called by .then(), or in .catch(), if options allow. const callNext = () => { // If we've hit the desired number of iterations, or stop was called, resolve the root promise and return if (currentIteration === settings.iterations || stopRequested) { rootPromiseResolve() return } // Otherwise, call the next iteration callFunction(currentIteration + 1) } // Calculate our interval length const calculatedIntervalLength = (typeof intervalLength === 'function') ? intervalLength(currentIteration) : intervalLength // If the interval length was calculated, validate the result if (typeof intervalLength === 'function') { if (!Number.isInteger(calculatedIntervalLength) || calculatedIntervalLength < 0) { rootPromiseReject(new Error('Function for "intervalLength" argument must return a non-negative integer.')) return } } // Call the user function after the desired interval length. After, call the next iteration (and/or handle error) setTimeout(() => { const returnVal = func(currentIteration, stop) // Ensure that the value returned is a promise if (!isPromise(returnVal)) { rootPromiseReject(new Error('Return value of "func" must be a Promise.')) return } returnVal.then(callNext).catch(err => { if (!settings.stopOnError) { callNext() return } rootPromiseReject(err) }) }, calculatedIntervalLength) } callFunction(1) }) } /** * A helper function to validate the arguments passed to interval(...) * * @param {*} func * @param {*} intervalLength * @param {*} options */ function validateArgs(func, intervalLength, options) { // Validate "func" if (typeof func !== 'function') { throw new TypeError('Argument 1, "func", must be a function.') } // Validate "intervalLength" if (typeof intervalLength === 'number') { if (!Number.isInteger(intervalLength) || intervalLength < 0) { throw new TypeError('Argument 2, "intervalLength", must be a non-negative integer or a function that returns a non-negative integer.') } } else if (typeof intervalLength !== 'function') { throw new TypeError('Argument 2, "intervalLength", must be a non-negative integer or a function that returns a non-negative integer.') } // Validate options... if (typeof options !== 'object') { throw new TypeError('Argument 3, "options", must be an object.') } // Validate passed keys const allowedKeys = ['iterations', 'stopOnError'] Object.keys(options).forEach(key => { if (!allowedKeys.includes(key)) { throw new TypeError('Option "' + key + '" is not a valid option.') } }) // validate "iterations" option (if passed) if (typeof options.iterations !== 'undefined') { if (options.iterations !== Infinity && (!Number.isInteger(options.iterations) || options.iterations < 1)) { throw new TypeError('Option "iterations" must be Infinity or an integer greater than 0.') } } // validate "stopOnError" option (if passed) if (typeof options.stopOnError !== 'undefined') { if (typeof options.stopOnError !== 'boolean') { throw new TypeError('Option "stopOnError" must be a boolean.') } } } module.exports = interval /***/ }), /***/ 843: /***/ ((module) => { /** * Checks if `value` is `null` or `undefined`. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is nullish, else `false`. * @example * * _.isNil(null); * // => true * * _.isNil(void 0); * // => true * * _.isNil(NaN); * // => false */ function isNil(value) { return value == null; } module.exports = isNil; /***/ }), /***/ 543: /***/ (function(module) { /******************************************************************************* * Copyright (c) 2013 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Andrew Banks - initial API and implementation and initial documentation *******************************************************************************/ // Only expose a single object name in the global namespace. // Everything must go through this module. Global Paho module // only has a single public function, client, which returns // a Paho client object given connection details. /** * Send and receive messages using web browsers. * <p> * This programming interface lets a JavaScript client application use the MQTT V3.1 or * V3.1.1 protocol to connect to an MQTT-supporting messaging server. * * The function supported includes: * <ol> * <li>Connecting to and disconnecting from a server. The server is identified by its host name and port number. * <li>Specifying options that relate to the communications link with the server, * for example the frequency of keep-alive heartbeats, and whether SSL/TLS is required. * <li>Subscribing to and receiving messages from MQTT Topics. * <li>Publishing messages to MQTT Topics. * </ol> * <p> * The API consists of two main objects: * <dl> * <dt><b>{@link Paho.Client}</b></dt> * <dd>This contains methods that provide the functionality of the API, * including provision of callbacks that notify the application when a message * arrives from or is delivered to the messaging server, * or when the status of its connection to the messaging server changes.</dd> * <dt><b>{@link Paho.Message}</b></dt> * <dd>This encapsulates the payload of the message along with various attributes * associated with its delivery, in particular the destination to which it has * been (or is about to be) sent.</dd> * </dl> * <p> * The programming interface validates parameters passed to it, and will throw * an Error containing an error message intended for developer use, if it detects * an error with any parameter. * <p> * Example: * * <code><pre> var client = new Paho.MQTT.Client(location.hostname, Number(location.port), "clientId"); client.onConnectionLost = onConnectionLost; client.onMessageArrived = onMessageArrived; client.connect({onSuccess:onConnect}); function onConnect() { // Once a connection has been made, make a subscription and send a message. console.log("onConnect"); client.subscribe("/World"); var message = new Paho.MQTT.Message("Hello"); message.destinationName = "/World"; client.send(message); }; function onConnectionLost(responseObject) { if (responseObject.errorCode !== 0) console.log("onConnectionLost:"+responseObject.errorMessage); }; function onMessageArrived(message) { console.log("onMessageArrived:"+message.payloadString); client.disconnect(); }; * </pre></code> * @namespace Paho */ /* jshint shadow:true */ (function ExportLibrary(root, factory) { if(true){ module.exports = factory(); } else {} })(this, function LibraryFactory(){ var PahoMQTT = (function (global) { // Private variables below, these are only visible inside the function closure // which is used to define the module. var version = "@VERSION@-@BUILDLEVEL@"; /** * @private */ var localStorage = global.localStorage || (function () { var data = {}; return { setItem: function (key, item) { data[key] = item; }, getItem: function (key) { return data[key]; }, removeItem: function (key) { delete data[key]; }, }; })(); /** * Unique message type identifiers, with associated * associated integer values. * @private */ var MESSAGE_TYPE = { CONNECT: 1, CONNACK: 2, PUBLISH: 3, PUBACK: 4, PUBREC: 5, PUBREL: 6, PUBCOMP: 7, SUBSCRIBE: 8, SUBACK: 9, UNSUBSCRIBE: 10, UNSUBACK: 11, PINGREQ: 12, PINGRESP: 13, DISCONNECT: 14 }; // Collection of utility methods used to simplify module code // and promote the DRY pattern. /** * Validate an object's parameter names to ensure they * match a list of expected variables name for this option * type. Used to ensure option object passed into the API don't * contain erroneous parameters. * @param {Object} obj - User options object * @param {Object} keys - valid keys and types that may exist in obj. * @throws {Error} Invalid option parameter found. * @private */ var validate = function(obj, keys) { for (var key in obj) { if (obj.hasOwnProperty(key)) { if (keys.hasOwnProperty(key)) { if (typeof obj[key] !== keys[key]) throw new Error(format(ERROR.INVALID_TYPE, [typeof obj[key], key])); } else { var errorStr = "Unknown property, " + key + ". Valid properties are:"; for (var validKey in keys) if (keys.hasOwnProperty(validKey)) errorStr = errorStr+" "+validKey; throw new Error(errorStr); } } } }; /** * Return a new function which runs the user function bound * to a fixed scope. * @param {function} User function * @param {object} Function scope * @return {function} User function bound to another scope * @private */ var scope = function (f, scope) { return function () { return f.apply(scope, arguments); }; }; /** * Unique message type identifiers, with associated * associated integer values. * @private */ var ERROR = { OK: {code:0, text:"AMQJSC0000I OK."}, CONNECT_TIMEOUT: {code:1, text:"AMQJSC0001E Connect timed out."}, SUBSCRIBE_TIMEOUT: {code:2, text:"AMQJS0002E Subscribe timed out."}, UNSUBSCRIBE_TIMEOUT: {code:3, text:"AMQJS0003E Unsubscribe timed out."}, PING_TIMEOUT: {code:4, text:"AMQJS0004E Ping timed out."}, INTERNAL_ERROR: {code:5, text:"AMQJS0005E Internal error. Error Message: {0}, Stack trace: {1}"}, CONNACK_RETURNCODE: {code:6, text:"AMQJS0006E Bad Connack return code:{0} {1}."}, SOCKET_ERROR: {code:7, text:"AMQJS0007E Socket error:{0}."}, SOCKET_CLOSE: {code:8, text:"AMQJS0008I Socket closed."}, MALFORMED_UTF: {code:9, text:"AMQJS0009E Malformed UTF data:{0} {1} {2}."}, UNSUPPORTED: {code:10, text:"AMQJS0010E {0} is not supported by this browser."}, INVALID_STATE: {code:11, text:"AMQJS0011E Invalid state {0}."}, INVALID_TYPE: {code:12, text:"AMQJS0012E Invalid type {0} for {1}."}, INVALID_ARGUMENT: {code:13, text:"AMQJS0013E Invalid argument {0} for {1}."}, UNSUPPORTED_OPERATION: {code:14, text:"AMQJS0014E Unsupported operation."}, INVALID_STORED_DATA: {code:15, text:"AMQJS0015E Invalid data in local storage key={0} value={1}."}, INVALID_MQTT_MESSAGE_TYPE: {code:16, text:"AMQJS0016E Invalid MQTT message type {0}."}, MALFORMED_UNICODE: {code:17, text:"AMQJS0017E Malformed Unicode string:{0} {1}."}, BUFFER_FULL: {code:18, text:"AMQJS0018E Message buffer is full, maximum buffer size: {0}."}, }; /** CONNACK RC Meaning. */ var CONNACK_RC = { 0:"Connection Accepted", 1:"Connection Refused: unacceptable protocol version", 2:"Connection Refused: identifier rejected", 3:"Connection Refused: server unavailable", 4:"Connection Refused: bad user name or password", 5:"Connection Refused: not authorized" }; /** * Format an error message text. * @private * @param {error} ERROR value above. * @param {substitutions} [array] substituted into the text. * @return the text with the substitutions made. */ var format = function(error, substitutions) { var text = error.text; if (substitutions) { var field,start; for (var i=0; i<substitutions.length; i++) { field = "{"+i+"}"; start = text.indexOf(field); if(start > 0) { var part1 = text.substring(0,start); var part2 = text.substring(start+field.length); text = part1+substitutions[i]+part2; } } } return text; }; //MQTT protocol and version 6 M Q I s d p 3 var MqttProtoIdentifierv3 = [0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70,0x03]; //MQTT proto/version for 311 4 M Q T T 4 var MqttProtoIdentifierv4 = [0x00,0x04,0x4d,0x51,0x54,0x54,0x04]; /** * Construct an MQTT wire protocol message. * @param type MQTT packet type. * @param options optional wire message attributes. * * Optional properties * * messageIdentifier: message ID in the range [0..65535] * payloadMessage: Application Message - PUBLISH only * connectStrings: array of 0 or more Strings to be put into the CONNECT payload * topics: array of strings (SUBSCRIBE, UNSUBSCRIBE) * requestQoS: array of QoS values [0..2] * * "Flag" properties * cleanSession: true if present / false if absent (CONNECT) * willMessage: true if present / false if absent (CONNECT) * isRetained: true if present / false if absent (CONNECT) * userName: true if present / false if absent (CONNECT) * password: true if present / false if absent (CONNECT) * keepAliveInterval: integer [0..65535] (CONNECT) * * @private * @ignore */ var WireMessage = function (type, options) { this.type = type; for (var name in options) { if (options.hasOwnProperty(name)) { this[name] = options[name]; } } }; WireMessage.prototype.encode = function() { // Compute the first byte of the fixed header var first = ((this.type & 0x0f) << 4); /* * Now calculate the length of the variable header + payload by adding up the lengths * of all the component parts */ var remLength = 0; var topicStrLength = []; var destinationNameLength = 0; var willMessagePayloadBytes; // if the message contains a messageIdentifier then we need two bytes for that if (this.messageIdentifier !== undefined) remLength += 2; switch(this.type) { // If this a Connect then we need to include 12 bytes for its header case MESSAGE_TYPE.CONNECT: switch(this.mqttVersion) { case 3: remLength += MqttProtoIdentifierv3.length + 3; break; case 4: remLength += MqttProtoIdentifierv4.length + 3; break; } remLength += UTF8Length(this.clientId) + 2; if (this.willMessage !== undefined) { remLength += UTF8Length(this.willMessage.destinationName) + 2; // Will message is always a string, sent as UTF-8 characters with a preceding length. willMessagePayloadBytes = this.willMessage.payloadBytes; if (!(willMessagePayloadBytes instanceof Uint8Array)) willMessagePayloadBytes = new Uint8Array(payloadBytes); remLength += willMessagePayloadBytes.byteLength +2; } if (this.userName !== undefined) remLength += UTF8Length(this.userName) + 2; if (this.password !== undefined) remLength += UTF8Length(this.password) + 2; break; // Subscribe, Unsubscribe can both contain topic strings case MESSAGE_TYPE.SUBSCRIBE: first |= 0x02; // Qos = 1; for ( var i = 0; i < this.topics.length; i++) { topicStrLength[i] = UTF8Length(this.topics[i]); remLength += topicStrLength[i] + 2; } remLength += this.requestedQos.length; // 1 byte for each topic's Qos // QoS on Subscribe only break; case MESSAGE_TYPE.UNSUBSCRIBE: first |= 0x02; // Qos = 1; for ( var i = 0; i < this.topics.length; i++) { topicStrLength[i] = UTF8Length(this.topics[i]); remLength += topicStrLength[i] + 2; } break; case MESSAGE_TYPE.PUBREL: first |= 0x02; // Qos = 1; break; case MESSAGE_TYPE.PUBLISH: if (this.payloadMessage.duplicate) first |= 0x08; first = first |= (this.payloadMessage.qos << 1); if (this.payloadMessage.retained) first |= 0x01; destinationNameLength = UTF8Length(this.payloadMessage.destinationName); remLength += destinationNameLength + 2; var payloadBytes = this.payloadMessage.payloadBytes; remLength += payloadBytes.byteLength; if (payloadBytes instanceof ArrayBuffer) payloadBytes = new Uint8Array(payloadBytes); else if (!(payloadBytes instanceof Uint8Array)) payloadBytes = new Uint8Array(payloadBytes.buffer); break; case MESSAGE_TYPE.DISCONNECT: break; default: break; } // Now we can allocate a buffer for the message var mbi = encodeMBI(remLength); // Convert the length to MQTT MBI format var pos = mbi.length + 1; // Offset of start of variable header var buffer = new ArrayBuffer(remLength + pos); var byteStream = new Uint8Array(buffer); // view it as a sequence of bytes //Write the fixed header into the buffer byteStream[0] = first; byteStream.set(mbi,1); // If this is a PUBLISH then the variable header starts with a topic if (this.type == MESSAGE_TYPE.PUBLISH) pos = writeString(this.payloadMessage.destinationName, destinationNameLength, byteStream, pos); // If this is a CONNECT then the variable header contains the protocol name/version, flags and keepalive time else if (this.type == MESSAGE_TYPE.CONNECT) { switch (this.mqttVersion) { case 3: byteStream.set(MqttProtoIdentifierv3, pos); pos += MqttProtoIdentifierv3.length; break; case 4: byteStream.set(MqttProtoIdentifierv4, pos); pos += MqttProtoIdentifierv4.length; break; } var connectFlags = 0; if (this.cleanSession) connectFlags = 0x02; if (this.willMessage !== undefined ) { connectFlags |= 0x04; connectFlags |= (this.willMessage.qos<<3); if (this.willMessage.retained) { connectFlags |= 0x20; } } if (this.userName !== undefined) connectFlags |= 0x80; if (this.password !== undefined) connectFlags |= 0x40; byteStream[pos++] = connectFlags; pos = writeUint16 (this.keepAliveInterval, byteStream, pos); } // Output the messageIdentifier - if there is one if (this.messageIdentifier !== undefined) pos = writeUint16 (this.messageIdentifier, byteStream, pos); switch(this.type) { case MESSAGE_TYPE.CONNECT: pos = writeString(this.clientId, UTF8Length(this.clientId), byteStream, pos); if (this.willMessage !== undefined) { pos = writeString(this.willMessage.destinationName, UTF8Length(this.willMessage.destinationName), byteStream, pos); pos = writeUint16(willMessagePayloadBytes.byteLength, byteStream, pos); byteStream.set(willMessagePayloadBytes, pos); pos += willMessagePayloadBytes.byteLength; } if (this.userName !== undefined) pos = writeString(this.userName, UTF8Length(this.userName), byteStream, pos); if (this.password !== undefined) pos = writeString(this.password, UTF8Length(this.password), byteStream, pos); break; case MESSAGE_TYPE.PUBLISH: // PUBLISH has a text or binary payload, if text do not add a 2 byte length field, just the UTF characters. byteStream.set(payloadBytes, pos); break; // case MESSAGE_TYPE.PUBREC: // case MESSAGE_TYPE.PUBREL: // case MESSAGE_TYPE.PUBCOMP: // break; case MESSAGE_TYPE.SUBSCRIBE: // SUBSCRIBE has a list of topic strings and request QoS for (var i=0; i<this.topics.length; i++) { pos = writeString(this.topics[i], topicStrLength[i], byteStream, pos); byteStream[pos++] = this.requestedQos[i]; } break; case MESSAGE_TYPE.UNSUBSCRIBE: // UNSUBSCRIBE has a list of topic strings for (var i=0; i<this.topics.length; i++) pos = writeString(this.topics[i], topicStrLength[i], byteStream, pos); break; default: // Do nothing. } return buffer; }; function decodeMessage(input,pos) { var startingPos = pos; var first = input[pos]; var type = first >> 4; var messageInfo = first &= 0x0f; pos += 1; // Decode the remaining length (MBI format) var digit; var remLength = 0; var multiplier = 1; do { if (pos == input.length) { return [null,startingPos]; } digit = input[pos++]; remLength += ((digit & 0x7F) * multiplier); multiplier *= 128; } while ((digit & 0x80) !== 0); var endPos = pos+remLength; if (endPos > input.length) { return [null,startingPos]; } var wireMessage = new WireMessage(type); switch(type) { case MESSAGE_TYPE.CONNACK: var connectAcknowledgeFlags = input[pos++]; if (connectAcknowledgeFlags & 0x01) wireMessage.sessionPresent = true; wireMessage.returnCode = input[pos++]; break; case MESSAGE_TYPE.PUBLISH: var qos = (messageInfo >> 1) & 0x03; var len = readUint16(input, pos); pos += 2; var topicName = parseUTF8(input, pos, len); pos += len; // If QoS 1 or 2 there will be a messageIdentifier if (qos > 0) { wireMessage.messageIdentifier = readUint16(input, pos); pos += 2; } var message = new Message(input.subarray(pos, endPos)); if ((messageInfo & 0x01) == 0x01) message.retained = true; if ((messageInfo & 0x08) == 0x08) message.duplicate = true; message.qos = qos; message.destinationName = topicName; wireMessage.payloadMessage = message; break; case MESSAGE_TYPE.PUBACK: case MESSAGE_TYPE.PUBREC: case MESSAGE_TYPE.PUBREL: case MESSAGE_TYPE.PUBCOMP: case MESSAGE_TYPE.UNSUBACK: wireMessage.messageIdentifier = readUint16(input, pos); break; case MESSAGE_TYPE.SUBACK: wireMessage.messageIdentifier = readUint16(input, pos); pos += 2; wireMessage.returnCode = input.subarray(pos, endPos); break; default: break; } return [wireMessage,endPos]; } function writeUint16(input, buffer, offset) { buffer[offset++] = input >> 8; //MSB buffer[offset++] = input % 256; //LSB return offset; } function writeString(input, utf8Length, buffer, offset) { offset = writeUint16(utf8Length, buffer, offset); stringToUTF8(input, buffer, offset); return offset + utf8Length; } function readUint16(buffer, offset) { return 256*buffer[offset] + buffer[offset+1]; } /** * Encodes an MQTT Multi-Byte Integer * @private */ function encodeMBI(number) { var output = new Array(1); var numBytes = 0; do { var digit = number % 128; number = number >> 7; if (number > 0) { digit |= 0x80; } output[numBytes++] = digit; } while ( (number > 0) && (numBytes<4) ); return output; } /** * Takes a String and calculates its length in bytes when encoded in UTF8. * @private */ function UTF8Length(input) { var output = 0; for (var i = 0; i<input.length; i++) { var charCode = input.charCodeAt(i); if (charCode > 0x7FF) { // Surrogate pair means its a 4 byte character if (0xD800 <= charCode && charCode <= 0xDBFF) { i++; output++; } output +=3; } else if (charCode > 0x7F) output +=2; else output++; } return output; } /** * Takes a String and writes it into an array as UTF8 encoded bytes. * @private */ function stringToUTF8(input, output, start) { var pos = start; for (var i = 0; i<input.length; i++) { var charCode = input.charCodeAt(i); // Check for a surrogate pair. if (0xD800 <= charCode && charCode <= 0xDBFF) { var lowCharCode = input.charCodeAt(++i); if (isNaN(lowCharCode)) { throw new Error(format(ERROR.MALFORMED_UNICODE, [charCode, lowCharCode])); } charCode = ((charCode - 0xD800)<<10) + (lowCharCode - 0xDC00) + 0x10000; } if (charCode <= 0x7F) { output[pos++] = charCode; } else if (charCode <= 0x7FF) { output[pos++] = charCode>>6 & 0x1F | 0xC0; output[pos++] = charCode & 0x3F | 0x80; } else if (charCode <= 0xFFFF) { output[pos++] = charCode>>12 & 0x0F | 0xE0; output[pos++] = charCode>>6 & 0x3F | 0x80; output[pos++] = charCode & 0x3F | 0x80; } else { output[pos++] = charCode>>18 & 0x07 | 0xF0; output[pos++] = charCode>>12 & 0x3F | 0x80; output[pos++] = charCode>>6 & 0x3F | 0x80; output[pos++] = charCode & 0x3F | 0x80; } } return output; } function parseUTF8(input, offset, length) { var output = ""; var utf16; var pos = offset; while (pos < offset+length) { var byte1 = input[pos++]; if (byte1 < 128) utf16 = byte1; else { var byte2 = input[pos++]-128; if (byte2 < 0) throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16),""])); if (byte1 < 0xE0) // 2 byte character utf16 = 64*(byte1-0xC0) + byte2; else { var byte3 = input[pos++]-128; if (byte3 < 0) throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16)])); if (byte1 < 0xF0) // 3 byte character utf16 = 4096*(byte1-0xE0) + 64*byte2 + byte3; else { var byte4 = input[pos++]-128; if (byte4 < 0) throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(1