/** * Module dependencies. */ var WS = require('./websocket') , util = require('../util') , debug = require('debug')('engine.io-client:flashsocket'); /** * Module exports. */ module.exports = FlashWS; /** * Obfuscated key for Blue Coat. */ var xobject = global[['Active'].concat('Object').join('X')]; /** * FlashWS constructor. * * @api public */ function FlashWS (options) { WS.call(this, options); this.flashPath = options.flashPath; this.policyPort = options.policyPort; }; /** * Inherits from WebSocket. */ util.inherits(FlashWS, WS); /** * Transport name. * * @api public */ FlashWS.prototype.name = 'flashsocket'; /** * Opens the transport. * * @api public */ FlashWS.prototype.doOpen = function () { if (!this.check()) { // let the probe timeout return; } // instrument websocketjs logging function log (type) { return function(){ var str = Array.prototype.join.call(arguments, ' '); debug('[websocketjs %s] %s', type, str); }; }; WEB_SOCKET_LOGGER = { log: log('debug'), error: log('error') }; WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true; WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true; if ('undefined' == typeof WEB_SOCKET_SWF_LOCATION) { WEB_SOCKET_SWF_LOCATION = this.flashPath + 'WebSocketMainInsecure.swf'; } // dependencies var deps = [this.flashPath + 'web_socket.js']; if ('undefined' == typeof swfobject) { deps.unshift(this.flashPath + 'swfobject.js'); } var self = this; load(deps, function () { self.ready(function () { WebSocket.__addTask(function () { WS.prototype.doOpen.call(self); }); }); }); }; /** * Override to prevent closing uninitialized flashsocket. * * @api private */ FlashWS.prototype.doClose = function () { if (!this.socket) return; var self = this; WebSocket.__addTask(function() { WS.prototype.doClose.call(self); }); }; /** * Writes to the Flash socket. * * @api private */ FlashWS.prototype.write = function() { var self = this, args = arguments; WebSocket.__addTask(function () { WS.prototype.write.apply(self, args); }); }; /** * Called upon dependencies are loaded. * * @api private */ FlashWS.prototype.ready = function (fn) { if (typeof WebSocket == 'undefined' || !('__initialize' in WebSocket) || !swfobject) { return; } if (swfobject.getFlashPlayerVersion().major < 10) { return; } function init () { // Only start downloading the swf file when the checked that this browser // actually supports it if (!FlashWS.loaded) { if (843 != self.policyPort) { WebSocket.loadFlashPolicyFile('xmlsocket://' + self.host + ':' + self.policyPort); } WebSocket.__initialize(); FlashWS.loaded = true; } fn.call(self); } var self = this; if (document.body) { return init(); } util.load(init); }; /** * Feature detection for flashsocket. * * @return {Boolean} whether this transport is available. * @api public */ FlashWS.prototype.check = function () { if ('undefined' != typeof process) { return false; } if (typeof WebSocket != 'undefined' && !('__initialize' in WebSocket)) { return false; } if (xobject) { var control = null; try { control = new xobject('ShockwaveFlash.ShockwaveFlash'); } catch (e) { } if (control) { return true; } } else { for (var i = 0, l = navigator.plugins.length; i < l; i++) { for (var j = 0, m = navigator.plugins[i].length; j < m; j++) { if (navigator.plugins[i][j].description == 'Shockwave Flash') { return true; } } } } return false; }; /** * Lazy loading of scripts. * Based on $script by Dustin Diaz - MIT */ var scripts = {}; /** * Injects a script. Keeps tracked of injected ones. * * @param {String} path * @param {Function} callback * @api private */ function create (path, fn) { if (scripts[path]) return fn(); var el = document.createElement('script'); var loaded = false; debug('loading "%s"', path); el.onload = el.onreadystatechange = function () { if (loaded || scripts[path]) return; var rs = el.readyState; if (!rs || 'loaded' == rs || 'complete' == rs) { debug('loaded "%s"', path); el.onload = el.onreadystatechange = null; loaded = true; scripts[path] = true; fn(); } }; el.async = 1; el.src = path; var head = document.getElementsByTagName('head')[0]; head.insertBefore(el, head.firstChild); }; /** * Loads scripts and fires a callback. * * @param {Array} paths * @param {Function} callback */ function load (arr, fn) { function process (i) { if (!arr[i]) return fn(); create(arr[i], function () { process(++i); }); }; process(0); };