PageRenderTime 31ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/libcommon/DTK1.7/dojox/socket.js

https://bitbucket.org/sasha.firsov/dojoplay2012
JavaScript | 222 lines | 131 code | 5 blank | 86 comment | 19 complexity | ef7d497fb5b90086720dbf41ddf27873 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, Apache-2.0, MIT
  1. define("dojox/socket", ["dojo", "dojo/Evented", "dojo/cookie", "dojo/_base/url"], function(dojo, Evented) {
  2. var WebSocket = window.WebSocket;
  3. function Socket(/*dojo.__XhrArgs*/ argsOrUrl){
  4. // summary:
  5. // Provides a simple socket connection using WebSocket, or alternate
  6. // communication mechanisms in legacy browsers for comet-style communication. This is based
  7. // on the WebSocket API and returns an object that implements the WebSocket interface:
  8. // http://dev.w3.org/html5/websockets/#websocket
  9. // description:
  10. // Provides socket connections. This can be used with virtually any Comet protocol.
  11. // argsOrUrl:
  12. // This uses the same arguments as the other I/O functions in Dojo, or a
  13. // URL to connect to. The URL should be a relative URL in order to properly
  14. // work with WebSockets (it can still be host relative, like //other-site.org/endpoint)
  15. // returns:
  16. // An object that implements the WebSocket API
  17. // example:
  18. // | dojo.require("dojox.socket");
  19. // | var socket = dojox.socket({"//comet-server/comet");
  20. // | // we could also add auto-reconnect support
  21. // | // now we can connect to standard HTML5 WebSocket-style events
  22. // | dojo.connect(socket, "onmessage", function(event){
  23. // | var message = event.data;
  24. // | // do something with the message
  25. // | });
  26. // | // send something
  27. // | socket.send("hi there");
  28. // | whenDone(function(){
  29. // | socket.close();
  30. // | });
  31. // You can also use the Reconnect module:
  32. // | dojo.require("dojox.socket");
  33. // | dojo.require("dojox.socket.Reconnect");
  34. // | var socket = dojox.socket({url:"/comet"});
  35. // | // add auto-reconnect support
  36. // | socket = dojox.socket.Reconnect(socket);
  37. if(typeof argsOrUrl == "string"){
  38. argsOrUrl = {url: argsOrUrl};
  39. }
  40. return WebSocket ? dojox.socket.WebSocket(argsOrUrl, true) : dojox.socket.LongPoll(argsOrUrl);
  41. };
  42. dojox.socket = Socket;
  43. Socket.WebSocket = function(args, fallback){
  44. // summary:
  45. // A wrapper for WebSocket, than handles standard args and relative URLs
  46. var ws = new WebSocket(new dojo._Url(document.baseURI.replace(/^http/i,'ws'), args.url));
  47. ws.on = function(type, listener){
  48. ws.addEventListener(type, listener, true);
  49. };
  50. var opened;
  51. dojo.connect(ws, "onopen", function(event){
  52. opened = true;
  53. });
  54. dojo.connect(ws, "onclose", function(event){
  55. if(opened){
  56. return;
  57. }
  58. if(fallback){
  59. Socket.replace(ws, dojox.socket.LongPoll(args), true);
  60. }
  61. });
  62. return ws;
  63. };
  64. Socket.replace = function(socket, newSocket, listenForOpen){
  65. // make the original socket a proxy for the new socket
  66. socket.send = dojo.hitch(newSocket, "send");
  67. socket.close = dojo.hitch(newSocket, "close");
  68. if(listenForOpen){
  69. proxyEvent("open");
  70. }
  71. // redirect the events as well
  72. dojo.forEach(["message", "close", "error"], proxyEvent);
  73. function proxyEvent(type){
  74. (newSocket.addEventListener || newSocket.on).call(newSocket, type, function(event){
  75. var newEvent = document.createEvent("MessageEvent");
  76. newEvent.initMessageEvent(event.type, false, false, event.data, event.origin, event.lastEventId, event.source);
  77. socket.dispatchEvent(newEvent);
  78. }, true);
  79. }
  80. };
  81. Socket.LongPoll = function(/*dojo.__XhrArgs*/ args){
  82. // summary:
  83. // Provides a simple long-poll based comet-style socket/connection to a server and returns an
  84. // object implementing the WebSocket interface:
  85. // http://dev.w3.org/html5/websockets/#websocket
  86. // args:
  87. // This uses the same arguments as the other I/O functions in Dojo, with this addition:
  88. // args.interval:
  89. // Indicates the amount of time (in milliseconds) after a response was received
  90. // before another request is made. By default, a request is made immediately
  91. // after getting a response. The interval can be increased to reduce load on the
  92. // server or to do simple time-based polling where the server always responds
  93. // immediately.
  94. // args.transport:
  95. // Provide an alternate transport like dojo.io.script.get
  96. // returns:
  97. // An object that implements the WebSocket API
  98. // example:
  99. // | dojo.require("dojox.socket.LongPoll");
  100. // | var socket = dojox.socket.LongPoll({url:"/comet"});
  101. // or:
  102. // | dojo.require("dojox.socket.LongPoll");
  103. // | dojox.socket.LongPoll.add();
  104. // | var socket = dojox.socket({url:"/comet"});
  105. var cancelled = false,
  106. first = true,
  107. timeoutId,
  108. connections = [];
  109. // create the socket object
  110. var socket = {
  111. send: function(data){
  112. // summary:
  113. // Send some data using XHR or provided transport
  114. var sendArgs = dojo.delegate(args);
  115. sendArgs.rawBody = data;
  116. clearTimeout(timeoutId);
  117. var deferred = first ? (first = false) || socket.firstRequest(sendArgs) :
  118. socket.transport(sendArgs);
  119. connections.push(deferred);
  120. deferred.then(function(response){
  121. // got a response
  122. socket.readyState = 1;
  123. // remove the current connection
  124. connections.splice(dojo.indexOf(connections, deferred), 1);
  125. // reconnect to listen for the next message if there are no active connections,
  126. // we queue it up in case one of the onmessage handlers has a message to send
  127. if(!connections.length){
  128. timeoutId = setTimeout(connect, args.interval);
  129. }
  130. if(response){
  131. // now send the message along to listeners
  132. fire("message", {data: response}, deferred);
  133. }
  134. }, function(error){
  135. connections.splice(dojo.indexOf(connections, deferred), 1);
  136. // an error occurred, fire the appropriate event listeners
  137. if(!cancelled){
  138. fire("error", {error:error}, deferred);
  139. if(!connections.length){
  140. socket.readyState = 3;
  141. fire("close", {wasClean:false}, deferred);
  142. }
  143. }
  144. });
  145. return deferred;
  146. },
  147. close: function(){
  148. // summary:
  149. // Close the connection
  150. socket.readyState = 2;
  151. cancelled = true;
  152. for(var i = 0; i < connections.length; i++){
  153. connections[i].cancel();
  154. }
  155. socket.readyState = 3;
  156. fire("close", {wasClean:true});
  157. },
  158. transport: args.transport || dojo.xhrPost,
  159. args: args,
  160. url: args.url,
  161. readyState: 0,
  162. CONNECTING: 0,
  163. OPEN: 1,
  164. CLOSING: 2,
  165. CLOSED: 3,
  166. dispatchEvent: function(event){
  167. fire(event.type, event);
  168. },
  169. on: Evented.prototype.on,
  170. firstRequest: function(args){
  171. // summary:
  172. // This allows for special handling for the first request. This is useful for
  173. // providing information to disambiguate between the first request and
  174. // subsequent long-poll requests so the server can properly setup a
  175. // connection on the first connection or reject a request for an expired
  176. // connection if the request is not expecting to be the first for a connection.
  177. // This method can be overriden. The default behavior is to include a Pragma
  178. // header with a value of "start-long-poll"
  179. var headers = (args.headers || (args.headers = {}));
  180. headers.Pragma = "start-long-poll";
  181. try{
  182. return this.transport(args);
  183. }finally{
  184. // cleanup the header so it is not used on subsequent requests
  185. delete headers.Pragma;
  186. }
  187. }
  188. };
  189. function connect(){
  190. if(socket.readyState == 0){
  191. // we fire the open event now because we really don't know when the "socket"
  192. // is truly open, and this gives us a to do a send() and get it included in the
  193. // HTTP request
  194. fire("open",{});
  195. }
  196. // make the long-poll connection, to wait for response from the server
  197. if(!connections.length){
  198. socket.send();
  199. }
  200. }
  201. function fire(type, object, deferred){
  202. if(socket["on" + type]){
  203. var event = document.createEvent("HTMLEvents");
  204. event.initEvent(type, false, false);
  205. dojo.mixin(event, object);
  206. event.ioArgs = deferred && deferred.ioArgs;
  207. socket["on" + type](event);
  208. }
  209. }
  210. // provide an alias for Dojo's connect method
  211. socket.connect = socket.on;
  212. // do the initial connection
  213. setTimeout(connect);
  214. return socket;
  215. };
  216. return Socket;
  217. });