Перейти к содержимому
НовостиGitHubСкачать

Поток событий

GET /events на контроллере передаёт события ядра в момент, когда они происходят: панель узнаёт, что у пользователя кончилась квота, что слушатель не запустился или что обновление провайдера не удалось, не опрашивая /traffic/users, /limits/users и остальное.

Поток устроен как /logs и /traffic:

  • WebSocket, если запрос просит upgrade: одно JSON-событие в текстовом сообщении. Браузер сначала получает одноразовый билет через POST /auth/ws-ticket, затем передаёт ?ticket= при upgrade. В запрос билета включите те же фильтры событий; для каждого переподключения нужен новый билет.
  • Server-Sent Events с Accept: text/event-stream: строки event: <тип> и data: <json>.
  • JSON по строкам в остальных случаях: chunked-ответ application/x-ndjson, по событию в строке.

Маршрут закрыт secret контроллера и подчиняется правилам external-controller-cors, как и все остальные.

curl -N -H "Authorization: Bearer $SECRET" 'http://127.0.0.1:9090/events?types=user.limit,inbound.state'

?types= принимает типы через запятую; без него передаются все. На неизвестный тип ответ 400.

Каждое событие — JSON-объект с type, time (RFC 3339) и data:

{"type":"user.limit","time":"2026-10-14T12:00:00.123Z","data":{"inbound":"vless-in","user":"alice","reason":"quota","action":"closed","detail":"quota of 1000000000 bytes used up"}}
Тип Когда data
auth Отклонённая аутентификация на входящем или пользователь с нового адреса. result (success, failure), count; неудача: protocol, local, remote, reason (no_credentials, wrong_credentials, rejected_handshake, authentication_timeout); успех: inbound, user, remote; repeated, overflow (см. ниже).
user.limit Пользователь израсходовал квоту или истёк (его соединения закрываются), либо соединение отклонено по expired, quota, max-conns или max-ips. inbound, user, reason, action (closed, rejected), detail, remote (при отказе), suppressed.
user.changed Изменились пользователи входящего: через API пользователей или перезагрузкой, обновившей пользователей на месте. inbound, added, removed, changed (имена).
config.reload Конфиг применён, или новый не разобрался (PUT /configs, SIGHUP). status (ok, error), error.
provider.update Провайдер прокси или правил скачан (по интервалу, по изменению файла или через API). name, kind (proxy, rule), vehicle, status (ok, error), changed (false, если содержимое то же), error.
inbound.state Слушатель из секции listeners запустился, не смог слушать или остановлен (удалён или пересоздан перезагрузкой). inbound, type, state (started, failed, stopped), error.
chain.health Проверка здоровья группы-цепочки нашла её в другом состоянии, чем раньше: цепочка оборвалась, отказал другой узел или она снова работает. Первая проверка сообщает только об оборванной цепочке. chain, alive, failedHop, position (с 1), error.
tun.forwarding Windows, TUN с auto-route: на интерфейсе, к которому ядро привязывает свои соединения, включился Forwarding или WeakHostSend, и они возвращаются в TUN (on), или это прошло (cleared). Приходит один раз на изменение, а не при каждой проверке; см. TUN в Windows. interface (псевдоним, как его принимает Set-NetIPInterface -InterfaceAlias), family (ipv4, ipv6), forwarding, weakHostSend, state (on, cleared), reason у cleared: off (флаги выключены), not-egress (ядро больше не привязывается к интерфейсу), gone (интерфейса больше нет), stopped (TUN остановлен).
dropped Поток читался слишком медленно, и события для него потеряны; приходит раз в 5 секунд, пока это происходит, при любом фильтре. count.

Сканер не должен залить поток, поэтому события auth агрегируются окнами по 5 секунд. Первая попытка адреса клиента (порт не учитывается) с данным исходом приходит сразу с count: 1; её повторы в окне приходят одним событием с repeated: true и их count в конце окна. За окно отслеживается до 256 клиентов; попытки остальных суммируются в одно событие на исход с overflow: true.

Успех — это пользователь, у счётчика которого появился адрес, ещё не онлайн для него (адрес из max-ips), поэтому успехи сообщаются только при включённой статистике пользователей или лимитах. Не каждое соединение пользователя — событие.

Отказ user.limit сообщается не чаще раза в секунду на пользователя, как и строка лога; suppressed — число отказов между ними (все они учтены в /traffic/users).

Доставка — по возможности: у каждого потока буфер на 256 событий, и отстающий поток теряет события, а не тормозит ядро; об этом сообщает событие dropped. События, случившиеся, пока поток не был открыт, не хранятся: после переподключения прочитайте состояние из /traffic/users, /limits/users и /inbounds/{name}/users.

Без открытых потоков хуки стоят одну атомарную загрузку. В метриках есть citrus_event_subscribers, citrus_events_published_total{type} и citrus_events_dropped_total.

  • Лимиты скорости (speed-up, speed-down) формируют трафик непрерывно, у них нет момента для события.
  • Проверки здоровья прокси: их состояние есть в /proxies и в citrus_proxy_alive.