bullet.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. function bullet(url) {
  2. var CONNECTING = 0;
  3. var OPEN = 1;
  4. var CLOSING = 2;
  5. var CLOSED = 3;
  6. var transports = {
  7. websocket: function() {
  8. var transport = null;
  9. if (window.WebSocket) { transport = window.WebSocket; }
  10. if (window.MozWebSocket) { transport = window.MozWebSocket; }
  11. if (transport) { return {'heart': true, 'transport': transport}; }
  12. return null;
  13. },
  14. xhrPolling: function() {
  15. var timeout;
  16. var xhr;
  17. nextPoll();
  18. var fake = {
  19. readyState: CONNECTING,
  20. receive: function(data) {
  21. if (fake.readyState == CONNECTING) { fake.readyState = OPEN; fake.onopen(fake); }
  22. if (data.length != 0) { fake.onmessage({'data': data }); }
  23. if (fake.readyState == OPEN) { nextPoll(); }
  24. },
  25. send: function(data) {
  26. if (this.readyState != CONNECTING && this.readyState != OPEN) return false;
  27. var fakeurl = url.replace('ws:', 'http:').replace('wss:', 'https:');
  28. var request = new XMLHttpRequest();
  29. request.open('POST',fakeurl,true);
  30. request.setRequestHeader('Content-Type',
  31. 'application/x-www-form-urlencoded; charset=utf-8');
  32. request.setRequestHeader('X-Socket-Transport','xhrPolling');
  33. request.onload = function() { fake.receive(request.response); }
  34. request.send(data);
  35. return true;
  36. },
  37. close: function(){
  38. this.readyState = CLOSED;
  39. xhr.abort();
  40. clearTimeout(timeout);
  41. fake.onclose();
  42. },
  43. onopen: function(){},
  44. onmessage: function(){},
  45. onerror: function(){},
  46. onclose: function(){}
  47. };
  48. function poll(pooling){
  49. var fakeurl = url.replace('ws:', 'http:').replace('wss:', 'https:');
  50. var request = new XMLHttpRequest();
  51. request.open('GET',fakeurl,true);
  52. request.setRequestHeader('Content-Type',
  53. 'application/x-www-form-urlencoded; charset=utf-8');
  54. request.setRequestHeader('X-Socket-Transport','xhrPolling');
  55. request.onload = function() { fake.receive(request.response); }
  56. request.onerror = function() { fake.onerror(); }
  57. request.send({});
  58. }
  59. function nextPoll() { timeout = setTimeout(function(){poll();}, 1000); }
  60. return {'heart': false, 'transport': function(){ return fake; fake.nextPoll(); }};
  61. }
  62. };
  63. var tn = 0;
  64. function next() {
  65. var c = 0;
  66. for (var f in transports) {
  67. if (tn == c) {
  68. var t = transports[f]();
  69. if (t) { var ret = new t.transport(url); ret.heart = t.heart; return ret; }
  70. tn++;
  71. }
  72. c++;
  73. }
  74. return false;
  75. }
  76. var stream = new function() {
  77. var isClosed = true;
  78. var readyState = CLOSED;
  79. var heartbeat;
  80. var delay = 80;
  81. var delayDefault = 80;
  82. var delayMax = 10000;
  83. var transport;
  84. function init() {
  85. isClosed = false;
  86. readyState = CONNECTING;
  87. transport = next();
  88. if (!transport) {
  89. delay = delayDefault;
  90. tn = 0;
  91. stream.ondisconnect();
  92. setTimeout(function(){init();}, delayMax);
  93. return false;
  94. }
  95. transport.onopen = function() {
  96. delay = delayDefault;
  97. if (transport.heart) {
  98. heartbeat = setInterval(function(){stream.onheartbeat();}, 4000);
  99. }
  100. if (readyState != OPEN) { readyState = OPEN; stream.onopen(); }
  101. };
  102. transport.onclose = function() {
  103. if (isClosed) { return; }
  104. transport = null;
  105. clearInterval(heartbeat);
  106. if (readyState == CLOSING){
  107. readyState = CLOSED;
  108. stream.onclose();
  109. } else {
  110. if (readyState == CONNECTING) tn++;
  111. delay *= 2;
  112. if (delay > delayMax) { delay = delayMax; }
  113. isClosed = true;
  114. setTimeout(function() { init(); }, delay);
  115. }
  116. };
  117. transport.onerror = transport.onclose;
  118. transport.onmessage = function(e){
  119. stream.onmessage(e);
  120. };
  121. }
  122. init();
  123. this.onopen = function(){}; this.oninit = function(){};
  124. this.onmessage = function(){}; this.ondisconnect = function(){ initialized = false; };
  125. this.onclose = function(){}; this.onheartbeat = function(){ return this.send('PING'); };
  126. this.setURL = function(newURL) { url = newURL; };
  127. this.send = function(data){
  128. if (transport) return transport.send(data); else return false;
  129. };
  130. this.close = function(){
  131. readyState = CLOSING;
  132. if (transport) transport.close();
  133. };
  134. };
  135. return stream;
  136. }