Redis
 sql >> Datenbank >  >> NoSQL >> Redis

Verwenden Sie Redis, um einen Echtzeit-Chat mit socket.io und NodeJs zu erstellen

Redis ist mehr als nur ein Schlüssel-Wert-Speicher.

Sie wollen also Folgendes:

  • Chatnachrichten,
  • Zwei-Personen-Diskussionen,
  • Sie haben keine Zeitbeschränkungen erwähnt, also nehmen wir an, dass Sie Nachrichten nach einer Weile archivieren,
  • Sie sagen auch nicht, ob Sie getrennte "Threads" zwischen zwei Personen wollen, wie Foren oder kontinuierliche Nachrichten, wie Facebook. Ich nehme an, kontinuierlich.

Für jeden Benutzer müssen Sie Nachrichten speichern, die er sendet. Sagen wir APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID> . Wir fügen hier die userId hinzu, damit wir alle von einem einzelnen Benutzer gesendeten Nachrichten problemlos abrufen können.

Und für jeweils zwei Benutzer müssen Sie ihre Gespräche verfolgen. Als Schlüssel können Sie einfach ihre Benutzer-IDs APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID> verwenden . Um sicherzustellen, dass Sie immer die gleiche, gemeinsame Konversation für die beiden Benutzer erhalten, können Sie ihre IDs alphabetisch sortieren, sodass die Benutzer 132 und 145 beide 132:145 als Konversationsschlüssel haben

Was soll also in „Gesprächen“ gespeichert werden? Lassen Sie uns eine Liste verwenden:[messageKey, messageKey, messageKey] .

Ok, aber was ist nun der messageKey? Kombination aus der obigen Benutzer-ID und einer Nachrichten-ID (damit wir die eigentliche Nachricht erhalten).

Im Grunde brauchen Sie also zwei Dinge:

  1. Speichern Sie die Nachricht und geben Sie ihr eine ID
  2. Speichern Sie einen Verweis auf diese Nachricht in der entsprechenden Konversation.

Mit Node und Standard-Redis/Hiredis-Client wäre dies so etwas wie (Ich überspringe die offensichtlichen Fehlerprüfungen usw. und schreibe ES6. Wenn Sie ES6 noch nicht lesen können, fügen Sie es einfach in babel ein):

 // 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);
    });
  });
}

Nun, das ist grob und ungetestet, aber das ist der Kern dessen, wie Sie dies tun können.