diff options
Diffstat (limited to 'js/dojo/dojox/socket.js')
| -rw-r--r-- | js/dojo/dojox/socket.js | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/js/dojo/dojox/socket.js b/js/dojo/dojox/socket.js new file mode 100644 index 0000000..75bb9e2 --- /dev/null +++ b/js/dojo/dojox/socket.js @@ -0,0 +1,223 @@ +//>>built +define("dojox/socket", ["dojo", "dojo/Evented", "dojo/cookie", "dojo/_base/url"], function(dojo, Evented) { + +var WebSocket = window.WebSocket; + +function Socket(/*dojo.__XhrArgs*/ argsOrUrl){ + // summary: + // Provides a simple socket connection using WebSocket, or alternate + // communication mechanisms in legacy browsers for comet-style communication. This is based + // on the WebSocket API and returns an object that implements the WebSocket interface: + // http://dev.w3.org/html5/websockets/#websocket + // description: + // Provides socket connections. This can be used with virtually any Comet protocol. + // argsOrUrl: + // This uses the same arguments as the other I/O functions in Dojo, or a + // URL to connect to. The URL should be a relative URL in order to properly + // work with WebSockets (it can still be host relative, like //other-site.org/endpoint) + // returns: + // An object that implements the WebSocket API + // example: + // | dojo.require("dojox.socket"); + // | var socket = dojox.socket({"//comet-server/comet"); + // | // we could also add auto-reconnect support + // | // now we can connect to standard HTML5 WebSocket-style events + // | dojo.connect(socket, "onmessage", function(event){ + // | var message = event.data; + // | // do something with the message + // | }); + // | // send something + // | socket.send("hi there"); + // | whenDone(function(){ + // | socket.close(); + // | }); + // You can also use the Reconnect module: + // | dojo.require("dojox.socket"); + // | dojo.require("dojox.socket.Reconnect"); + // | var socket = dojox.socket({url:"/comet"}); + // | // add auto-reconnect support + // | socket = dojox.socket.Reconnect(socket); + if(typeof argsOrUrl == "string"){ + argsOrUrl = {url: argsOrUrl}; + } + return WebSocket ? dojox.socket.WebSocket(argsOrUrl, true) : dojox.socket.LongPoll(argsOrUrl); +}; +dojox.socket = Socket; + +Socket.WebSocket = function(args, fallback){ + // summary: + // A wrapper for WebSocket, than handles standard args and relative URLs + var ws = new WebSocket(new dojo._Url(document.baseURI.replace(/^http/i,'ws'), args.url)); + ws.on = function(type, listener){ + ws.addEventListener(type, listener, true); + }; + var opened; + dojo.connect(ws, "onopen", function(event){ + opened = true; + }); + dojo.connect(ws, "onclose", function(event){ + if(opened){ + return; + } + if(fallback){ + Socket.replace(ws, dojox.socket.LongPoll(args), true); + } + }); + return ws; +}; +Socket.replace = function(socket, newSocket, listenForOpen){ + // make the original socket a proxy for the new socket + socket.send = dojo.hitch(newSocket, "send"); + socket.close = dojo.hitch(newSocket, "close"); + if(listenForOpen){ + proxyEvent("open"); + } + // redirect the events as well + dojo.forEach(["message", "close", "error"], proxyEvent); + function proxyEvent(type){ + (newSocket.addEventListener || newSocket.on).call(newSocket, type, function(event){ + var newEvent = document.createEvent("MessageEvent"); + newEvent.initMessageEvent(event.type, false, false, event.data, event.origin, event.lastEventId, event.source); + socket.dispatchEvent(newEvent); + }, true); + } +}; +Socket.LongPoll = function(/*dojo.__XhrArgs*/ args){ + // summary: + // Provides a simple long-poll based comet-style socket/connection to a server and returns an + // object implementing the WebSocket interface: + // http://dev.w3.org/html5/websockets/#websocket + // args: + // This uses the same arguments as the other I/O functions in Dojo, with this addition: + // args.interval: + // Indicates the amount of time (in milliseconds) after a response was received + // before another request is made. By default, a request is made immediately + // after getting a response. The interval can be increased to reduce load on the + // server or to do simple time-based polling where the server always responds + // immediately. + // args.transport: + // Provide an alternate transport like dojo.io.script.get + // returns: + // An object that implements the WebSocket API + // example: + // | dojo.require("dojox.socket.LongPoll"); + // | var socket = dojox.socket.LongPoll({url:"/comet"}); + // or: + // | dojo.require("dojox.socket.LongPoll"); + // | dojox.socket.LongPoll.add(); + // | var socket = dojox.socket({url:"/comet"}); + +var cancelled = false, + first = true, + timeoutId, + connections = []; + + // create the socket object + var socket = { + send: function(data){ + // summary: + // Send some data using XHR or provided transport + var sendArgs = dojo.delegate(args); + sendArgs.rawBody = data; + clearTimeout(timeoutId); + var deferred = first ? (first = false) || socket.firstRequest(sendArgs) : + socket.transport(sendArgs); + connections.push(deferred); + deferred.then(function(response){ + // got a response + socket.readyState = 1; + // remove the current connection + connections.splice(dojo.indexOf(connections, deferred), 1); + // reconnect to listen for the next message if there are no active connections, + // we queue it up in case one of the onmessage handlers has a message to send + if(!connections.length){ + timeoutId = setTimeout(connect, args.interval); + } + if(response){ + // now send the message along to listeners + fire("message", {data: response}, deferred); + } + }, function(error){ + connections.splice(dojo.indexOf(connections, deferred), 1); + // an error occurred, fire the appropriate event listeners + if(!cancelled){ + fire("error", {error:error}, deferred); + if(!connections.length){ + socket.readyState = 3; + fire("close", {wasClean:false}, deferred); + } + } + }); + return deferred; + }, + close: function(){ + // summary: + // Close the connection + socket.readyState = 2; + cancelled = true; + for(var i = 0; i < connections.length; i++){ + connections[i].cancel(); + } + socket.readyState = 3; + fire("close", {wasClean:true}); + }, + transport: args.transport || dojo.xhrPost, + args: args, + url: args.url, + readyState: 0, + CONNECTING: 0, + OPEN: 1, + CLOSING: 2, + CLOSED: 3, + dispatchEvent: function(event){ + fire(event.type, event); + }, + on: Evented.prototype.on, + firstRequest: function(args){ + // summary: + // This allows for special handling for the first request. This is useful for + // providing information to disambiguate between the first request and + // subsequent long-poll requests so the server can properly setup a + // connection on the first connection or reject a request for an expired + // connection if the request is not expecting to be the first for a connection. + // This method can be overriden. The default behavior is to include a Pragma + // header with a value of "start-long-poll" + var headers = (args.headers || (args.headers = {})); + headers.Pragma = "start-long-poll"; + try{ + return this.transport(args); + }finally{ + // cleanup the header so it is not used on subsequent requests + delete headers.Pragma; + } + } + }; + function connect(){ + if(socket.readyState == 0){ + // we fire the open event now because we really don't know when the "socket" + // is truly open, and this gives us a to do a send() and get it included in the + // HTTP request + fire("open",{}); + } + // make the long-poll connection, to wait for response from the server + if(!connections.length){ + socket.send(); + } + } + function fire(type, object, deferred){ + if(socket["on" + type]){ + var event = document.createEvent("HTMLEvents"); + event.initEvent(type, false, false); + dojo.mixin(event, object); + event.ioArgs = deferred && deferred.ioArgs; + socket["on" + type](event); + } + } + // provide an alias for Dojo's connect method + socket.connect = socket.on; + // do the initial connection + setTimeout(connect); + return socket; +}; +return Socket; +});
\ No newline at end of file |
