Loopback + Socket.io custom notifications

2019-07-30 16:43发布

I have models: Team, Project, Task. Tasks in projects, projects in teams, teams consists users.

I'm creating my app like in example - https://docs.strongloop.com/display/MSG/Building+a+real-time+app+using+socket.io+and+AngularJS

In my example:

server/server.js

...

app.use(loopback.token({ model: app.models.accessToken }));

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
  if (err) throw err;

  // start the server if `$ node server.js`
  if (require.main === module) {
    //Comment this app.start line and add following lines
    //app.start();
    app.io = require('socket.io')(app.start());
    require('socketio-auth')(app.io, {
      authenticate: function (socket, value, callback) {

        var AccessToken = app.models.AccessToken;
        //get credentials sent by the client
        var token = AccessToken.find({
          where:{
            and: [{ userId: value.userId }, { id: value.id }]
          }
        }, function(err, tokenDetail){
          if (err) throw err;
          if(tokenDetail.length){
            callback(null, true);
          } else {
            callback(null, false);
          }
        }); //find function..
      } //authenticate function..
    });

    app.io.on('connection', function(socket){
      console.log('a user connected');
      socket.on('disconnect', function(){
        console.log('user disconnected');
      });
    });
  }
});

server/pubsub.js

'use strict';
var loopback = require('loopback');
//Writing pubsub module for socket.io
module.exports = {
  //Publishing a event..
  publish: function(socket, options ){

    var ctx = loopback.getCurrentContext();


    if(options){
      var collectionName = options.collectionName;
      var method         = options.method;
      var data           = options.data;
      var modelId        = options.modelId;
      if(method === 'POST'){
        //console.log('Posting new data');
        var name = '/' + collectionName + '/' + method;
        socket.emit(name, data);
      }
      else{
        var name = '/' + collectionName + '/' + modelId + '/' + method;
        socket.emit(name, data);
      }
    }else{
      throw 'Error: Option must be an object type';
    }
  }, //End Publish..

  isEmpty:function (obj) {
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    // null and undefined are "empty"
    if (obj == null) return true;
    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;
    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
      if (this.hasOwnProperty.call(obj, key)) return false;
    }
    return true;
  } //isEmpty function..
}

common/models/task.js

var pubsub = require('../../server/pubsub.js');
var loopback = require('loopback');
module.exports = function(Task) {
  //Task after save..
  Task.observe('after save', function (ctx, next) {
    console.log('Task after save');

    var socket = Task.app.io;
    if(ctx.isNewInstance){
      //Now publishing the data..
      pubsub.publish(socket, {
        collectionName : 'Task',
        data: ctx.instance,
        method: 'POST'
      });
    }else{
      //Now publishing the data..
      pubsub.publish(socket, {
        collectionName : 'Task',
        data: ctx.instance,
        modelId: ctx.instance.id,
        method: 'PUT'
      });
    }
    //Calling the next middleware..
    next();
  }); //after save..
  //TaskDetail before delete..
  Task.observe("before delete", function(ctx, next){
    var socket = Task.app.io;
    //Now publishing the data..
    pubsub.publish(socket, {
      collectionName : 'Task',
      data: ctx.instance.id,
      modelId: ctx.instance.id,
      method: 'DELETE'
    });
    //move to next middleware..
    next();
  }); //before delete..
}; //Module exports..

I want deliver task, project, team changes via sockets. Some projects or tasks can be private. It means that only invited to project/task members can see them. Where can I put my logic witch determines who will receive notification? In general, all team members have to receive changes in tasks, projects and teams, but in private tasks and projects is another logic.

What is the best way to do it? Create namespace or room like team/team_id for common case and send individual notification in private case. Or is it better to create namespace or room for each connected user and on task change check who have to receive changes and send to them?

In my example, when I save a task all users receives this task via sockets...

Thanks.

0条回答
登录 后发表回答