Angular using Server Sent Events in a factory

旧巷老猫 提交于 2019-12-20 06:37:21

问题


I am trying to setup message notifications in an Angular/Rails app.

When the user logs in, I want to open a SSE connection which will subscribe to a Redis stream and push an alert to the client when the user gets a new message.

I have my SSE setup and working, but cannot figure out a way to reliably close the SSE connection when a user logs out. I am trying to build a service to handle SSE opening and closing:

angular.module('messagesApp')
.factory('StreamHandler', function(CookieHandler, MessageStream){
  var StreamHandler = {

    set: function(){
      var user
      user = CookieHandler.get();
      MessageStream.get = function(){
        var source = new EventSource('/api/v1/messages/count?id='+user.id)
        return source
      }
    },

    get: function(){
      var source = MessageStream.get()
      source.onmessage = function(event) {
        //do something
      }
    },

    kill: function(){
      var source = MessageStream.get()
      source.close()
    }
  }

  return StreamHandler
})

I cannot figure out how to kill the stream that is opened in StreamHandler.set(). My attempt in the kill attribute does not work, possible because calling the getter actually creates a new stream?

I am open to other approaches: I just need a way to set and kill an EventSource stream on user login/logout.


回答1:


The problem was that I was putting the function that creates an EventSource in my get attribute, instead of putting the actual EventSource object. A few changes makes it work:

.factory('StreamHandler', function(CookieHandler, MessageStream){
  var StreamHandler = {

    set: function(){
      var user
      user = CookieHandler.get();
      var source = new EventSource('/api/v1/messages/count?id='+user.id)
      MessageStream.get = source
    },

    get: function(){
      var source = MessageStream.get
      source.onmessage = function(event) {
        console.log(event)
      }
      source.onerror = function(error) {
        source.close()
      }
    },

    kill: function(){
      var source = MessageStream.get
      source.close();

    }
  }

  return StreamHandler
})



回答2:


Look into Oboe.js - http://oboejs.com/examples

Using Oboe, I basically did (and I guess you don't need to inject $source and $http either in this case):

.factory('MyStreamingResource', ['$resource', '$http', 
    function($resource, $http) {
      return {
        stream: function(options, startFn, nodeFn, doneFn) {
          oboe('//url/' + 'maybeSomeOptions/?maybe=' + options.passedAbove)
           .start(startFn)
           .node(options.path, nodeFn)
           .done(doneFn);
        }
      };
    }
  ]);

Then simply injected it and called from some controllers with:

MyStreamingResource.stream({
        passedAbove: 'foo',
        path: 'items.*'
      },
      // start callback
      function(status, headers){
        // console.dir(headers);
        // this.abort(); // could be called from here too
      },
      // node callback (where your data is going to be streamed to)
      function(data){
        if(data !== null) {
          console.dir(data);
          //this.abort();
        }
      },
      // done (if you really want to wait)
      function(parsedJson){
        // ...
      });

Very similar to other services that you'd see with $http, but instead you have a few more callbacks to consider.

Oboe.js worked like a charm for me and the Golang go-json-rest package streaming a response (even with invalid JSON - which is quite common with streams since they aren't complete and won't have closing tags or will have extra commas, etc.). Just ensure the browser version of the script gets included on your page and you can just call it where ever. I spent a good while searching on how to do this with AngularJS, but there just didn't seem to be a straight forward facility for it. If it is at all possible.

Of course from here you could probably figure out how to make it work for your needs...Update something in the $scope, etc.



来源:https://stackoverflow.com/questions/25131691/angular-using-server-sent-events-in-a-factory

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!