Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

Use redis para criar um bate-papo em tempo real com socket.io e NodeJs


Redis é mais do que um armazenamento de valor-chave.

Então você quer o seguinte:
  • mensagens de bate-papo,
  • discussões de duas pessoas,
  • você não mencionou restrições de tempo, então vamos supor que você arquive as mensagens depois de um tempo,
  • você também não diz se quer "threads" separados entre duas pessoas, como fóruns ou mensagens contínuas, como facebook. Estou assumindo contínua.

Para cada usuário, você deve armazenar as mensagens que ele envia. Digamos APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID> . Adicionamos userId aqui para que possamos recuperar facilmente todas as mensagens enviadas por um único usuário.

E, para cada dois usuários, você precisa acompanhar suas conversas. Como chave, você pode simplesmente usar seus IDs de usuário APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID> . Para garantir que você sempre tenha a mesma conversa compartilhada para os dois usuários, você pode classificar seus ids em ordem alfabética, para que os usuários 132 e 145 tenham 132:145 como chave de conversa

Então, o que guardar em "conversas"? Vamos usar uma lista:[messageKey, messageKey, messageKey] .

Ok, mas o que é agora o messageKey? Combinação de userId acima e um messageId (para que possamos obter a mensagem real).

Então, basicamente, você precisa de duas coisas:
  1. Armazene a mensagem e dê um ID a ela
  2. Armazene uma referência a esta mensagem na conversa relevante.

Com node e cliente redis/hiredis padrão, isso seria algo como (vou pular as verificações óbvias de erro etc, e escreverei ES6. Se você ainda não consegue ler o ES6, basta colá-lo no 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);
    });
  });
}

Agora, isso é bruto e não testado, mas essa é a essência de como você pode fazer isso.