feat(voice): вход в голосовые комнаты, voice states и модерация (Фаза 3)
AGENT.md 7.14, начало Фазы 3:
- `internal/voice`: собственный подписыватель токенов LiveKit (HS256, grants
roomJoin/canPublish/canSubscribe/canPublishData) и адрес комнаты
`guild_{g}_channel_{c}` — без внешних зависимостей;
- таблица `voice_states` (миграция 00009) и store-методы: вход, флаги
(микрофон, звук, камера, экран), серверный мьют и глушение, перемещение,
выход, подсчёт участников комнаты;
- ручки: POST /channels/{id}/voice/join (проверяет CONNECT_VOICE, тип комнаты,
лимит участников и выдаёт токен), POST /channels/{id}/voice/leave,
PATCH /guilds/{id}/voice-states/@me, GET /guilds/{id}/voice-states,
PATCH /guilds/{id}/voice-states/{user_id} (MUTE_MEMBERS/DEAFEN_MEMBERS,
аудит), POST /guilds/{id}/voice-states/{user_id}/move (MOVE_MEMBERS);
- события VOICE_STATE_UPDATE всем участникам сервера, системные записи о входе
в голосовую комнату, READY отдаёт голосовые состояния серверов;
- конфиг: LIVEKIT_API_KEY/SECRET/URL приложению, публичный адрес
`LIVEKIT_PUBLIC_URL` (по умолчанию ws(s)://<домен>/rtc) в установщике и
compose; `/api/v1/meta` сообщает voice_enabled и voice_url;
- тесты: claims токена LiveKit и подпись, выключенный голос, имя комнаты, вход
и флаги, запрет мьюта без прав, перемещение и выход.
This commit is contained in:
@@ -79,6 +79,20 @@ type ReadyGuild struct {
|
||||
MyPerms []string `json:"my_permissions"`
|
||||
// Emojis — кастомные эмодзи сервера (AGENT.md 7.12).
|
||||
Emojis []ReadyEmoji `json:"emojis"`
|
||||
// VoiceStates — кто находится в голосовых комнатах (AGENT.md 7.14).
|
||||
VoiceStates []ReadyVoiceState `json:"voice_states"`
|
||||
}
|
||||
|
||||
// ReadyVoiceState — участник голосовой комнаты в снапшоте.
|
||||
type ReadyVoiceState struct {
|
||||
UserID string `json:"user_id"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
SelfMute bool `json:"self_mute"`
|
||||
SelfDeaf bool `json:"self_deaf"`
|
||||
ServerMute bool `json:"server_mute"`
|
||||
ServerDeaf bool `json:"server_deaf"`
|
||||
Camera bool `json:"camera"`
|
||||
Screen bool `json:"screen"`
|
||||
}
|
||||
|
||||
// ReadyEmoji — эмодзи сервера в снапшоте: имя, файл и токен для вставки.
|
||||
|
||||
+29
-10
@@ -128,16 +128,17 @@ func (s *Snapshot) Build(ctx context.Context, user *store.User) (*Ready, error)
|
||||
|
||||
func (s *Snapshot) buildGuild(ctx context.Context, guild store.Guild, user *store.User, resolved permissions.Resolved) (ReadyGuild, error) {
|
||||
readyGuild := ReadyGuild{
|
||||
ID: formatID(guild.ID),
|
||||
Name: guild.Name,
|
||||
OwnerID: formatID(guild.OwnerID),
|
||||
IsMain: guild.IsMain,
|
||||
Channels: []ReadyChannel{},
|
||||
Roles: []ReadyRole{},
|
||||
MemberIDs: []string{},
|
||||
MyRoles: []string{},
|
||||
MyPerms: []string{},
|
||||
Emojis: []ReadyEmoji{},
|
||||
ID: formatID(guild.ID),
|
||||
Name: guild.Name,
|
||||
OwnerID: formatID(guild.OwnerID),
|
||||
IsMain: guild.IsMain,
|
||||
Channels: []ReadyChannel{},
|
||||
Roles: []ReadyRole{},
|
||||
MemberIDs: []string{},
|
||||
MyRoles: []string{},
|
||||
MyPerms: []string{},
|
||||
Emojis: []ReadyEmoji{},
|
||||
VoiceStates: []ReadyVoiceState{},
|
||||
}
|
||||
|
||||
// Кастомные эмодзи сервера: клиент показывает их в пикере и в тексте.
|
||||
@@ -159,6 +160,24 @@ func (s *Snapshot) buildGuild(ctx context.Context, guild store.Guild, user *stor
|
||||
})
|
||||
}
|
||||
|
||||
// Кто сейчас в голосовых комнатах сервера.
|
||||
voiceStates, err := s.store.ListVoiceStates(ctx, guild.ID)
|
||||
if err != nil {
|
||||
return readyGuild, err
|
||||
}
|
||||
for _, state := range voiceStates {
|
||||
readyGuild.VoiceStates = append(readyGuild.VoiceStates, ReadyVoiceState{
|
||||
UserID: formatID(state.UserID),
|
||||
ChannelID: formatID(state.ChannelID),
|
||||
SelfMute: state.SelfMute,
|
||||
SelfDeaf: state.SelfDeaf,
|
||||
ServerMute: state.ServerMute,
|
||||
ServerDeaf: state.ServerDeaf,
|
||||
Camera: state.Camera,
|
||||
Screen: state.Screen,
|
||||
})
|
||||
}
|
||||
|
||||
roles, err := s.store.ListGuildRoles(ctx, guild.ID)
|
||||
if err != nil {
|
||||
return readyGuild, err
|
||||
|
||||
Reference in New Issue
Block a user