如何生成房间 ID 并强制两个用户加入该房间?

Posted

技术标签:

【中文标题】如何生成房间 ID 并强制两个用户加入该房间?【英文标题】:How to generate a room id and force two users to join that room? 【发布时间】: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 标签:) 【参考方案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);
    )
);

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

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

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

示例:

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');
    );
);

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

【讨论】:

以上是关于如何生成房间 ID 并强制两个用户加入该房间?的主要内容,如果未能解决你的问题,请参考以下文章

socket.io 从两个房间加入客户端

如何让用户加入他们的多个房间 socket.io

在React Native JSX中如何在一个房间里连接两个用户?

选择两个日期之间的可用房间

信令服务器房间设置

XMPP群聊java - 在邀请监听器内加入房间的用户的逻辑不起作用