Перейти к содержимому

События ​

Всё, что происходит, пока работает задача, — шаги запуска, сообщения монитора, числа нагрузочного потока, кадры Инспектора, завершение задачи — отправляется как событие. В браузере страница сервера получает их по одному WebSocket, /api/events; скрипт может слушать тот же сокет. Настольное приложение получает те же события с теми же именами и тем же содержимым внутри себя.

Подписка ​

Откройте WebSocket на /api/events сервера:

bash
websocat -H "Authorization: Bearer $TOKEN" ws://127.0.0.1:1430/api/events
  • Аутентификация такая же, как у остального API: токен в Authorization: Bearer или cookie сессии браузера. Без неё переход отклоняется с 401 auth.required.
  • Origin: клиент, который отправляет заголовок Origin, должен отправить собственный источник сервера (хост и порт равны Host), иначе переход отклоняется с 403auth.origin. Большинство библиотек WebSocket вне браузера его не отправляют.
  • Все события каждому клиенту. Подписываться не на что: каждый сокет получает каждое событие каждой задачи, кто бы её ни начал. Нужное выбирайте по event и по job_id в содержимом.
  • Только слушать. Сервер игнорирует то, что отправляет клиент, кроме закрытия; сообщение больше 64 КиБ закрывает сокет.
  • Поддержание связи. Сервер отправляет ping каждые 20 с, поэтому молчащий сокет остаётся открытым и через прокси. Когда сервер останавливается, он закрывает все сокеты.
  • Ничего не воспроизводится заново. События, отправленные, пока клиент не был подключён, для него потеряны. Клиент, который переподключился, должен прочитать текущее состояние командами (jobs_list, inspect_snapshot, emulator_exchanges…).
  • Отставание. Для одного сокета ожидают до 4096 событий. Клиент, который отстаёт сильнее, получает server://lagged с числом пропущенных.

Формат сообщения ​

Каждое событие — одно текстовое сообщение с одним объектом JSON:

json
{ "event": "scan://open", "payload": { "job_id": 9, "ts": 1759600000123, "port": 8080, "banner": null } }
ПолеЧто это
eventКанал, см. ниже
payloadЗначения события; их состав зависит от канала

Время (ts, first_ms и last_ms пира) — миллисекунды с 1970 года; задержки и другие длительности (*_latency_ms, p50_ms…, ms) — миллисекунды. Ошибки в содержимом — объекты EngineError; их коды перечислены в сообщениях об ошибках.

Каналы ​

КаналКто отправляетКогда
experiment://stepЗапускШаг начинается, проходит, не проходит, повторяется или сообщает о нагрузке
experiment://endedЗапускОдин раз, когда запуск заканчивается сам
job://endedЛюбая задачаОдин раз, когда задача заканчивается сама или с ошибкой
osc://messageМонитор OSCКаждый пакет
osc://gen-tickГенератор OSCКаждое сообщение или от 30 до 45 раз в секунду при темпе выше 60 сообщений в секунду
http://burst-progressНагрузочный поток HTTPКаждые 100 мс и в конце
ws://stateСоединение WebSocketПодключено, закрыто
ws://messagesСоединение WebSocketКаждые 100 мс, если есть что-то новое
mqtt://stateСоединение MQTTПодключено, подписано, закрыто
mqtt://messagesСоединение MQTTКаждые 100 мс, если есть что-то новое
mqtt://ackСоединение MQTTПубликация QoS 1/2 завершена; на отписку получен ответ
broadcast://emit-statМаякКаждые 250 мс и в конце
broadcast://peersПриёмник обнаруженияКаждые 400 мс
netsim://statРеле помехКаждые 250 мс
storm://statШтормКаждые 250 мс и в конце
scan://openСканерКаждый открытый порт
scan://progressСканерПримерно на каждый 1 % диапазона и в конце
emulator://activityЗадача эмулятораКаждые 200 мс, если есть что-то новое
inspect://batchИнспекторКаждые 120 мс при новых кадрах, примерно раз в секунду в тишине, пока захват включён
server://laggedСерверКлиент отстал

experiment://step ​

Один шаг запуска: узел начинается, проходит, не проходит, ждёт повторной попытки, повторяется или сообщает о ходе нагрузки. Запуск, начатый через /api/run, отправляет те же шаги в своём ответе (см. запуски).

ПолеТипЗначение
job_idчислоЗадача запуска
tsчислоКогда
node_idстрокаУзел
stateстрокаrunning, passed, failed, retry (попытка не удалась, и шаг после паузы выполняется снова), repeating (ход повторяющегося действия, не чаще раза в секунду) или load (ход нагрузки, не чаще раза в секунду)
detailстрокаЧто произошло, по-английски; пусто для running и failed (см. error)
message_keyстрока или nullТекст интерфейса для этого — как ключ его словаря
message_paramsобъект или nullЗначения, которые называет message_key
varsобъектПеременные, которые записал шаг; пропускается, если их нет
errorEngineErrorПочему шаг не прошёл или почему не удалась попытка (retry); иначе пропускается
frameчислоКадр Инспектора для сообщения, которому соответствовало ожидание (или ожидаемый ответ на отправку), если захват был включён; иначе пропускается
loadобъектЧто измерила нагрузка, с прочитанными порогами — в последнем событии шага нагрузки, прошёл он или нет; иначе пропускается. См. нагрузку

Узел Финиш запуска показывает running, когда его достигает первая ветка, и passed, когда все ветки закончились без сбоя. Значения секретов маскируются во всех полях.

experiment://ended ​

Запуск закончился сам: он прошёл, не прошёл или вышло время. Отправляется сразу после того же содержимого в job://ended. Запуск, остановленный через job_stop или Остановить всё, не отправляет ни то, ни другое и не сохраняет отчёт.

ПолеТипЗначение
job_idчислоЗадача запуска
kindстрокаexperiment
seedчислоseed, с которым он работал
profileстрока или nullЕго профиль
overriddenлогическоеЧасть значений параметров пришла из Запустить с… или из overrides
errorEngineError или nullПервый сбой запуска; null, если он прошёл
report_pathстрока или nullЕго отчёт в runs/ папки данных
report_errorEngineError или nullПочему отчёт не удалось записать

job://ended ​

Задача закончилась сама или с ошибкой. Задача, остановленная через job_stop или jobs_stop_all, его не отправляет.

ПолеТипЗначение
job_idчислоЗадача
kindстрокаosc-monitor, osc-gen, http-burst, netsim, storm, scan, beacon, discovery, mqtt, websocket, emulator или experiment
errorEngineError или nullПочему она закончилась, если что-то пошло не так

job://ended запуска несёт и поля experiment://ended. Что заканчивает каждый вид:

kindЗаканчивается, когдаerror
osc-monitorСокет больше не может приниматьwait.receive_failed
osc-genЕё длительность вышла или отправка не удаласьnull или transport.*
http-burstДостигнут его итог или длительностьnull
stormЕго длительность вышлаnull
scanОпробован каждый порт диапазонаnull
beaconЕго круги или длительность вышли, либо больше 32 отправок не удались и ни одна не прошлаnull или transport.*
discoveryСокет больше не может приниматьwait.receive_failed
mqttБрокер закрыл соединение или оно потеряноtransport.* (transport.reset, когда соединение закрыл брокер) или mqtt.protocol
websocketСоединение закрылосьnull или почему оно потеряно
netsimРеле больше не может работатьпочему
emulatorЕго сокет вышел из строяпочему
experimentЗапуск заканчиваетсясбой запуска или null

osc://message ​

Один пакет UDP, принятый монитором OSC, расшифрованный. Отправляется для каждого пакета, без пачек.

ПолеТипЗначение
job_idчислоЗадача монитора
tsчислоКогда он пришёл
fromстрокаОтправитель, IP:port
bytesчислоРазмер пакета
messagesobject[]Каждое сообщение пакета (в бандле их несколько): address и args (OscArg[])
errorEngineError или nullosc.packet_malformed, если пакет не расшифрован (тогда messages пуст)

osc://gen-tick ​

Ход работы генератора OSC: для каждого сообщения при темпе ниже 60 сообщений в секунду; выше — для каждого n-го, где n — темп, делённый на 30 и округлённый вниз, то есть от 30 до 45 раз в секунду.

ПолеТипЗначение
job_idчислоЗадача генератора
tsчислоКогда
valueчислоТолько что отправленное значение, до округления до целого или до 32-битного числа с плавающей запятой
sentчислоСколько сообщений отправлено

http://burst-progress ​

Числа нагрузочного потока HTTP каждые 100 мс, пока он работает, и ещё раз с done: true, когда он заканчивается сам.

ПолеТипЗначение
job_idчислоЗадача потока
tsчислоКогда
sentчислоЗапросов, на которые ответили или которые завершились сбоем
okчислоИз них получили ответ со статусом 2xx
failedчислоИз них с любым другим статусом или без ответа
missedчислоЗапросы потока с заданным темпом, которые слишком долго ждали свободного исполнителя и были пропущены
rpsчислоЗапросов в секунду за последние 100 мс; в последнем событии — за весь поток
last_latency_ms, min_latency_ms, max_latency_ms, avg_latency_msчислоЗадержки на текущий момент
p50_ms, p90_ms, p95_ms, p99_msчислоПерцентили всех запросов на текущий момент, включая неудавшиеся, с точностью до 0,5 %
doneлогическоеПоследнее событие потока

ws://state ​

Соединение WebSocket, открытое через ws_connect, подключилось или закрылось. Соединение, чью задачу остановили, closed не отправляет.

ПолеТипЗначение
job_idчислоЗадача соединения
tsчислоКогда
stateстрокаconnected или closed
handshakeобъектurl, peer, local, protocol (подпротокол, который выбрал сервер, или null) и ms (подключение и переход)
closedобъект или nullПри closed: code, reason, by (client, server или lost) и error

ws://messages ​

Что соединение WebSocket отправило и приняло с прошлого события, каждые 100 мс, если есть что-то новое.

ПолеТипЗначение
job_idчислоЗадача соединения
tsчислоКогда
messagesobject[]По порядку: ts, dir (rx принято, tx отправлено), kind (text или binary), text (первые 64 КиБ в UTF-8, у двоичного сообщения тоже; байты, не являющиеся UTF-8, превращаются в �), hex (первые 4096 байт двоичного сообщения в hex, иначе null), bytes (полный размер) и truncated (показано не всё: больше 64 КиБ текста, больше 4096 байт двоичных данных)
droppedчислоСообщения, не попавшие в это событие, потому что их было больше 2000; самые старые уходят первыми

mqtt://state ​

Состояние соединения MQTT изменилось.

ПолеТипЗначение
job_idчислоЗадача соединения
tsчислоКогда
stateстрокаconnected; subscribed после каждого ответа на подписку; closed, когда соединение закончилось (но не когда остановили его задачу)
brokerстрокаhost:port
errorEngineError или nullПочему закончилось соединение с closed (transport.reset, когда его закрыл брокер); иначе null
grantsobject[]При subscribed: каждый запрошенный фильтр, с filter, qos (выданный) и accepted; иначе пусто

mqtt://messages ​

Что соединение MQTT получило с прошлого события, каждые 100 мс, если есть что-то новое. Повторно доставленное сообщение QoS 2 показывается один раз.

ПолеТипЗначение
job_idчислоЗадача соединения
tsчислоКогда
messagesobject[]ts, topic, payload (в UTF-8; байты, не являющиеся UTF-8, превращаются в �), bytes, qos, retain, dup
droppedчислоСообщения, пропущенные потому, что за 100 мс пришло больше 4000; самые старые уходят первыми

mqtt://ack ​

Брокер завершил то, о чём просило соединение.

ПолеТипЗначение
job_idчислоЗадача соединения
tsчислоКогда
kindстрокаpublished (публикация QoS 1 или 2 завершена) или unsubscribed
packet_idчислоИдентификатор пакета MQTT
topicстрока или nullОпубликованный топик; null для unsubscribed

broadcast://emit-stat ​

Счётчики маяка каждые 250 мс и ещё раз, когда он заканчивается сам, с pps равным 0.

ПолеТипЗначение
job_idчислоЗадача маяка
tsчислоКогда
targetsчислоАдресатов в каждом круге
roundsчислоОтправлено кругов
packets, bytesчислоОтправлено датаграмм и байтов
errorsчислоОтправок, которые не удались
ppsчислоДатаграмм в секунду за последние 250 мс

broadcast://peers ​

Что услышал приёмник обнаружения, каждые 400 мс.

ПолеТипЗначение
job_idчислоЗадача приёмника
tsчислоКогда
peersobject[]Недавно услышанные первыми: addr, proto, packets, bytes, first_ms, last_ms, last_summary, responded (его пакеты, на которые ответили, считая по мере прихода); не больше 512
packets, bytesчислоВсё принятое
responsesчислоОтправлено ответов

netsim://stat ​

Счётчики реле помех каждые 250 мс. Реле узлов Сетевые помехи запуска сообщают о себе в отчёте запуска.

ПолеТипЗначение
job_idчислоЗадача реле
tsчислоКогда
received, forwardedчислоДатаграммы или фрагменты на входе и на выходе
droppedчислоПотеряно из-за loss, пачек или offline (UDP; реле TCP в состоянии offline держит поток и ничего не теряет)
throttledчислоUDP: отброшено из-за ограничения полосы или потому, что в пути уже было слишком много. TCP: фрагменты, которые удерживали свой поток из-за ограничения полосы
duplicated, corrupted, reorderedчислоЧто профиль сделал с ними
bytesчислоПередано байтов
connections, reset, stalledчислоTCP: соединений принято, сброшено, оставлено полуоткрытыми; пропускается, пока 0
profileстрокаПрофиль, по которому оно вносит помехи сейчас, как его называет лента запуска: имя или то, что он делает (60 ms ±25 · loss 2%)

storm://stat ​

Счётчики шторма каждые 250 мс и ещё раз, когда он заканчивается сам, с pps и mbps равными 0.

ПолеТипЗначение
job_idчислоЗадача шторма
tsчислоКогда
packets, bytesчислоОтправлено датаграмм (или соединений TCP) и байтов
errorsчислоОтправки или соединения, которые не удались
ppsчислоВ секунду за последние 250 мс
mbpsчислоМегабит в секунду за последние 250 мс

scan://open ​

Сканер нашёл открытый порт.

ПолеТипЗначение
job_idчислоЗадача сканирования
tsчислоКогда
portчислоПорт
bannerстрока или nullЧто служба отправила первым, если баннеры запрашивались и она что-то сказала в течение 400 мс

scan://progress ​

Как далеко продвинулось сканирование: примерно на каждый 1 % диапазона и когда оно заканчивается само, с done, равным total (последнее может прийти дважды).

ПолеТипЗначение
job_idчислоЗадача сканирования
tsчислоКогда
doneчислоОпробовано портов
totalчислоПортов в диапазоне
openчислоНайдено открытых портов

emulator://activity ​

Что эмулятор, запущенный через emulator_start, принял и на что ответил с прошлого события, каждые 200 мс, если что-то изменилось (обмен, отключение или включение либо сообщение, которое брокер MQTT не смог доставить). Узлы Эмулятор запуска его не отправляют; их счётчики — в отчёте запуска.

ПолеТипЗначение
job_idчислоЗадача эмулятора
tsчислоКогда
countsобъектtotal, unmatched, failed, down, hits (по правилам) и missed (MQTT; пропускается, пока 0) — как у emulator_exchanges
forcedстрокаunavailable, reset или timeout, пока он отключён; иначе пропускается
exchangesobject[]Новые обмены, как их перечисляет emulator_exchanges, но без data; не больше 200
droppedчислоОбмены сверх первых 200 за интервал, здесь не отправленные; emulator_exchanges по-прежнему хранит последние 500

inspect://batch ​

Новые кадры Инспектора. Отправляется только пока захват включён: каждые 120 мс, если есть новые кадры, и примерно раз в секунду, если их нет, чтобы счётчики оставались актуальными.

ПолеТипЗначение
framesobject[]Новые кадры, самые старые первыми, не больше 250; без их байтов (используйте inspect_payload)
statsобъектСчётчики захвата, CaptureStats
skipped_nowчислоКадры, захваченные с прошлой пачки, но не вошедшие в эту: пришло больше 250 или буфер их отпустил. В экспорте они остаются, пока их держит буфер

server://lagged ​

Только сервер. Этот клиент отстал больше чем на 4096 событий и часть пропустил. Прочитайте состояние заново командами.

ПолеТипЗначение
skippedчислоСколько событий он пропустил