feat(gateway): WebSocket Gateway с HELLO, IDENTIFY и READY
Реализован Gateway по AGENT.md §8.3:
- оп-коды 0/1/2/3/4/7/10/11, единый конверт {op,t,d,s};
- HELLO с интервалом сердцебиения (45 с) и идентификатором сессии;
- IDENTIFY/RESUME с проверкой токена через auth.ResolveSession;
- READY: пользователь, серверы, видимые комнаты, роли, участники и права,
собранные через движок прав (VIEW_CHANNEL-фильтрация);
- HEARTBEAT → HEARTBEAT_ACK, лимит частоты IDENTIFY (5 с);
- RESUME: буфер на 1000 событий с TTL 5 минут, догон пропущенных событий и
подтверждение RESUMED, полный READY при расхождении состояния;
- рассылка Dispatch/SendToUser с буферизацией для отключённых сессий;
- проверка Origin по allowlist доменов инстанса (AGENT.md §9.7);
- httpx.statusRecorder пробрасывает Hijack, иначе апгрейд ломается.
Тесты: 6 сценариев Gateway (READY, скрытые комнаты, неверный токен,
heartbeat, dispatch, RESUME) и 2 теста маршрута /gateway через полный стек
middleware, включая отклонение чужого Origin.
This commit is contained in:
@@ -100,6 +100,19 @@ func (c Config) Scheme() string {
|
||||
return "http"
|
||||
}
|
||||
|
||||
// AllowedOrigins возвращает домены, с которых разрешены WebSocket и
|
||||
// state-changing запросы (AGENT.md 9.7: точный allowlist, никаких *).
|
||||
func (c Config) AllowedOrigins() []string {
|
||||
origins := []string{
|
||||
"https://" + c.Domain,
|
||||
"http://" + c.Domain,
|
||||
}
|
||||
if c.FilesDomain != "" && c.FilesDomain != c.Domain {
|
||||
origins = append(origins, "https://"+c.FilesDomain, "http://"+c.FilesDomain)
|
||||
}
|
||||
return origins
|
||||
}
|
||||
|
||||
func (c Config) BaseURL() string { return c.Scheme() + "://" + c.Domain }
|
||||
func (c Config) FilesURL() string { return c.Scheme() + "://" + c.FilesDomain }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user