chat.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. var RxDOM = require('rx-dom').DOM;
  2. var _ = require('lodash');
  3. var util = require('../util');
  4. function byVal(val) {
  5. return function(msg) {
  6. return msg === val;
  7. }
  8. }
  9. function byKind(kind) {
  10. return function(msg) {
  11. return msg.kind === kind;
  12. }
  13. }
  14. function makeid() {
  15. var text = "";
  16. var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  17. for( var i=0; i < 5; i++ )
  18. text += possible.charAt(Math.floor(Math.random() * possible.length));
  19. return text;
  20. }
  21. function connect(username$, room$, outgoing$) {
  22. var currRoom$ = room$.map(function(room) {
  23. return room || makeid();
  24. }).distinctUntilChanged().shareReplay(1);
  25. var details$ = username$.withLatestFrom(currRoom$, function(username, room) {
  26. return {
  27. username: username,
  28. room: room
  29. }
  30. });
  31. var nullSubject = Rx.Subject.create(Rx.Observer.create(), Rx.Observable.empty());
  32. var connection$ = details$
  33. .map(function(params) {
  34. if(params.username == null) {
  35. return { ws$: nullSubject, open$: nullSubject }
  36. }
  37. var url = jsRoutes.controllers.Application.chat(params.username, params.room).webSocketURL();
  38. var open = new Rx.Subject();
  39. return {
  40. ws$: RxDOM.fromWebSocket(url, 'chat', open.asObserver()),
  41. open$: open.map(function() { return 'connected' }).startWith('connecting')
  42. };
  43. }).share();
  44. var ws$ = connection$
  45. .flatMapLatest(function(conn) {
  46. return conn.ws$
  47. .map(function(ev) { return JSON.parse(ev.data) })
  48. .onErrorResumeNext(Rx.Observable.just({kind: 'disconnected'}));
  49. })
  50. .share();
  51. connection$.subscribe(function(conn) {
  52. outgoing$.subscribe(conn.ws$.asObserver());
  53. });
  54. var status$ = ws$
  55. .filter(byKind('disconnected'))
  56. .map(function() { return 'disconnected' })
  57. .merge(connection$.flatMapLatest(function(conn) { return conn.open$ }))
  58. .startWith('disconnected')
  59. .distinctUntilChanged()
  60. var error$ = ws$
  61. .map(function(msg) { return msg.error })
  62. .filter(_.isString)
  63. .merge(status$.filter(byVal('connecting')).map(function() { return '' }))
  64. .startWith('')
  65. return {
  66. ws$: ws$,
  67. details$: details$,
  68. status$: status$,
  69. error$: error$
  70. };
  71. }
  72. module.exports = {
  73. connect: connect
  74. }