sql >> Base de Datos >  >> NoSQL >> Redis

Use redis para crear un chat en tiempo real con socket.io y NodeJs

Redis es más que una tienda de clave-valor.

Así que quieres lo siguiente:

  • mensajes de chat,
  • discusiones de dos personas,
  • no mencionó las limitaciones de tiempo, así que supongamos que archiva los mensajes después de un tiempo,
  • Tampoco dices si quieres "hilos" separados entre dos personas, como foros o mensajes continuos, como Facebook. Asumo continuo.

Para cada usuario, debe almacenar los mensajes que envía. Digamos APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID> . Agregamos userId aquí para que podamos recuperar fácilmente todos los mensajes enviados por un solo usuario.

Y, para cada dos usuarios, debe realizar un seguimiento de sus conversaciones. Como clave, simplemente puede usar sus ID de usuario APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID> . Para asegurarse de obtener siempre la misma conversación compartida para los dos usuarios, puede ordenar sus ID alfabéticamente, de modo que los usuarios 132 y 145 tengan 132:145 como clave de conversación

Entonces, ¿qué almacenar en "conversaciones"? Usemos una lista:[messageKey, messageKey, messageKey] .

Ok, pero ¿qué es ahora la clave del mensaje? Combo de ID de usuario anterior y un ID de mensaje (para que podamos obtener el mensaje real).

Básicamente, necesitas dos cosas:

  1. Guarde el mensaje y asígnele una identificación
  2. Almacene una referencia a este mensaje en la conversación relevante.

Con el nodo y el cliente redis/hiredis estándar, esto sería algo como (me saltearé las comprobaciones de errores obvios, etc., y escribiré ES6. Si aún no puede leer ES6, simplemente péguelo en 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);
    });
  });
}

Eso es crudo y no probado, pero esa es la esencia de cómo puedes hacer esto.