Продолжаем рассматривать варианты хранения данных приложения Node.js на примере создания простого чата на TCP-сокетах. На очереди хранилище Redis. Предлагаю хранить сообщения нашего чата в структуре данных по имени список. Списки в Redis позволяют хранить и манипулировать массивами значений для заданного ключа - то, что нужно для нашего чата.
Для начала в каталоге приложения создадим каталог node_modules, в который будем устанавливать модули, необходимые для работы нашего приложения.
Затем создадим файл package.json с помощью утилиты npm init:
После того, как мы согласимся с содержимым файла, предложенным утилитой npm init, файл package.json будет создан:
Теперь можно установить модуль redis, а также одновременно сохранить информацию об установленном модуле в раздел dependencies файла package.json, выполнив в консоли команду npm install --save redis:
Редактируем код нашей модели данных - файла message.js.
Единственный модуль, который нам понадобится для работы с данными - это разумеется redis.
Ограничим размер списка - структуры данных, в которой мы будем хранить наши сообщения - следующим образом: сразу же после сохранения сообщения с помощью команды lpush предлагаю обрезать размер списка командой ltrim, создав тем самым очередь сообщений ограниченного размера:
На текущем этапе изменения в файле server.js незначительны - я немного изменил код получения сообщений сразу после присоединения к чату нового пользователя - привел его в соответствие экспортируемому методу get модели данных:
Не забываем скачать бинарники Redis, запускаем redis-server:
Запускаем северную часть чата, пару клиентов, начинаем разговор:
Запускаем третьего клиента...
... и замечаем, что сообщения у нас появляются в обратном порядке :).
Мой косяк, отредактируем код файла message.js - перевернем массив, который возвращает метод get модели данных.
Кроме того, раз уж все равно полезли в код модели, предлагаю немного изменить код функции обратного вызова того же метода get с тем, чтобы она соответствовала соглашению "error first":
Соответственно подрихтуем и код сервера:
Запускаем сервер, пару клиентов:
С Redis все. В следующей серии рассмотрим вариант с использованием MongoDB Native Driver. Продолжение следует...
Для начала в каталоге приложения создадим каталог node_modules, в который будем устанавливать модули, необходимые для работы нашего приложения.
Затем создадим файл package.json с помощью утилиты npm init:
После того, как мы согласимся с содержимым файла, предложенным утилитой npm init, файл package.json будет создан:
Теперь можно установить модуль redis, а также одновременно сохранить информацию об установленном модуле в раздел dependencies файла package.json, выполнив в консоли команду npm install --save redis:
Редактируем код нашей модели данных - файла message.js.
Единственный модуль, который нам понадобится для работы с данными - это разумеется redis.
Ограничим размер списка - структуры данных, в которой мы будем хранить наши сообщения - следующим образом: сразу же после сохранения сообщения с помощью команды lpush предлагаю обрезать размер списка командой ltrim, создав тем самым очередь сообщений ограниченного размера:
var redis = require("redis");
module.exports = function(len, size) {
this.len = len || 100; // длина сообщения по умолчанию - 100 символов
this.size = size || 19; //размер кэша сообщений по умолчанию - 20 штук
this.insert = function(client, data, cb) {
if(data.length > this.len) {
cb('Too much information!');
return;
}
data = {data: data, from: client['_id'], ts: Date.now()};
var client = createRedisClient();
client.lpush('list:msg', JSON.stringify(data), redis.print);
client.ltrim('list:msg', 0, this.size, redis.print);
client.quit();
cb(false, createMessage(data));
}
this.get = function(n, cb) {
var i = n || 5; // количество сообщений по умолчанию - 5 штук
var client = createRedisClient();
client.lrange('list:msg', 0, i, function(err, list) {
cb(list.map(function(msg) {
return createMessage(JSON.parse(msg));
}).join('\n'));
client.quit();
});
}
}
function createMessage(msg) {
return new Date(msg.ts).toLocaleTimeString() + ' ' + msg.from + ' >>> ' + msg.data;
}
function createRedisClient() {
var client = redis.createClient();
client.on("error", function (err) {
console.log("--- redis client error ---\n%s", err);
});
return client;
}
На текущем этапе изменения в файле server.js незначительны - я немного изменил код получения сообщений сразу после присоединения к чату нового пользователя - привел его в соответствие экспортируемому методу get модели данных:
var net = require('net');
var PubSub = require('./pubsub'),
pubsub = new PubSub;
var Message = require('./message'),
message = new Message();
var server = net.createServer(function(socket) {
socket.setEncoding('utf8');
console.log('--- socket connected ---\nfrom: %s', socket.remoteAddress + ':' + socket.remotePort);
pubsub.emit('join', socket, function() {
message.get(null, function(data) {
socket.write('\n' + data);
});
});
socket.on('data', function(data) {
data = data.replace(/\r\n$/, '');
console.log('--- socket data ---\n%s', data);
message.insert(this, data, function(err, data) {
if(err) {
socket.write(err);
return;
}
pubsub.emit('broadcast', socket, data);
});
});
socket.on('close', function() {
console.log('--- socket closed ---');
pubsub.emit('leave', this);
});
socket.on('end', function() {
console.log('--- socket end ---');
pubsub.emit('leave', this);
});
socket.on('error', function(e) {
console.log('--- server error ---\ncode: %s', e.code);
});
});
server.listen(8124, function() {
console.log('Chamber of Secrets is opened on port %d...', this.address()['port']);
});
Не забываем скачать бинарники Redis, запускаем redis-server:
Запускаем северную часть чата, пару клиентов, начинаем разговор:
Запускаем третьего клиента...
... и замечаем, что сообщения у нас появляются в обратном порядке :).
Мой косяк, отредактируем код файла message.js - перевернем массив, который возвращает метод get модели данных.
Кроме того, раз уж все равно полезли в код модели, предлагаю немного изменить код функции обратного вызова того же метода get с тем, чтобы она соответствовала соглашению "error first":
var redis = require("redis");
module.exports = function(len, size) {
this.len = len || 100; // длина сообщения по умолчанию - 100 символов
this.size = size || 19; //размер кэша сообщений по умолчанию - 20 штук
this.insert = function(client, data, cb) {
if(data.length > this.len) {
cb('Too much information!');
return;
}
data = {data: data, from: client['_id'], ts: Date.now()};
var client = createRedisClient();
client.lpush('list:msg', JSON.stringify(data), redis.print);
client.ltrim('list:msg', 0, this.size, redis.print);
client.quit();
cb(false, createMessage(data));
}
this.get = function(n, cb) {
var i = n || 5; // количество сообщений по умолчанию - 5 штук
var client = createRedisClient();
client.lrange('list:msg', 0, i, function(err, list) {
if(err) return cb('--- error getting data ---');
cb(false, list.map(function(msg) {
return createMessage(JSON.parse(msg));
}).reverse().join('\n'));
client.quit();
});
}
}
function createMessage(msg) {
return new Date(msg.ts).toLocaleTimeString() + ' ' + msg.from + ' >>> ' + msg.data;
}
function createRedisClient() {
var client = redis.createClient();
client.on("error", function (err) {
console.log("--- redis client error ---\n%s", err);
});
return client;
}
Соответственно подрихтуем и код сервера:
var net = require('net');
var PubSub = require('./pubsub'),
pubsub = new PubSub;
var Message = require('./message'),
message = new Message();
var server = net.createServer(function(socket) {
socket.setEncoding('utf8');
console.log('--- socket connected ---\nfrom: %s', socket.remoteAddress + ':' + socket.remotePort);
pubsub.emit('join', socket, function() {
message.get(null, function(err, data) {
if(err) return socket.write(err);
socket.write('\n' + data);
});
});
socket.on('data', function(data) {
data = data.replace(/\r\n$/, '');
console.log('--- socket data ---\n%s', data);
message.insert(this, data, function(err, data) {
if(err) return socket.write(err);
pubsub.emit('broadcast', socket, data);
});
});
socket.on('close', function() {
console.log('--- socket closed ---');
pubsub.emit('leave', this);
});
socket.on('end', function() {
console.log('--- socket end ---');
pubsub.emit('leave', this);
});
socket.on('error', function(e) {
console.log('--- server error ---\ncode: %s', e.code);
});
});
server.listen(8124, function() {
console.log('Chamber of Secrets is opened on port %d...', this.address()['port']);
});
Запускаем сервер, пару клиентов:
С Redis все. В следующей серии рассмотрим вариант с использованием MongoDB Native Driver. Продолжение следует...









Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации