【问题标题】:Use redis to build a real time chat with socket.io and NodeJs使用 redis 构建与 socket.io 和 NodeJs 的实时聊天
【发布时间】:2016-04-12 05:36:09
【问题描述】:

我想为我的项目构建一个实时聊天系统,但实际上我在使用 Redis 时遇到了一些问题,因为我希望我的数据尽可能好地存储。

我的问题:

我想用Socket Io在一个封闭的群里(两个人)进行实时聊天,但是如何存储消息呢?

Redis 是一个键值存储,这意味着如果我想存储一些东西,我需要在存储之前为我的数据添加一个唯一键。

如果同一用户发布多条消息,我会在 redis 中使用哪些键?我正在考虑将唯一 ID 作为唯一键,但由于我希望能够在用户登录聊天页面时获取此 cmets,但如果我这样做,我需要编写另一个数据库,将聊天 ID 与发布该内容的用户相关联留言

我是不是忘记了什么?有没有最好的方法来做到这一点?

对不起,我的英语不好。

【问题讨论】:

    标签: node.js sockets redis socket.io


    【解决方案1】:

    Redis 不仅仅是键值存储。

    所以你想要以下内容:

    • 聊天消息,
    • 两人讨论,
    • 您没有提到时间限制,因此假设您在一段时间后归档消息,
    • 您也没有说是否要在两个人之间建立单独的“线程”,例如论坛或连续消息,例如 facebook。我假设是连续的。

    对于每个用户,您必须存储他发送的消息。假设APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID>。我们在此处添加 userId,以便我们可以轻松检索单个用户发送的所有消息。

    而且,对于每两个用户,您都需要跟踪他们的对话。作为密钥,您可以简单地使用他们的用户 ID APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID>。为确保您始终为两个用户获得相同的共享对话,您可以按字母顺序对他们的 id 进行排序,以便用户 132 和 145 都将 132:145 作为对话键

    那么在“对话”中存储什么?让我们使用一个列表:[messageKey, messageKey, messageKey]

    好的,但是现在的 messageKey 是什么?上面的 userId 和 messageId 的组合(所以我们可以得到实际的消息)。

    所以基本上,你需要两件事:

    1. 存储消息并为其指定 ID
    2. 将对此消息的引用存储到相关对话中。

    使用 node 和标准 redis/hiredis 客户端,这有点像(我将跳过明显的错误等检查,我将编写 ES6。如果您还不能阅读 ES6,只需将其粘贴到 babel):

     // assuming the init connects to redis and exports a redisClient
    import redisClient from './redis-init';
    import uuid from `node-uuid`;
    
    
    export function storeMessage(userId, toUserId, message) {
    
      return new Promise(function(resolve, reject) {
    
        // give it an id.
        let messageId = uuid.v4(); // gets us a random uid.
        let messageKey = `${userId}:${messageId}`;
        let key = `MY_APP:MESSAGES:${messageKey}`;
        client.hmset(key, [
          "message", message,
          "timestamp", new Date(),
          "toUserId", toUserId
        ], function(err) {
          if (err) { return reject(err); }
    
          // Now we stored the message. But we also want to store a reference to the messageKey
          let convoKey = `MY_APP:CONVERSATIONS:${userId}-${toUserId}`; 
          client.lpush(convoKey, messageKey, function(err) {
            if (err) { return reject(err); }
            return resolve();
          });
        });
      });
    }
    
    // We also need to retreive the messages for the users.
    
    export function getConversation(userId, otherUserId, page = 1, limit = 10) {
      return new Promise(function(resolve, reject) {
        let [userId1, userId2] = [userId, otherUserId].sort();
        let convoKey = `MY_APP:CONVERSATIONS:${userId1}-${userId2}`;
        // lets sort out paging stuff. 
        let start = (page - 1) * limit; // we're zero-based here.
        let stop = page * limit - 1;
        client.lrange(convoKey, start, stop, function(err, messageKeys) {
    
          if (err) { return reject(err); }
          // we have message keys, now get all messages.
          let keys = messageKeys.map(key => `MY_APP:MESSAGES:${key}`);
          let promises = keys.map(key => getMessage(key));
          Promise.all(promises)
          .then(function(messages) {
             // now we have them. We can sort them too
             return resolve(messages.sort((m1, m2) => m1.timestamp - m2.timestamp));
          })
          .catch(reject);
        }); 
      });
    }
    
    // we also need the getMessage here as a promise. We could also have used some Promisify implementation but hey.
    export function getMessage(key) {
      return new Promise(function(resolve, reject)  {
        client.hgetall(key, function(err, message) {
          if (err) { return reject(err); }
          resolve(message);
        });
      });
    }
    

    现在这是粗略且未经测试的,但这就是您如何做到这一点的要点。

    【讨论】:

      【解决方案2】:

      redis 是你项目中的一个约束吗?

      你可以通过这个http://autobahn.ws/python/wamp/programming.html

      【讨论】:

      • 我正在使用 redis 和 socket.io,因为我的项目实际上可以在 NodeJs 上运行,但感谢您的建议
      猜你喜欢
      • 2016-11-12
      • 2015-05-22
      • 2013-08-08
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 2018-08-02
      相关资源
      最近更新 更多