Здравствуйте, сейчас повсеместно используется аякс для большей интерактивности сайтов, сам аякс очень крут, но для реализации тех-же уведомлений до сих пор бОльшинство используют запросы по timeout-у, в то время, когда есть много фич, для того, чтобы они происходили только в момент исполнения "события", в большинстве реализации для этого используется node.js и модуль socket.io, так-как хорошая документация, прост и удобен.
Есть только несколько вещей из коробки, которые будут мешать отличной работе данного решения:
- браузер ограничивает кол-во одновременных соединений к домену;
- использование по 1 соединению на вкладки;
- связь php и node.js (тут проблема условная и есть много вариантов решения);
Сразу оговорюсь, что людям, которые используют шаред хостинги, делать нечего, кроме как покупать vps.
Чтобы использовать 1 соединение на сайт, есть несколько способов решения проблемы:
1. WebWorkers
2. localStorage
3. Кукисы
Воркеры самый идеальный вариант, но не сейчас, слишком сыро и слабая поддержка браузерами, тогда как вариант с локалсторейджем и кукисами, на данный момент самый оптимальный, но мы пришли к этому не первыми, поэтому проще всего использовать готовые библиотеки, я пробовал писать и своё, но в итоге нашёл всё, что мне нужно в одной, которая удовлетворила все мои нужды:
https://github.com/RubaXa/wormhole
Реализация с её использованием проста:
Code:
var hole = new wormhole.Universal(crossDomain);
hole.on('master', function () {
// Если вкладка стала master создаем соединение с сокетом
var adapter = io.connect(socketUrl + ':' + socketPort);
adapter.on('connect', function() {
adapter.emit('join', {
id: userId
});
});
// Подписываемся на события от сервера
adapter.on('message', function (data) {
// Рассылаем данные между табами
hole.emit('message', data);
});
});
// Слушаем события из мастера
hole.on('message', function (data) {
switch(data.action) {
case 'message':
switch(data.event) {
case 'new':
messageNewNotify();
playSound("/audio/notify.ogg");
break;
case 'read':
messageDeleteNotify();
break;
case 'notify':
playSound("/audio/notify.ogg");
break;
}
break;
}
});
Собственно пример с живого сайта:
Code:
var hole = new wormhole.Universal(crossDomain);
это для CORS (так как для каждого подпроекта свой субдомен и нужна взаимосвязь между ними)
Для связи nodejs и php я выбрал redis, так-как в проекте он уже использовался для сессий и кеширования данных доктрины, к примеру мы отправляем личное сообщение и сразу отправляем в канал redis-a уведомление об этом:
(сразу оговорюсь, я использую в проекте symfony и соответствующий бандл для работы с редисом, но в целом, при интеграции в вб, код будет незначительно другим, в зависимости от того, какую обёртку возьмёте или реализуете для клиента)
PHP Code:
$redis = $this->get('snc_redis.default');
$redis->publish('actions', json_encode(array(
'clientId' => $recipient->getHashUserId(), // кому сообщение
'data' => array(
'action' => 'message', // действие, в данном случае личное сообщение
'event' => 'read' // событие - пометить как прочитанное
)
)));
Далее на стороне node приложения мы его принимаем и обрабатываем:
Code:
// Слушаем Redis
redisClient.on("message", function(channel, message) {
var response = JSON.parse(message);
response.clientId = cleanHash(response.clientId);
try {
switch (response.clientId) {
case ('broadcast'):
// Отправка сообщения всем пользователям
io.send(response.data);
console.log('Send global data: "' + response.data.action + '"');
break;
default:
// Отправка личного сообщения
clients[response.clientId].forEach(function(client) {
client.send(response.data);
console.log('Send data: "' + response.data.action + '" to ' + response.clientId);
});
break;
}
}
catch (error) {
console.log(error)
}
});
Всё изложено сумбурно и скорее для общего ознакомления, но готов ответить на вопросы.