2016-01-07 2 views
1

Я хочу создать чат-систему в реальном времени для моего проекта, но на самом деле у меня есть некоторые проблемы с Redis, потому что я хочу, чтобы мои данные хранились как можно лучше.Используйте redis для создания чата реального времени с socket.io и NodeJs

Моя проблема:

Я хотел бы использовать сокет Ио делать в режиме реального времени, болтая в закрытой группе (два человека), но, как хранить сообщения?

Redis - это хранилище ключевых значений, и это означает, что если я хочу что-то хранить, мне нужно добавить уникальный ключ к моим данным, прежде чем вы сможете его сохранить.

Если один и тот же пользователь отправил несколько сообщений, какие ключи я бы использовал внутри redis? Я думаю об уникальных идентификаторах как о уникальных ключах, но поскольку я хочу получать эти комментарии, когда пользователь регистрирует страницу чата, но если я это делаю, мне нужно написать другую базу данных, которая связывает идентификаторы чата с пользователем, который опубликовал это сообщение

Я ничего не забываю? Есть ли лучший способ сделать это?

Извините за мой плохой английский.

ответ

2

Redis является более ключ-значение магазина.

Итак, вы хотите следующее:

  • сообщений чата,
  • дискуссии двух человек,
  • вы не говоря уже о временных ограничений, так что давайте предположим, что вы архивировать сообщения через некоторое время,
  • вы также не говорите, хотите ли вы отдельные «потоки» между двумя людьми, например форумы или непрерывные сообщения, например, facebook. Я предполагаю, что он будет непрерывным.

Для каждого пользователя вы должны хранить отправленные им сообщения. Скажем, APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID>. Мы добавляем здесь userId, чтобы мы могли легко восстановить все сообщения, отправленные одним пользователем.

И для каждого двух пользователей вам необходимо отслеживать их разговоры. В качестве ключа вы можете просто использовать свои идентификаторы пользователей APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID>. Чтобы убедиться, что вы всегда получаете то же самое, общий разговор для двух пользователей, вы можете сортировать их идентификаторы по алфавиту, так что пользователи 132 и 145 будут иметь 132: 145 как ключ разговора

Итак, что хранить в «разговорах», ? Давайте воспользуемся списком: [messageKey, messageKey, messageKey].

Хорошо, но что теперь представляет сообщение? Комбинация userId выше и messageId (чтобы мы могли получить фактическое сообщение).

Так в основном, вам нужно две вещи:

  1. сохранить сообщение и дать ему ID
  2. сохранить ссылку на это сообщение на соответствующий разговор.

с узлом и стандартным Redis/hiredis клиентом это будет somehting как (я пропущу очевидные ошибки и т.д. проверки, и я напишу 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); 
    }); 
    }); 
} 

Теперь это грубо и непроверено, но это суть того, как вы можете это сделать.

1

Редис - это ограничение в вашем проекте?

вы можете пройти через этот http://autobahn.ws/python/wamp/programming.html

+0

Я использую redis и socket.io, потому что мой проект действительно работает на NodeJs, но спасибо за ваше предложение – leodev