websocket notification

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

websocket notification

Сообщение vitaxa_prog »

Доброго времени суток, коллеги.
Занялся переводом системы уведомлений на веб-сокеты. Нашел в сети кучу примеров как реализовать чат. Но это немного не то что нужно.
В связи с этим возникло несколько вопросов из-за недопонимания технологии. Я понимаю как работает чат. Клиент отправил сообщение, сервер ответил всем клиентам. Клиент слушает сервер, сервер слушает клиентов. Тут все понятно.
А вот как реализовать это в системе уведомлений не пойму.
Например клиент подключился по websocket к серверу. Допустим сервер опросил базу данных на предмет не прочитанных уведомлений и ответил.
И тут возникает вопрос: Если в базе данных в дальнейшем, появились новые уведомления, как отследить их?

1. Опрашивать с клиента через какие то промежутки времени, сервер(setInterval)? Тогда чем это отличается от ajax?
2. На сервере через какие то промежутки времени опрашивать базу данных и при появлении новых записей, оповещать об этом клиент? Тогда нужно делать бесконечный цикл и sleep?
3. Не использовать MySQL? А использовать что то другое?
4. ...?

Посоветуйте знающие люди как лучше организовать такую систему?
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

Ну если у вас все общение через вебсокет, то никаких проблем нет. При наступлении события вы просто рассылаете сообщение нужным пользователям.
Если событие наступает в результате например синхронного запроса, кто-то сохранил какую-то форму или из очереди чтото прилетело, то надо как-то пропихнуть это событие в демон вебсокета и сделать это быстро. Может быть при наступлении события класть что-то в кеш, а демон будет действительно в бесконечном цикле смотреть этот кеш. Как только видит что есть обновление он рассылает его нужным пользователям.

По пунктам:
1. Так действительно смысла нет, кроме того, что не надо каждый раз поднимать соединение.
2. Ну вот да, если у вас не все на вебсокете. Но лучше опрашивать не базу, а что-то побыстрее.
3. Тут смысл в доставлении события до демона, а не в средстве хранения данных.
4. В принципе ничего нет невозможного.

PS. Я с такой проблемой не сталкивался, просто я использовал вебсокеты. Так что все выше мои умозаключения.
2b||!2b Just read the instructions
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

Re: websocket notification

Сообщение vitaxa_prog »

zabachok писал(а): 2017.09.11, 18:09 Может быть при наступлении события класть что-то в кеш, а демон будет действительно в бесконечном цикле смотреть этот кеш. Как только видит что есть обновление он рассылает его нужным пользователям.
Хм, спасибо. А это мысль. Может быть еще посмотреть в сторону чего то типа redis? Я конечно не силен в этом, но научиться никогда не поздно и никому не рано.
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

vitaxa_prog писал(а): 2017.09.11, 18:15 Хм, спасибо. А это мысль. Может быть еще посмотреть в сторону чего то типа redis? Я конечно не силен в этом, но научиться никогда не поздно и никому не рано.
Конечно! Redis вообще шикарная вещь! Там можно тегировать записи и по тегам их получать. Еще если под докером работаете, то установка вообще будет очень простой. А доступ к редису из yii осуществляется через стандартный компонент. Так что ничего сложного в там нет.
Главное продумать хороший и надежный механизм передачи событий откуда угодно в демон через редис. Чтоб можно было отправить сообщение всем клиентам или одному конкретному.
2b||!2b Just read the instructions
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

Re: websocket notification

Сообщение vitaxa_prog »

Возникла такая мысль. А можно как то сигнализировать демону WebSocketServer, например из контроллера, что произошло какое то событие? Например сохранение записи в базу данных.
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

Нет возможности передать данные из одного процесса в другой, кроме как через внешнее хранилище(например кэш). В этом и проблема.
Если вы все делаете в рамках одно процесса,то проблем нет.
2b||!2b Just read the instructions
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

vitaxa_prog писал(а): 2017.09.12, 13:47 Возникла такая мысль. А можно как то сигнализировать демону WebSocketServer, например из контроллера, что произошло какое то событие? Например сохранение записи в базу данных.
Появилась новая идея. Из процесса, который что-то сохраняет в базу, подключиться к демону через вебсокет, закинуть туда сообщение и отключиться. Таким образом получится, что не надо внешнее хранилище и пользователи будут уведомлены сразу.
2b||!2b Just read the instructions
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

Re: websocket notification

Сообщение vitaxa_prog »

zabachok писал(а): 2017.09.12, 15:13 подключиться к демону через вебсокет
Приходила такая мысль. Но не придумал ничего другого как с помощью curl. А curl не поддерживает протокол ws://
Или можно как то по другому подключиться из процесса, который что-то сохраняет в базу к демону?
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

vitaxa_prog писал(а): 2017.09.12, 15:48 Или можно как то по другому подключиться из процесса, который что-то сохраняет в базу к демону?
Ну погуглить же
https://packagist.org/search/?q=websocket%20client
https://www.google.ru/search?num=20&new ... FrJEF7c1fE

Предложений море
2b||!2b Just read the instructions
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

Re: websocket notification

Сообщение vitaxa_prog »

Да, уж. Голова перестала соображать. Не подумал вообще загуглить "websocket client in php". Видимо отдыхать надо иногда. Спасибо.

Параллельно почитал на http://socketo.me про pusher. Тоже вариант.
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

vitaxa_prog писал(а): 2017.09.12, 16:29 Да, уж. Голова перестала соображать. Не подумал вообще загуглить "websocket client in php". Видимо отдыхать надо иногда. Спасибо.

Параллельно почитал на http://socketo.me про pusher. Тоже вариант.
Получилось чего?
2b||!2b Just read the instructions
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

Re: websocket notification

Сообщение vitaxa_prog »

zabachok писал(а): 2017.09.13, 11:43 Получилось чего?
Да. Не было времени. Допилил наконец.
Напишу, может кому пригодится.
Взял вот этот клиент https://github.com/ratchetphp/Pawl
В своей модели Notification в методе afterSave добавил код:

Код: Выделить всё

\Ratchet\Client\connect('ws://site.loc:8080')->then(function($conn) {
            $conn->on('message', function($msg) use ($conn) {
                //получить ответ от демона и закрыть соединение
                //хотя на ответ можно наплевать, клиент не ждет здесь ответа
                echo "Received count: {$msg}\n";
                $conn->close();
            });
            //отправить демону запрос(тут можно команду отправлять, это тестовый код)
            $conn->send('check_seen='.$this->user_id);
        }, function ($e) {
            echo "Could not connect: {$e->getMessage()}\n";
        });
В качестве сервера взял https://github.com/consik/yii2-websocket
На сервере(простой эхо сервер пока)

Код: Выделить всё

class EchoServer extends WebSocketServer
{
    public function init()
    {
        parent::init();

        $this->on(self::EVENT_CLIENT_MESSAGE, function (WSClientMessageEvent $e) {
            //Если получили сообщение на проверку уведомлений, проверяем
            if(strpos ($e->message, 'check_seen'))
            {
                 $params = explode('=', $e->message);
                 $count = Notification::find()->where(['user_id'=>$params[1], 'seen'=>0])->count();
                 $e->client->send( $count );//отправить сообщение клиенту
            	 echo $count."\n";//посмотреть в консоли что отвечает сервер
            }
            else
            {
                //просто отвечаем эхом
            	$e->client->send( $e->message );
            }
        });
    }
}
Работает. Отвечает количеством новых уведомлений
Осталось идентифицировать клиенты. Пока не придумал как.
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

Правильно я понял, что в первом листинге фрагмент $conn->on('message'... не нужен и надо закрытие ставить сразу после отправки? Здесь же нужно только отправить что-то демону, а не получить. Либо если вы хотите убедиться, что сообщение доставлено и демон ответил эхом, то нужен механизм проверки отсутствия ответа.
Очень рекомендую передавать сообщения в формате json, это очень удобно, решит много проблем и исключит много багов.
2b||!2b Just read the instructions
Аватара пользователя
vitaxa_prog
Сообщения: 306
Зарегистрирован: 2011.06.06, 22:44
Откуда: Волноваха

Re: websocket notification

Сообщение vitaxa_prog »

zabachok писал(а): 2017.09.18, 12:32 Правильно я понял, что в первом листинге фрагмент $conn->on('message'... не нужен и надо закрытие ставить сразу после отправки?
Да, если никакие обработки не нужны то можно просто

Код: Выделить всё

\Ratchet\Client\connect('ws://site.loc:8080')->then(function($conn) {
            $conn->send('check_seen='.$this->user_id);
            $conn->close();
        }, function ($e) {
            echo "Could not connect: {$e->getMessage()}\n";
        });
zabachok писал(а): 2017.09.18, 12:32 Очень рекомендую передавать сообщения в формате json, это очень удобно, решит много проблем и исключит много багов.
Да json это правильно. Код который я привел в пример, это набросок на скорую руку. Другими словами говоря - пример как делать не надо)))
В принципе ничего нет невозможного.
— Вы думаете?
— Для человека. С интеллектом.
Аватара пользователя
Ghost_nsk
Сообщения: 825
Зарегистрирован: 2012.01.01, 00:45
Откуда: Новосибирск
Контактная информация:

Re: websocket notification

Сообщение Ghost_nsk »

у нас реализована связка на одном из проектов - yii2 + node.js + socket.io + redis. Работает более менее адекватно
Аватара пользователя
zabachok
Сообщения: 522
Зарегистрирован: 2013.12.16, 14:38

Re: websocket notification

Сообщение zabachok »

vitaxa_prog писал(а): 2017.09.18, 16:49 Да json это правильно. Код который я привел в пример, это набросок на скорую руку. Другими словами говоря - пример как делать не надо)))
Круто! Пишите, если будут новые интересные подробности!
2b||!2b Just read the instructions
Ответить