111 lines
3.7 KiB
Go
111 lines
3.7 KiB
Go
// Package tencentrtc contains the gateway-owned Tencent RTC token boundary.
|
|
package tencentrtc
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"hyapp/pkg/roomid"
|
|
"hyapp/pkg/tencentsig"
|
|
)
|
|
|
|
const (
|
|
// RoomIDTypeString means clients must use TRTC strRoomId, not numeric roomId.
|
|
RoomIDTypeString = "string"
|
|
// AppSceneVoiceChatRoom is the first supported RTC scene for room audio.
|
|
AppSceneVoiceChatRoom = "voice_chat_room"
|
|
// RoleAudience is the safe default; publishing audio requires a later MicUp flow.
|
|
RoleAudience = "audience"
|
|
)
|
|
|
|
// TokenConfig describes the explicit RTC application used by gateway token signing.
|
|
type TokenConfig struct {
|
|
// Enabled must be true before gateway issues RTC UserSig credentials.
|
|
Enabled bool
|
|
// SDKAppID is the Tencent RTC application ID.
|
|
SDKAppID int64
|
|
// SecretKey signs UserSig and must stay server-side.
|
|
SecretKey string
|
|
// TTL controls the RTC UserSig validity window.
|
|
TTL time.Duration
|
|
// RoomIDType is fixed to "string" in v1 to avoid TRTC roomId/strRoomId drift.
|
|
RoomIDType string
|
|
// AppScene is fixed to voice_chat_room until product introduces more RTC scenes.
|
|
AppScene string
|
|
}
|
|
|
|
// TokenResult is returned by gateway-service after room-service presence is verified.
|
|
type TokenResult struct {
|
|
SDKAppID int64 `json:"sdk_app_id"`
|
|
UserID string `json:"user_id"`
|
|
RTCUserID string `json:"rtc_user_id"`
|
|
UserSig string `json:"user_sig"`
|
|
ExpireAtMS int64 `json:"expire_at_ms"`
|
|
RoomID string `json:"room_id"`
|
|
RTCRoomID string `json:"rtc_room_id"`
|
|
RTCRoomIDType string `json:"rtc_room_id_type"`
|
|
StrRoomID string `json:"str_room_id"`
|
|
AppScene string `json:"app_scene"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
// FormatUserID converts the internal immutable user_id to Tencent RTC UserID.
|
|
func FormatUserID(userID int64) string {
|
|
// Decimal user_id matches Tencent IM identifier and keeps troubleshooting one-to-one.
|
|
return strconv.FormatInt(userID, 10)
|
|
}
|
|
|
|
// GenerateToken signs a Tencent RTC UserSig and attaches the explicit string room mapping.
|
|
func GenerateToken(cfg TokenConfig, userID int64, targetRoomID string, now time.Time) (TokenResult, error) {
|
|
if err := ValidateConfig(cfg); err != nil {
|
|
return TokenResult{}, err
|
|
}
|
|
if userID <= 0 {
|
|
// RTC UserID must always come from an authenticated internal user_id.
|
|
return TokenResult{}, fmt.Errorf("tencent rtc user_id is invalid")
|
|
}
|
|
if !roomid.ValidStringID(targetRoomID) {
|
|
// This guard protects package callers; gateway maps this case to INVALID_ARGUMENT first.
|
|
return TokenResult{}, fmt.Errorf("room_id is invalid for tencent rtc")
|
|
}
|
|
|
|
rtcUserID := FormatUserID(userID)
|
|
userSig, err := tencentsig.GenerateUserSig(tencentsig.Config{
|
|
SDKAppID: cfg.SDKAppID,
|
|
SecretKey: cfg.SecretKey,
|
|
TTL: cfg.TTL,
|
|
}, rtcUserID, now)
|
|
if err != nil {
|
|
return TokenResult{}, err
|
|
}
|
|
|
|
return TokenResult{
|
|
SDKAppID: userSig.SDKAppID,
|
|
UserID: rtcUserID,
|
|
RTCUserID: rtcUserID,
|
|
UserSig: userSig.UserSig,
|
|
ExpireAtMS: userSig.ExpireAtMS,
|
|
RoomID: targetRoomID,
|
|
RTCRoomID: targetRoomID,
|
|
RTCRoomIDType: RoomIDTypeString,
|
|
StrRoomID: targetRoomID,
|
|
AppScene: AppSceneVoiceChatRoom,
|
|
Role: RoleAudience,
|
|
}, nil
|
|
}
|
|
|
|
// ValidateConfig verifies gateway can safely sign RTC tokens before calling room-service.
|
|
func ValidateConfig(cfg TokenConfig) error {
|
|
if !cfg.Enabled || cfg.SDKAppID <= 0 || cfg.SecretKey == "" || cfg.TTL <= 0 {
|
|
// Gateway must fail closed when RTC credentials are incomplete or disabled.
|
|
return fmt.Errorf("tencent rtc token config is incomplete")
|
|
}
|
|
if cfg.RoomIDType != RoomIDTypeString || cfg.AppScene != AppSceneVoiceChatRoom {
|
|
// The first RTC version only supports TRTC strRoomId for voice chat rooms.
|
|
return fmt.Errorf("tencent rtc policy is unsupported")
|
|
}
|
|
|
|
return nil
|
|
}
|