fix(realtime): события ролей, комнат и отзыв сессий без перезагрузки
Дефекты, найденные e2e-матрицей AGENT.md 11.6 (пункты 1, 2, 7, 12):
- ROLE_CREATE/ROLE_UPDATE уходили телом роли без guild_id, а клиент ждал
ссылку {guild_id, role_id} — событие отбрасывалось, роли у второго
участника не обновлялись. В rolePayload добавлено guild_id, parseRoleEvent
принимает и тело роли, и старую ссылку;
- выдача роли (MEMBER_UPDATE) и правки ролей не перечитывали список комнат,
поэтому приватная комната не появлялась в сайдбаре без F5 — теперь клиент
перечитывает комнаты по этим событиям;
- CHANNEL_CREATE/CHANNEL_UPDATE уходили телом комнаты с нулевым can_view
(права персональные), и клиент прятал комнату по этому признаку. Сервер
шлёт тело события без вычисленных прав плюс GUILD_CHANNELS_SYNC, а клиент
по событию комнаты перечитывает список;
- отзыв сессий (logout-all, смена пароля, админский сброс и «выйти везде»,
бан, удаление) не доходил до Gateway: второе устройство оставалось в
приложении. Добавлен gateway.InvalidateUser — клиент получает
INVALID_SESSION и закрывает соединение; клиент дополнительно обрабатывает
событие SESSION_INVALIDATED.
Тесты: gateway (отзыв сессий закрывает соединения и не задевает чужого),
web (событие SESSION_INVALIDATED, перечитывание комнат по CHANNEL_CREATE).
This commit is contained in:
@@ -488,6 +488,9 @@ func (s *Server) registerInstanceRoutes(api huma.API) {
|
||||
if err := s.auth.SetPassword(ctx, target.ID, password); err != nil {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
if s.gateway != nil {
|
||||
s.gateway.InvalidateUser(target.ID, "password_reset")
|
||||
}
|
||||
s.recordAudit(ctx, admin, 0, "instance.user_password_reset", "user", &target.ID, "")
|
||||
output := &adminPasswordOutput{}
|
||||
output.Body.UserID = formatSnowflake(target.ID)
|
||||
@@ -521,6 +524,9 @@ func (s *Server) registerInstanceRoutes(api huma.API) {
|
||||
if _, err := s.store.RevokeUserSessions(ctx, targetID); err != nil {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
if s.gateway != nil {
|
||||
s.gateway.InvalidateUser(targetID, "logout_all")
|
||||
}
|
||||
s.recordAudit(ctx, admin, 0, "instance.user_logout", "user", &targetID, "")
|
||||
return newOKOutput(), nil
|
||||
})
|
||||
@@ -575,7 +581,7 @@ func (s *Server) registerInstanceRoutes(api huma.API) {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
if s.gateway != nil {
|
||||
s.gateway.SendToUser(target.ID, "SESSION_INVALIDATED", map[string]any{"reason": "user_banned"})
|
||||
s.gateway.InvalidateUser(target.ID, "user_banned")
|
||||
}
|
||||
s.recordAudit(ctx, admin, 0, "instance.user_ban", "user", &target.ID, reason)
|
||||
updated, err := s.store.GetUser(ctx, target.ID)
|
||||
@@ -663,7 +669,7 @@ func (s *Server) registerInstanceRoutes(api huma.API) {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
if s.gateway != nil {
|
||||
s.gateway.SendToUser(targetID, "SESSION_INVALIDATED", map[string]any{"reason": "user_deleted"})
|
||||
s.gateway.InvalidateUser(targetID, "user_deleted")
|
||||
}
|
||||
s.recordAudit(ctx, admin, 0, "instance.user_delete", "user", &targetID, "")
|
||||
return newOKOutput(), nil
|
||||
|
||||
Reference in New Issue
Block a user