Skip to content
Extraits de code Groupes Projets
web_socket.js 8,84 ko
Newer Older
  • Learn to ignore specific revisions
  • maxwell's avatar
    maxwell a validé
    // Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
    // Lincense: New BSD Lincense
    // Reference: http://dev.w3.org/html5/websockets/
    // Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
    
    (function() {
      
      if (window.WebSocket) return;
    
      var console = window.console;
      if (!console) console = {log: function(){ }, error: function(){ }};
    
      function hasFlash() {
        if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']) {
          return !!navigator.plugins['Shockwave Flash'].description;
        }
        if ('ActiveXObject' in window) {
          try {
            return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
          } catch (e) {}
        }
        return false;
      }
      
      if (!hasFlash()) {
        console.error("Flash Player is not installed.");
        return;
      }
    
      WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
        var self = this;
        self.readyState = WebSocket.CONNECTING;
        self.bufferedAmount = 0;
        WebSocket.__addTask(function() {
          self.__flash =
            WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
    
          self.__flash.addEventListener("open", function(fe) {
            try {
              if (self.onopen) self.onopen();
            } catch (e) {
              console.error(e.toString());
            }
          });
    
          self.__flash.addEventListener("close", function(fe) {
            try {
              if (self.onclose) self.onclose();
            } catch (e) {
              console.error(e.toString());
            }
          });
    
          self.__flash.addEventListener("message", function(fe) {
            var data = decodeURIComponent(fe.getData());
            try {
              if (self.onmessage) {
                var e;
                if (window.MessageEvent) {
                  e = document.createEvent("MessageEvent");
                  e.initMessageEvent("message", false, false, data, null, null, window);
                } else { // IE
                  e = {data: data};
                }
                self.onmessage(e);
              }
            } catch (e) {
              console.error(e.toString());
            }
          });
    
          self.__flash.addEventListener("stateChange", function(fe) {
            try {
              self.readyState = fe.getReadyState();
              self.bufferedAmount = fe.getBufferedAmount();
            } catch (e) {
              console.error(e.toString());
            }
          });
    
          //console.log("[WebSocket] Flash object is ready");
        });
      }
    
      WebSocket.prototype.send = function(data) {
        if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
          throw "INVALID_STATE_ERR: Web Socket connection has not been established";
        }
        var result = this.__flash.send(data);
        if (result < 0) { // success
          return true;
        } else {
          this.bufferedAmount = result;
          return false;
        }
      };
    
      WebSocket.prototype.close = function() {
        if (!this.__flash) return;
        if (this.readyState != WebSocket.OPEN) return;
        this.__flash.close();
        // Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
        // which causes weird error:
        // > You are trying to call recursively into the Flash Player which is not allowed.
        this.readyState = WebSocket.CLOSED;
        if (this.onclose) this.onclose();
      };
    
      /**
       * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
       *
       * @param {string} type
       * @param {function} listener
       * @param {boolean} useCapture !NB Not implemented yet
       * @return void
       */
      WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
        if (!('__events' in this)) {
          this.__events = {};
        }
        if (!(type in this.__events)) {
          this.__events[type] = [];
          if ('function' == typeof this['on' + type]) {
            this.__events[type].defaultHandler = this['on' + type];
            this['on' + type] = WebSocket_FireEvent(this, type);
          }
        }
        this.__events[type].push(listener);
      };
    
      /**
       * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
       *
       * @param {string} type
       * @param {function} listener
       * @param {boolean} useCapture NB! Not implemented yet
       * @return void
       */
      WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
        if (!('__events' in this)) {
          this.__events = {};
        }
        if (!(type in this.__events)) return;
        for (var i = this.__events.length; i > -1; --i) {
          if (listener === this.__events[type][i]) {
            this.__events[type].splice(i, 1);
            break;
          }
        }
      };
    
      /**
       * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
       *
       * @param {WebSocketEvent} event
       * @return void
       */
      WebSocket.prototype.dispatchEvent = function(event) {
        if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
        if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
    
        for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) {
          this.__events[event.type][i](event);
          if (event.cancelBubble) break;
        }
    
        if (false !== event.returnValue &&
            'function' == typeof this.__events[event.type].defaultHandler)
        {
          this.__events[event.type].defaultHandler(event);
        }
      };
    
      /**
       *
       * @param {object} object
       * @param {string} type
       */
      function WebSocket_FireEvent(object, type) {
        return function(data) {
          var event = new WebSocketEvent();
          event.initEvent(type, true, true);
          event.target = event.currentTarget = object;
          for (var key in data) {
            event[key] = data[key];
          }
          object.dispatchEvent(event, arguments);
        };
      }
    
      /**
       * Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
       *
       * @class
       * @constructor
       */
      function WebSocketEvent(){}
    
      /**
       *
       * @type boolean
       */
      WebSocketEvent.prototype.cancelable = true;
    
      /**
       *
       * @type boolean
       */
      WebSocketEvent.prototype.cancelBubble = false;
    
      /**
       *
       * @return void
       */
      WebSocketEvent.prototype.preventDefault = function() {
        if (this.cancelable) {
          this.returnValue = false;
        }
      };
    
      /**
       *
       * @return void
       */
      WebSocketEvent.prototype.stopPropagation = function() {
        this.cancelBubble = true;
      };
    
      /**
       *
       * @param {string} eventTypeArg
       * @param {boolean} canBubbleArg
       * @param {boolean} cancelableArg
       * @return void
       */
      WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {
        this.type = eventTypeArg;
        this.cancelable = cancelableArg;
        this.timeStamp = new Date();
      };
    
    
      WebSocket.CONNECTING = 0;
      WebSocket.OPEN = 1;
      WebSocket.CLOSED = 2;
    
      WebSocket.__tasks = [];
    
      WebSocket.__initialize = function() {
        if (!WebSocket.__swfLocation) {
          //console.error("[WebSocket] set WebSocket.__swfLocation to location of WebSocketMain.swf");
          //return;
          WebSocket.__swfLocation = "js/WebSocketMain.swf";
        }
        var container = document.createElement("div");
        container.id = "webSocketContainer";
        // Puts the Flash out of the window. Note that we cannot use display: none or visibility: hidden
        // here because it prevents Flash from loading at least in IE.
        container.style.position = "absolute";
        container.style.left = "-100px";
        container.style.top = "-100px";
        var holder = document.createElement("div");
        holder.id = "webSocketFlash";
        container.appendChild(holder);
        document.body.appendChild(container);
        swfobject.embedSWF(
          WebSocket.__swfLocation, "webSocketFlash", "8", "8", "9.0.0",
          null, {bridgeName: "webSocket"}, null, null,
          function(e) {
            if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed");
          }
        );
        FABridge.addInitializationCallback("webSocket", function() {
          try {
            //console.log("[WebSocket] FABridge initializad");
            WebSocket.__flash = FABridge.webSocket.root();
            WebSocket.__flash.setCallerUrl(location.href);
            for (var i = 0; i < WebSocket.__tasks.length; ++i) {
              WebSocket.__tasks[i]();
            }
            WebSocket.__tasks = [];
          } catch (e) {
            console.error("[WebSocket] " + e.toString());
          }
        });
      };
    
      WebSocket.__addTask = function(task) {
        if (WebSocket.__flash) {
          task();
        } else {
          WebSocket.__tasks.push(task);
        }
      }
    
      // called from Flash
      function webSocketLog(message) {
        console.log(decodeURIComponent(message));
      }
    
      // called from Flash
      function webSocketError(message) {
        console.error(decodeURIComponent(message));
      }
    
      if (window.addEventListener) {
        window.addEventListener("load", WebSocket.__initialize, false);
      } else {
        window.attachEvent("onload", WebSocket.__initialize);
      }
      
    })();