Socket
Система предоставляет канал для информирования пользователей о событиях в режиме реального времени через параллельное соединение пользователя с сервером посредством web-socket-a (если версия браузера не позволяет их использование, то автоматически будут использоваться другие механизмы, например, long-polling). С помощью данной функциональности, реализованы: общение между пользователями (модуль chat), система публикации сообщений (модуль livefeed), система мониторинга работы расчетчика (модуль calclog) и многие другие.
В качестве дополнительного инструмента реализованного на базе socket-а является Progress bar. При разработке системы, нужно принимать в расчет, что некоторые запросы, которые пользователь отправляет на сервер требуют продолжительного времени исполнения, например печать свода документов. В этом случае, при отправке ajax запроса, если клиент не получает ответ от браузера в течении определенного промежутка времени (обычно 2-х минут), браузер отправляет повторный запрос. Чтобы избежать такого поведения клиентского кода, система запускает задачу, инициализирует прогресс бар и отправляет клиенту в качестве ответа уникальный id, по которому в дальнейшем отправляется информация через socket о прогрессе работы.
Перейдем к описанию программной реализации:
Серверный код
В качестве основной библиотеки используется nodejs библиотек socket.io.
Код на стороне сервера находится в файле src/socket.js. Основные методы предоставляемые модулем на стороне сервера:
emitEventAll = function(eventName,data) // оповещение всех пользователей о каком то событии
emitTo = function(CodeUser,EventName,data) // оповещение конкретного пользователя о событии
Кроме того, при присоединении или разрыве соединения с пользователем модуль инициирует события:
Events.emit("userconnected",socket)
Events.emit("userdisconnected",socket)
Рассмотрим пример использования событий. Код из модуля login. Появлению этого куска кода в системе способствовало то, что при закрытии браузера Chrome сессия по умолчанию не завершается (это можно устранить в настройках браузера, поставив нужную галочку). В связи с этим, на форме входа в систему возникла галочка "Чужой компьютер", при включении которой в системе запускается свой механизм автоматического выхода пользователя из системы через 5 секунд после обрыва всех socket соединений.
var SocketManager = require(__base+'src/socket.js');
var AlienDeviceGuard = (new function(){
var self = this;
self.DisconnectTimeouts = {};
self.UserConnected = function(socket){
var CodeUser = socket.request.session.user.CodeUser;
if (self.DisconnectTimeouts[CodeUser]){
clearTimeout(self.DisconnectTimeouts[CodeUser]);
}
}
self.UserDisconnected = function(socket){
var CodeUser = socket.request.session.user.CodeUser;
if (socket.request.session.alienDevice){
if (socket.request.session && socket.request.session.user && !_.isEmpty(CodeUser)){
self.DisconnectTimeouts[CodeUser] = setTimeout(function(req){
return function(){
req.logout();
req.session.destroy();
}
}(socket.request),5000);
}
}
}
SocketManager.Events.on("userconnected",self.UserConnected);
SocketManager.Events.on("userdisconnected",self.UserDisconnected);
return self;
})
Клиентский код
Код на стороне клиента находится в файле modules/socket/index.js
Работа с socket-ом на стороне клиента происходит по следующему алгоритму:
Регистрируется событие модуля в виде название события + обработчик
Запускается прослушивание события
Останавливается прослушивание события
На словах это выглядит так: сначала модуль регистрирует событие, затем, обычно, при входе на страницу модуля запускается прослушивание, при уходе со страницы модуля, прослушивание останавливается. Ниже приведен пример из клиентского кода модуля livefeed:
self.Init = function(done){
self.LoadLiveFeed();
MSocket.RegisterEvent("livefeedupdate",self.UpdateFeed);
MSocket.Start ("livefeedupdate");
MSite.Events.on("scroll-bottom",self.LoadMore);
return done();
}
Модуль при загрузке передаёт информацию socket-у о том, что события "livefeedupdate" будут обрабатываться aeyrwbtq UpdateFeed. И запускает прослушивание. На стороне сервера, при изменении сообщений событие рассылается всем пользователям, например при удалении события:
router.delete("/feed/:id", HP.TaskAccess("IsFeedWriter"), function(req,res,next){
var FeedModel = mongoose.model("lfmessage"), id = req.params.id;
FeedModel.remove({_id:id}).exec(function(err){
SocketManager.emitEventAll("livefeedupdate",{id:id,type:'delete'});
return res.json({});
})
})
Last updated
Was this helpful?