WebSocketSubject.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. "use strict";
  2. var __extends = (this && this.__extends) || function (d, b) {
  3. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  4. function __() { this.constructor = d; }
  5. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  6. };
  7. var Subject_1 = require('../../Subject');
  8. var Subscriber_1 = require('../../Subscriber');
  9. var Observable_1 = require('../../Observable');
  10. var Subscription_1 = require('../../Subscription');
  11. var root_1 = require('../../util/root');
  12. var ReplaySubject_1 = require('../../ReplaySubject');
  13. var tryCatch_1 = require('../../util/tryCatch');
  14. var errorObject_1 = require('../../util/errorObject');
  15. var assign_1 = require('../../util/assign');
  16. /**
  17. * We need this JSDoc comment for affecting ESDoc.
  18. * @extends {Ignored}
  19. * @hide true
  20. */
  21. var WebSocketSubject = (function (_super) {
  22. __extends(WebSocketSubject, _super);
  23. function WebSocketSubject(urlConfigOrSource, destination) {
  24. if (urlConfigOrSource instanceof Observable_1.Observable) {
  25. _super.call(this, destination, urlConfigOrSource);
  26. }
  27. else {
  28. _super.call(this);
  29. this.WebSocketCtor = root_1.root.WebSocket;
  30. this._output = new Subject_1.Subject();
  31. if (typeof urlConfigOrSource === 'string') {
  32. this.url = urlConfigOrSource;
  33. }
  34. else {
  35. // WARNING: config object could override important members here.
  36. assign_1.assign(this, urlConfigOrSource);
  37. }
  38. if (!this.WebSocketCtor) {
  39. throw new Error('no WebSocket constructor can be found');
  40. }
  41. this.destination = new ReplaySubject_1.ReplaySubject();
  42. }
  43. }
  44. WebSocketSubject.prototype.resultSelector = function (e) {
  45. return JSON.parse(e.data);
  46. };
  47. /**
  48. * Wrapper around the w3c-compatible WebSocket object provided by the browser.
  49. *
  50. * @example <caption>Wraps browser WebSocket</caption>
  51. *
  52. * let socket$ = Observable.webSocket('ws://localhost:8081');
  53. *
  54. * socket$.subscribe(
  55. * (msg) => console.log('message received: ' + msg),
  56. * (err) => console.log(err),
  57. * () => console.log('complete')
  58. * );
  59. *
  60. * socket$.next(JSON.stringify({ op: 'hello' }));
  61. *
  62. * @example <caption>Wraps WebSocket from nodejs-websocket (using node.js)</caption>
  63. *
  64. * import { w3cwebsocket } from 'websocket';
  65. *
  66. * let socket$ = Observable.webSocket({
  67. * url: 'ws://localhost:8081',
  68. * WebSocketCtor: w3cwebsocket
  69. * });
  70. *
  71. * socket$.subscribe(
  72. * (msg) => console.log('message received: ' + msg),
  73. * (err) => console.log(err),
  74. * () => console.log('complete')
  75. * );
  76. *
  77. * socket$.next(JSON.stringify({ op: 'hello' }));
  78. *
  79. * @param {string | WebSocketSubjectConfig} urlConfigOrSource the source of the websocket as an url or a structure defining the websocket object
  80. * @return {WebSocketSubject}
  81. * @static true
  82. * @name webSocket
  83. * @owner Observable
  84. */
  85. WebSocketSubject.create = function (urlConfigOrSource) {
  86. return new WebSocketSubject(urlConfigOrSource);
  87. };
  88. WebSocketSubject.prototype.lift = function (operator) {
  89. var sock = new WebSocketSubject(this, this.destination);
  90. sock.operator = operator;
  91. return sock;
  92. };
  93. WebSocketSubject.prototype._resetState = function () {
  94. this.socket = null;
  95. if (!this.source) {
  96. this.destination = new ReplaySubject_1.ReplaySubject();
  97. }
  98. this._output = new Subject_1.Subject();
  99. };
  100. // TODO: factor this out to be a proper Operator/Subscriber implementation and eliminate closures
  101. WebSocketSubject.prototype.multiplex = function (subMsg, unsubMsg, messageFilter) {
  102. var self = this;
  103. return new Observable_1.Observable(function (observer) {
  104. var result = tryCatch_1.tryCatch(subMsg)();
  105. if (result === errorObject_1.errorObject) {
  106. observer.error(errorObject_1.errorObject.e);
  107. }
  108. else {
  109. self.next(result);
  110. }
  111. var subscription = self.subscribe(function (x) {
  112. var result = tryCatch_1.tryCatch(messageFilter)(x);
  113. if (result === errorObject_1.errorObject) {
  114. observer.error(errorObject_1.errorObject.e);
  115. }
  116. else if (result) {
  117. observer.next(x);
  118. }
  119. }, function (err) { return observer.error(err); }, function () { return observer.complete(); });
  120. return function () {
  121. var result = tryCatch_1.tryCatch(unsubMsg)();
  122. if (result === errorObject_1.errorObject) {
  123. observer.error(errorObject_1.errorObject.e);
  124. }
  125. else {
  126. self.next(result);
  127. }
  128. subscription.unsubscribe();
  129. };
  130. });
  131. };
  132. WebSocketSubject.prototype._connectSocket = function () {
  133. var _this = this;
  134. var WebSocketCtor = this.WebSocketCtor;
  135. var observer = this._output;
  136. var socket = null;
  137. try {
  138. socket = this.protocol ?
  139. new WebSocketCtor(this.url, this.protocol) :
  140. new WebSocketCtor(this.url);
  141. this.socket = socket;
  142. if (this.binaryType) {
  143. this.socket.binaryType = this.binaryType;
  144. }
  145. }
  146. catch (e) {
  147. observer.error(e);
  148. return;
  149. }
  150. var subscription = new Subscription_1.Subscription(function () {
  151. _this.socket = null;
  152. if (socket && socket.readyState === 1) {
  153. socket.close();
  154. }
  155. });
  156. socket.onopen = function (e) {
  157. var openObserver = _this.openObserver;
  158. if (openObserver) {
  159. openObserver.next(e);
  160. }
  161. var queue = _this.destination;
  162. _this.destination = Subscriber_1.Subscriber.create(function (x) { return socket.readyState === 1 && socket.send(x); }, function (e) {
  163. var closingObserver = _this.closingObserver;
  164. if (closingObserver) {
  165. closingObserver.next(undefined);
  166. }
  167. if (e && e.code) {
  168. socket.close(e.code, e.reason);
  169. }
  170. else {
  171. observer.error(new TypeError('WebSocketSubject.error must be called with an object with an error code, ' +
  172. 'and an optional reason: { code: number, reason: string }'));
  173. }
  174. _this._resetState();
  175. }, function () {
  176. var closingObserver = _this.closingObserver;
  177. if (closingObserver) {
  178. closingObserver.next(undefined);
  179. }
  180. socket.close();
  181. _this._resetState();
  182. });
  183. if (queue && queue instanceof ReplaySubject_1.ReplaySubject) {
  184. subscription.add(queue.subscribe(_this.destination));
  185. }
  186. };
  187. socket.onerror = function (e) {
  188. _this._resetState();
  189. observer.error(e);
  190. };
  191. socket.onclose = function (e) {
  192. _this._resetState();
  193. var closeObserver = _this.closeObserver;
  194. if (closeObserver) {
  195. closeObserver.next(e);
  196. }
  197. if (e.wasClean) {
  198. observer.complete();
  199. }
  200. else {
  201. observer.error(e);
  202. }
  203. };
  204. socket.onmessage = function (e) {
  205. var result = tryCatch_1.tryCatch(_this.resultSelector)(e);
  206. if (result === errorObject_1.errorObject) {
  207. observer.error(errorObject_1.errorObject.e);
  208. }
  209. else {
  210. observer.next(result);
  211. }
  212. };
  213. };
  214. /** @deprecated internal use only */ WebSocketSubject.prototype._subscribe = function (subscriber) {
  215. var _this = this;
  216. var source = this.source;
  217. if (source) {
  218. return source.subscribe(subscriber);
  219. }
  220. if (!this.socket) {
  221. this._connectSocket();
  222. }
  223. var subscription = new Subscription_1.Subscription();
  224. subscription.add(this._output.subscribe(subscriber));
  225. subscription.add(function () {
  226. var socket = _this.socket;
  227. if (_this._output.observers.length === 0) {
  228. if (socket && socket.readyState === 1) {
  229. socket.close();
  230. }
  231. _this._resetState();
  232. }
  233. });
  234. return subscription;
  235. };
  236. WebSocketSubject.prototype.unsubscribe = function () {
  237. var _a = this, source = _a.source, socket = _a.socket;
  238. if (socket && socket.readyState === 1) {
  239. socket.close();
  240. this._resetState();
  241. }
  242. _super.prototype.unsubscribe.call(this);
  243. if (!source) {
  244. this.destination = new ReplaySubject_1.ReplaySubject();
  245. }
  246. };
  247. return WebSocketSubject;
  248. }(Subject_1.AnonymousSubject));
  249. exports.WebSocketSubject = WebSocketSubject;
  250. //# sourceMappingURL=WebSocketSubject.js.map