jquery-simple-websocket

jquery simple websocket

Dette scriptet burde ikke installeres direkte. Det er et bibliotek for andre script å inkludere med det nye metadirektivet // @require https://update.greatest.deepsurf.us/scripts/407743/830687/jquery-simple-websocket.js

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. * jQuery Simple Websocket
  20. * https://github.com/jbloemendal/jquery-simple-websocket
  21. */
  22.  
  23. (function (factory) {
  24. if ('object' === typeof module && typeof 'object' === module.exports) {
  25. module.exports = factory(jQuery);
  26. } else {
  27. factory(jQuery);
  28. }
  29. }(function($) {
  30.  
  31. var SimpleWebSocket = function(opt) {
  32. if (this._isEmpty(opt, 'url')) {
  33. throw new Error('Missing argument, example usage: $.simpleWebSocket({ url: "ws://127.0.0.1:3000" }); ');
  34. }
  35. this._opt = opt;
  36.  
  37. this._ws = null;
  38. this._reConnectTries = 60;
  39. this._reConnectDeferred = null;
  40. this._dataType = this._prop(this._opt, 'dataType', 'json');
  41.  
  42. this._listeners = [];
  43.  
  44. var self = this;
  45. this._api = (function() {
  46. return {
  47. connect: function() {
  48. return $.extend(self._api, self._reConnect.apply(self, []));
  49. },
  50.  
  51. isConnected: function(callback) {
  52. if (callback) {
  53. callback.apply(this, [self._isConnected.apply(self, [])]);
  54. return self._api;
  55. } else {
  56. return self._isConnected.apply(self, []);
  57. }
  58. },
  59.  
  60. send: function(data) {
  61. return $.extend(self._api, self._send.apply(self, [data]));
  62. },
  63.  
  64. listen: function(listener) {
  65. return $.extend(self._api, self._listenReconnect.apply(self, [listener]));
  66. },
  67.  
  68. remove: function(listener) {
  69. self._remove.apply(self, [listener]);
  70. return self._api;
  71. },
  72.  
  73. removeAll: function() {
  74. self._removeAll.apply(self, []);
  75. return self._api;
  76. },
  77.  
  78. close: function() {
  79. self._close.apply(self, []);
  80. self._reset.apply(self, []);
  81. return self._api;
  82. }
  83. };
  84. })();
  85.  
  86. return this._api;
  87. };
  88.  
  89. SimpleWebSocket.prototype = {
  90.  
  91. _createWebSocket: function(opt) {
  92. var ws = null;
  93. if (opt.protocols) {
  94. if ('undefined' === typeof window.MozWebSocket) {
  95. if (window.WebSocket) {
  96. ws = new WebSocket(opt.url, opt.protocols);
  97. } else {
  98. throw new Error('Error, websocket could not be initialized.');
  99. }
  100. } else {
  101. ws = new MozWebSocket(opt.url, opt.protocols);
  102. }
  103. } else {
  104. if ('undefined' === typeof window.MozWebSocket) {
  105. if (window.WebSocket) {
  106. ws = new WebSocket(opt.url);
  107. } else {
  108. throw new Error('Error, websocket could not be initialized.');
  109. }
  110. } else {
  111. ws = new MozWebSocket(opt.url);
  112. }
  113. }
  114. return ws;
  115. },
  116.  
  117. _bindSocketEvents: function(ws, opt) {
  118. var self = this;
  119. $(ws).bind('open', opt.open)
  120. .bind('close', opt.close)
  121. .bind('message', function(event) {
  122. try {
  123. if ('function' === typeof opt.message) {
  124. if (self._dataType && 'json' === self._dataType.toLowerCase()) {
  125. var json = JSON.parse(event.originalEvent.data);
  126. opt.message.call(this, json);
  127. } else if (self._dataType && 'xml' === self._dataType.toLowerCase()) {
  128. var domParser = new DOMParser();
  129. var dom = domParser.parseFromString(event.originalEvent.data, 'text/xml');
  130. opt.message.call(this, dom);
  131. } else {
  132. opt.message.call(this, event.originalEvent.data);
  133. }
  134. }
  135. } catch (exception) {
  136. if ('function' === typeof opt.error) {
  137. opt.error.call(this, exception);
  138. }
  139. }
  140. }).bind('error', function(exception) {
  141. if ('function' === typeof opt.error) {
  142. opt.error.call(this, exception);
  143. }
  144. });
  145. },
  146.  
  147. _webSocket: function(opt) {
  148. var ws = this._createWebSocket(opt);
  149. this._bindSocketEvents(ws, opt);
  150.  
  151. return ws;
  152. },
  153.  
  154. _getSocketEventHandler: function(attempt) {
  155. var self = this;
  156. return {
  157. open: function(e) {
  158. var sock = this;
  159. if (attempt) {
  160. attempt.resolve(sock);
  161. }
  162. },
  163. close: function(e) {
  164. if (attempt) {
  165. attempt.rejectWith(e);
  166. }
  167. },
  168. message: function(message) {
  169. for (var i=0, len=self._listeners.length; i<len; i++) {
  170. try {
  171. self._listeners[i].deferred.notify.apply(self, [message]);
  172. } catch (error) {
  173. }
  174. }
  175. },
  176. error: function(e) {
  177. self._ws = null;
  178. for (var i=0, len=self._listeners.length; i<len; i++) {
  179. self._listeners[i].deferred.reject.apply(self, [e]);
  180. }
  181. if (attempt) {
  182. attempt.rejectWith.apply(self, [e]);
  183. }
  184. }
  185. };
  186. },
  187.  
  188. _connect: function() {
  189. var attempt = $.Deferred();
  190.  
  191. if (this._ws) {
  192. if (2 === this._ws.readyState) {
  193. // close previous socket
  194. this._ws.close();
  195. } else if (3 === this._ws.readyState) {
  196. // close previous socket
  197. this._ws.close();
  198. } else if (0 === this._ws.readyState) {
  199. return attempt.promise();
  200. } else if (1 === this._ws.readyState) {
  201. attempt.resolve(this._ws);
  202. return attempt.promise();
  203. }
  204. }
  205.  
  206. this._ws = this._webSocket($.extend(this._opt, this._getSocketEventHandler(attempt)));
  207.  
  208. return attempt.promise();
  209. },
  210.  
  211. _reset: function() {
  212. this._reConnectTries = this._prop(this._opt, 'attempts', 60); // default 10min
  213. this._reConnectDeferred = $.Deferred();
  214. },
  215.  
  216. _close: function() {
  217. if (this._ws) {
  218. this._ws.close();
  219. this._ws = null;
  220. }
  221. },
  222.  
  223. _isConnected: function() {
  224. if (null === this._ws) {
  225. return false;
  226. } else if (1 === this._ws.readyState) {
  227. return true;
  228. }
  229. return false;
  230. },
  231.  
  232. _reConnectTry: function() {
  233. var self = this;
  234. this._connect().done(function() {
  235. self._reConnectDeferred.resolve.apply(self, [self._ws]);
  236. }).fail(function(e) {
  237. self._reConnectTries--;
  238. if (self._reConnectTries > 0) {
  239. window.setTimeout(function() {
  240. self._reConnect.apply(self, []);
  241. }, self._prop.apply(self, [self._opt, 'timeout', 10000]));
  242. } else {
  243. self._reConnectDeferred.rejectWith.apply(self, [e]);
  244. }
  245. });
  246. },
  247.  
  248. _reConnect: function() {
  249. var self = this;
  250. if (null === this._reConnectDeferred) {
  251. this._reset();
  252. } else if ('resolved' === this._reConnectDeferred.state()) {
  253. this._reset();
  254. } else if ('rejected' === this._reConnectDeferred.state()) {
  255. this._reset();
  256. }
  257. if (this._ws && this._ws.readyState === 1) {
  258. this._reConnectDeferred.resolve(this._ws);
  259. } else {
  260. this._reConnectTry();
  261. }
  262.  
  263. return self._reConnectDeferred.promise.apply(self, []);
  264. },
  265.  
  266. _preparePayload: function(data) {
  267. var payload;
  268. if (this._opt.dataType && 'text' === this._opt.dataType.toLowerCase()) {
  269. payload = data;
  270. } else if (this._opt.dataType && 'xml' === this._opt.dataType.toLowerCase()) {
  271. payload = data;
  272. } else if (this._opt.dataType && 'json' === this._opt.dataType.toLowerCase()) {
  273. payload = JSON.stringify(data);
  274. } else {
  275. payload = JSON.stringify(data); // default
  276. }
  277. return payload;
  278. },
  279.  
  280. _send: function(data) {
  281. var self = this;
  282. var attempt = $.Deferred();
  283.  
  284. (function(json) {
  285. self._reConnect.apply(self, []).done(function(ws) {
  286. ws.send(json);
  287. attempt.resolve.apply(self, [self._api]);
  288. }).fail(function(e) {
  289. attempt.rejectWith.apply(self, [e]);
  290. });
  291. })(this._preparePayload(data));
  292.  
  293. return attempt.promise();
  294. },
  295.  
  296. _indexOfListener: function(listener) {
  297. for (var i=0, len=this._listeners.length; i<len; i++) {
  298. if (this._listeners[i].listener === listener) {
  299. return i;
  300. }
  301. }
  302. return -1;
  303. },
  304.  
  305. _isEmpty: function(obj, property) {
  306. if (typeof 'undefined' === obj) {
  307. return true;
  308. } else if (null === obj) {
  309. return true;
  310. } else if ('undefined' === typeof property) {
  311. return true;
  312. } else if (null === property) {
  313. return true;
  314. } else if ('' === property) {
  315. return true;
  316. } else if ('undefined' === typeof obj[property]) {
  317. return true;
  318. } else if (null === obj[property]) {
  319. return true;
  320. }
  321. return false;
  322. },
  323.  
  324. _prop: function(obj, property, defaultValue) {
  325. if (this._isEmpty(obj, property)) {
  326. return defaultValue;
  327. }
  328. return obj[property];
  329. },
  330.  
  331. _listen: function(listener) {
  332. var self = this;
  333. var dInternal = $.Deferred();
  334. self._reConnect.apply(self, []).done(function() {
  335. dInternal.progress(function() {
  336. listener.apply(this, arguments);
  337. });
  338. self._remove.apply(self, [listener]);
  339. self._listeners.push({ 'deferred': dInternal, 'listener': listener });
  340. }).fail(function(e) {
  341. dInternal.reject(e);
  342. });
  343. return dInternal.promise();
  344. },
  345.  
  346. _listenReconnect: function(listener) {
  347. var dExternal = $.Deferred();
  348.  
  349. var self = this;
  350. this._listen(listener)
  351. .fail(function() {
  352. dExternal.notify(arguments);
  353. self._listenReconnect.apply(self, [listener]);
  354. }).done(function() {
  355. dExternal.resolve();
  356. });
  357.  
  358. return dExternal.promise();
  359. },
  360.  
  361. _remove: function(listener) {
  362. var index = this._indexOfListener(listener);
  363. if (0 <= index) {
  364. this._listeners[index].deferred.resolve();
  365. this._listeners.splice(index, 1);
  366. }
  367. },
  368.  
  369. _removeAll: function() {
  370. for (var i=0, len=this._listeners.length; i<len; i++) {
  371. this._listeners[i].deferred.resolve();
  372. }
  373. this._listeners = [];
  374. }
  375. };
  376.  
  377. $.extend({
  378. simpleWebSocket: function(opt) {
  379. return new SimpleWebSocket(opt);
  380. }
  381. });
  382.  
  383. return $.simpleWebSocket;
  384. }));