【问题标题】:How to generate a room id and force two users to join that room?如何生成房间 ID 并强制两个用户加入该房间?
【发布时间】:2016-05-07 09:42:01
【问题描述】:

我正在用 node.js、socket.io 和 mongoose 构建一个聊天应用程序。我的目标是建立一对一的聊天,它类似于 facebook 网络聊天。所以基本上每当我点击一个用户时,它都会转到该用户的网址并可能与他/她聊天

但我面临的问题是我只能将消息发送给目标用户,而不能发送给我自己。

这是当前代码

服务器端

socket.on('chatTo', function(data){
      User.findOne({ username: data.destinationUsername, socketId: { '$ne': null}}, function(err, foundUser) {
        if (foundUser) {
          io.to(foundUser.socketId).emit('incomingChat', { sender: user.username, message: data.message });

        } else {
          io.to(socket.id).emit('deliverError', { error: foundUser + ' is not online' });

        }
      });
    });

客户端

$(function() {

  var socket = io();


  function chatTo(message, destinationUsername) {
    socket.emit('chatTo', { message: message, destinationUsername });
  }


  $('#sendMessage').submit(function(){
    var input = $('#message').val();
    var username = $('#username').val();
    chatTo(input, username);
    $('#message').val('');
    return false;
  });


  socket.on('incomingChat', function(data) {
    var html = data; // Messages to append to media-list

    $('.media-list').append(html);
  });
});

所以这里发生的是,在客户端,用户 A 点击表单提交,提交消息,它将调用 chatTo 函数并发出数据。只是想让你们知道,inputusername 来自 html 页面。它看起来像这样

input = "Hello";

username = "jackmoscovi" // user's username

然后它会将这两个数据发送回服务器,socket.on('chatTo') 正在监听。在一些 MongoDB 操作之后,如果找到用户,则向该特定套接字发出。

结果是

蝙蝠侠发出的信息只显示在小丑的页面上,而不会出现在蝙蝠侠的页面上。我知道这一点,因为我专门向那个套接字发射。真正的问题是我如何强制这两个用户都在一个独特的房间里?我应该创建一个新的Room mongoose model 吗?然后拨打socket.join('uniqueRoom')?

然后简单地io.to('uniqueRoom').emit("Message?");

我将如何实现这个房间机制?

我已经挣扎了2天了,请有人结束这种痛苦:(

【问题讨论】:

  • 如果您的问题是如何向发射器发送事件,则可以在回调函数中执行this.emit(......)
  • @AlexBlex 有可能我需要将房间存储在猫鼬中,因此使用 mongodb 标签:)

标签: node.js mongodb express socket.io


【解决方案1】:

首先创建一个像这样的猫鼬模式

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;
var messageSchema=new Schema({
    sender : {
        type : String,
    },
    receiver : {
        type : String.
    },
    message : {
        type : String
    }
})
mongoose.model('messages',messageSchema);

然后在服务器代码中

message = mongoose.model('messages')
socket.on('chatTo', function(data){  // data is json containing sender, receiver and message
    User.findOne({ username: data.destinationUsername, socketId: { '$ne': null}}, function(err, foundUser) {
        if (foundUser) {
            io.to(foundUser.socketId).emit('incomingChat', { sender: user.username, message: data.message });
            socket.emit('incomingChat', { sender: user.username, message: data.message });
            var newMessage = new message({
                sender : data.sender,
                receiver : data.receiver,
                message : data.message
            })
            newMessage.save(function (err, data){
                if(err)
                    console.log(err)
            })
        } else {
            io.to(socket.id).emit('deliverError', { error: foundUser + ' is not online' });

        }
    });
});

【讨论】:

  • 这种方法的问题是,我需要将消息保存到一个房间。这样以后渲染数据会更容易。
  • 你可以简单地创建一个猫鼬消息模式,其中包含发送者、接收者和消息的唯一用户名。导致结构类似::: var messageSchema = new mongoose.Schema({"sender":String, "receiver":String, "message"});
  • var messageSchema = new mongoose.Schema({"sender":String, "receiver":String, "message":String});因此,当您想从数据库中获取消息时,您可以使用发送者和接收者字段来查询它们。由于它是一对一聊天,我看不出创建房间的意义
  • 感谢您的回答,但我刚刚意识到还有一个问题。在渲染消息模型中的数据时,我将如何渲染它?
  • 对不起,如果我没有得到你。当你说渲染时,你到底是什么意思?
【解决方案2】:

这有点难以回答,因为感觉你实际上是在问错误的问题。要了解您“应该”如何做到这一点,您实际上必须首先解决很多其他架构问题。

您需要解决的第一件事是身份验证/授权问题,即当您将套接字从浏览器连接到服务器时,您的服务器如何知道您是谁并且知道您不是冒名顶替者?我没有这方面的最佳实践,但您可能想查看socketio-auth package,这可能会给您一些想法。

您需要解决的第二件事是如何将经过身份验证的用户与套接字关联。我能找到的唯一参考来源是 socket.io 网站上的chat demo

此时,您的服务器中应该有一组具有关联用户的套接字。当蝙蝠侠上线时,您应该检查数据库中是否有他参与的任何聊天,并让他通过 id 连接到该聊天室:

Chat.find({usernames: "Batman"}).exec().then(function(chats){
    chats.forEach(function(chat){
        socket.join(chat.id);
    })
});

到目前为止,这是假设小丑尚未创建与蝙蝠侠的聊天,因此数据库中没有将两者连接起来的聊天。

当小丑想和蝙蝠侠聊天时,你需要通过套接字发送一个“连接”消息

  1. 在其中创建与他们两人的聊天
  2. 如果它们当前已连接到服务器,则查找它们当前的套接字,并且
  3. 发送他们已相互连接的消息

示例:

socket.on('startChat', function(data){
    //assuming that you have assocated the current user with the socket
    var currentUser = socket.user;

    //who the current user (Joker) wants to connect to
    var connectToUser = data.connectToUser; // Batman

    Chat.create({
        usernames: [currentUser.username, connectToUser.username] // ["Joker", "Batman"]
    }).then(function(newChat){
        socket.join(newChat.id); // add current user (Joker) to that socket.io room

        // this is overly simplified: assuming you have an array collectionOfConnectedSockets which
        // contains all currently connected sockets
        var otherUserSocket = collectionOfConnectedSockets[connectToUser.username];

        //otherUserSocket now is Batman's socket - so make him join the room
        otherUserSocket.join(newChat.id);

        //send them both a message that a chat has been connected
        io.to(newChat.id).emit('You have been connected to a new chat');
    });
});

现在,这会覆盖 很多 的细节,而这些细节中的每一个都取决于您的应用程序的架构。此外,我的语法可能有点偏离,这些示例仅作为您应该尝试做的指示,而不是作为您问题的直接解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2014-07-18
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    相关资源
    最近更新 更多