如何仅向Meteor流中的一个客户端发送数据

时间:2014-04-18 06:54:15

标签: meteor

我正在使用Meteor流构建实时游戏。我只需要更新一个客户端 - 从服务器发送一个房间ID。用户未登录,因此Meteor.userId()为null,因此我无法使用此:http://arunoda.github.io/meteor-streams/communication-patterns.html#streaming_private_page

只有一个URL(主页)可以发生所有事情。所以我不使用任何URL参数的空间。一切都在服务器上。

我曾尝试使用Meteor.uuid()而不是Meteor.userId(),但每次发射后都会更改uuid(这很奇怪)。

在socket.io中我会这样做:

//clients is an array of connected socket ids
var clientIndex = clients.indexOf(socket.id);
io.sockets.socket(clients[clientIndex]).emit('message', 'hi client');

有没有办法在流星流或流星本身中做到这一点?

2 个答案:

答案 0 :(得分:1)

我认为像登录一样使用Meteor.onConnection()可以让你在发布功能中轻松地做你想做的事。

这样的事情:

Messages = new Meteor.Collection( 'messages' );

if ( Meteor.isServer ){
   var Connections = new Meteor.Collection( 'connections' );
   Meteor.onConnection( function( connection ){
     var connectionMongoId = Connections.insert( connection );
     //example Message
     Message.insert( {connectionId: connection.id, msg: "Welcome"}); 

     //remove users when they disconnect
     connection.onClose = function(){
       Connections.remove( connectionMongoId );
     };
   });

   Meteor.publish( 'messages', function(){
     var self = this;
     var connectionId = self.connection.id;
     return Messages.find( {connectionId: connectionId});
   });

}

if ( Meteor.isClient ){
  Meteor.subscribe('messages');

  Template.myTemplate.messages = function(){
    //show all user messages in template
    return Messages.find();
  };
}

我在这里使用过数据库支持的集合,因为它们是默认值,但数据库不是必需的。无论何时插入新消息,使消息成为集合都会使响应式发布变得容易。

这与流不同的一种方式是,发送到所有客户端的所有消息最终都会保留在服务器内存中,因为它会尝试跟踪发送的所有数据。如果这确实不合适,那么你可以使用Meteor.method来代替发送数据,只需使用publish来通知用户新的消息可用,所以调用方法并获取它。

无论如何,这就是我的开始。

答案 1 :(得分:1)

嗯,如果您决定使用数据库,这可以轻松完成,但我想如果您拥有大量客户端,这不是最佳选择。

另一种实现这一目标的方法 - 没有数据库 - 就是要充分利用Meteor的publish/subscribe机制。基本上它的工作方式如下:

 1. client asks server for a communication token (use Meteor.methods)
 2. client subscribes to some (abstract) data set using that token
 3. server publishes the required data based on the received token

因此,您需要在为新用户生成令牌的服务器上定义一个方法(比如说getToken)(因为您不想使用accounts)。这可能或多或少是这样的:

var clients = {}

Meteor.methods({
  getToken: function () {
    var token;
    do {
      token = Random.id();
    } while (clients[token]);
    clients[token] = {
      dependency: new Deps.Dependency(),
      messages: [],
    };
    return token;
  },
});

新客户端需要请求令牌并订阅数据流:

Meteor.startup(function () {
  Meteor.call('getToken', function (error, myToken) {
    // possibly use local storage to save the token for further use
    if (!error) {
      Meteor.subscribe('messages', myToken);
    }
  });
});

在服务器上,您需要定义自定义发布方法:

Meteor.publish('messages', function (token) {
  var self = this;

  if (!clients[token]) {
    throw new Meteor.Error(403, 'Access deniend.');
  }

  send(token, 'hello my new client');

  var handle = Deps.autorun(function () {
    clients[token].dependency.depend();
    while (clients[token].messages.length) {
      self.added('messages', Random.id(), {
        message: clients[token].messages.shift()
      });
    }
  });

  self.ready();

  self.onStop(function () {
    handle.stop();
  });
});

并且send函数可以定义如下:

var send = function (token, message) {
  if (clients[token]) {
    clients[token].messages.push(message);
    clients[token].dependency.changed();
  }
}

这是我将使用的方法。请检查它是否适合您。