feat(dm): ручки и события звонков в беседах (Фаза 7)
Звонки 1:1 и в групповых беседах до 10 участников поверх той же голосовой
инфраструктуры LiveKit: те же токены, что у серверных комнат, но без
серверных ролей — позвонить может участник беседы.
Ручки: POST /channels/{id}/call (создание, в ответе токен и адрес
сигналинга), accept, decline, end, PATCH /call/@me для флагов микрофона,
камеры и шаринга, GET /call (текущий звонок) и GET /calls (история: кто
звонил, когда, сколько длился, кто пропустил). Постороннему — 404,
существование чужой беседы не подтверждаем; в беседе больше десяти
участников звонить нельзя (dm.call_limit); выключенный голос отвечает
voice.disabled.
События: DM_CALL_RING приходит приглашённым, DM_CALL_UPDATE — участникам
при смене состояния, DM_CALL_END — с итогом и причиной. Звонок добавлен в
READY и в карточку беседы (active_call), поэтому «идёт звонок» переживает
перезагрузку. Вебхук LiveKit разбирает комнаты dm_call_* и синхронизирует
состояние, сторож голосовых состояний закрывает гудки без ответа и
опустевшие комнаты.
Тесты: жизненный цикл 1:1, отклонение и пропущенный, отказ постороннему
на всех ручках, предел десяти участников, поведение при выключенном
голосе, события Gateway и active_call в READY.
This commit is contained in:
@@ -121,6 +121,24 @@ func ParseRoomName(room string) (guildID, channelID uint64, ok bool) {
|
||||
return guildID, channelID, true
|
||||
}
|
||||
|
||||
// CallRoomName собирает имя комнаты звонка в личной беседе. Отдельный префикс
|
||||
// нужен и вебхуку LiveKit, и сторожу: по имени комнаты видно, серверная это
|
||||
// комната или звонок в DM (AGENT.md 7.8).
|
||||
func CallRoomName(callID uint64) string {
|
||||
return fmt.Sprintf("dm_call_%d", callID)
|
||||
}
|
||||
|
||||
// ParseCallRoomName разбирает имя комнаты звонка.
|
||||
func ParseCallRoomName(room string) (callID uint64, ok bool) {
|
||||
if !strings.HasPrefix(room, "dm_call_") {
|
||||
return 0, false
|
||||
}
|
||||
if _, err := fmt.Sscanf(room, "dm_call_%d", &callID); err != nil || callID == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return callID, true
|
||||
}
|
||||
|
||||
func encodeSegment(payload []byte) string {
|
||||
return base64.RawURLEncoding.EncodeToString(payload)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user