Класс websocket
moko 17.10 21:59
Во встроенный веб-сервер парсера добавлена поддержка WebSocket (RFC 6455): двусторонний канал между браузером и скриптом по одному долгому соединению.
Когда JS делает запрос по протоколу ws://, он отправляет заголовок Upgrade: websocket. Серверный код при наличии заголовка принимает соединение и работает в цикле, пока оно открыто. Один запрос на всё соединение: конфигурация и auto.p выполняются один раз, состояние можно хранить в обычных переменных. Примерный код:
@main[]
^if($env:HTTP_UPGRADE eq websocket){
^websocket:accept[]
^while(true){
$message[^websocket:receive(30)]
^if($message is hash){
^if($message.type eq close){^break[]}
$response[^answer[$message]]
^websocket:send[$response]
}
}
}{
... страница с JS ...
}Со стороны браузера:
const ws = new WebSocket('ws://' + location.host + '/');
ws.onopen = () => ws.send('привет');
ws.onmessage = (e) => console.log(e.data);Класс websocket статический, доступные методы:
- ^websocket:accept[] - принять соединение. Поля $response:, заданные до этого, уходят вместе с заголовками websocket.
- ^websocket:receive(секунды) - ждёт сообщение не дольше таймаута. Если ничего не пришло, вернёт void, иначе hash: $.type[text|binary|close], $.data (для binary это файл) и для close ещё
поле $.code. Ping/pong и фрагментацию парсер обрабатывает сам.
- ^websocket:send[строка или файл] - строка уходит текстовым сообщением, файл бинарным.
- ^websocket:ping[], ^websocket:ping[данные].
- ^websocket:close[], ^websocket:close(код), ^websocket:close(код;причина).
Подробности:
- Текст по сети идёт в UTF-8. Строки при отправке обрабатываются как обычный вывод, в httpd по умолчанию как html, таким образом ^websocket:send[$form:name] экранирует опасные символы.
- Размер сообщения ограничен $LIMITS.post_max_size (по умолчанию 10 МБ, как у POST). Большее сообщение закрывает соединение с кодом 1009.
- Закрытая вкладка приходит как $.type[close] с кодом 1001, обрыв связи без закрытия с кодом 1006.
- После @main парсер сам корректно закрывает соединение: шлёт Close и ждёт ответ клиента не дольше $HTTPD.timeout.
- При проксировании через nginx нужно передавать заголовки Upgrade и Connection (proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";).
В тесты добавлено
демонстрационное приложение, страница и серверная часть в одном файле. Запуск через run_server.sh, затем надо открыть
http://localhost:8100/ в браузере. Сервер 20 раз в секунду присылает свой статус (время, CPU, память, номер сообщения). Дополнительно есть эхо, ping/pong, отправка бинарных данных и закрытие. Можно открыть несколько вкладок.
Как обычно, уже доступно в
ночных сборках.
- Класс websocket, moko [M] 17.10 21:59