Предупреждение! Я опытный пользователь персонального компьютера и программы МС Ворд и Звукозапись. Однако ряд терминов и определений в этой статье могу употребить не верно. Сообщите о моих ошибках, если они найдутся.
Есть две системы. Одна разрабатывается мной и на ней отображены лица сотрудников ИПК. Страница первой системы открыта на большой сенсорной панеле на входе. По тычку в лицо соответствующий человек записывается в базу, выделяется цветом вовремя пришедшего или опаздавшего и т.д. Вторая — это СКУД от RusGuard.
Предусмотрена система синхронизации моей системы со скудом. Но работает она так: каждые N секунд уходит аякс на сервер, сервер получает данные от MS SQL на скуде за текущее число, парсит тех, кто есть в скуде, но не отмечен на странице моей системы (открытой на сенсорной панельке) и делает по ним джаваскриптовый клик.
Мне не нравится это решение.
Метод проб и ошибок привел меня к следующему решению. На сервере скуда в Конфигурации_системы-Реакции добавляем расписание от 00:00 до 23:59, например. Создаем событие, указываем типы и источники событий, во вкладке Сотрудников не забываем указать сотрудников (по умолчанию никто не стоит). Привязываем расписание к событию. Создаем действие Запуска программы. В пути прописываем путь до файла bat (русгуард только их в данном случае принимает). В корневой каталог дублирую каталог файла.
В батнике курл или вгет делает гет запрос к моей системе с указанием ключа в мд5.
У себя в шаблоне обозначаю EventSource
const eventSource = new EventSource("/sse"); eventSource.onmessage = function (event) { console.log(event['data']); if (event['data'] === 'update') { check_cart(); } }; eventSource.onopen = function (e) { console.log("Открыто соединение"); };
eventSource.onerror = function (e) { console.log(e); };
Пишем роуты для нашего события и потока.
Route::get('/sse', 'PeopleController@sse'); Route::get('/upd/{key}', 'PeopleController@scud_upd_event');
И самое кайфоное. Создаем метод для события, который запоминает в кеш необходимость обновить данные на открытой странице моей системы:
public function scud_upd_event($key) { if(md5(self::$key) === $key){ Cache::forget('update_event_cache'); Cache::put('update_event_cache', 'true', 3500); } }
И говорим, что сервак транслирует поток, реализуем в нем цикл с какой-то например задержкой, который работает до появления данных в "update_event_cache" кеша. После чего отправляем клиенту информацию о необходимости совершения аякса, который запустит клики по лицам, пикнувшимся в скуде, но не тыкнувшимся на панеле:
public function sse() { return response()->stream(function () { while (true) { usleep(1000); if (Cache::has('update_event_cache')) { Cache::forget('update_event_cache'); echo "data: " . 'update' . "\n\n"; ob_flush(); flush(); } } }, 200, [ 'Cache-Control' => 'no-cache', 'Content-Type' => 'text/event-stream', ]); }
Технология server sent events помогла нам установить постоянное соединение с сервера с клиентом, в котором клиену в реальном времени можно дослать информацию по событию, произошедшему на сервере.
Ключевые фрагменты на гитхаб