rtc
This commit is contained in:
parent
1d2961c09a
commit
3bbaa78528
@ -46,6 +46,8 @@ red-circle:
|
||||
endpoint: ${LIKEI_TRTC_ENDPOINT}
|
||||
region: ${LIKEI_TRTC_REGION:ap-singapore}
|
||||
sdkAppId: ${LIKEI_TRTC_SDK_APP_ID}
|
||||
userSigKey: ${LIKEI_TRTC_USER_SIG_KEY:${LIKEI_TRTC_SECRET_KEY}}
|
||||
userSigExpireSeconds: ${LIKEI_TRTC_USER_SIG_EXPIRE_SECOND:7200}
|
||||
tencet-im:
|
||||
appId: ${LIKEI_IM_APP_ID}
|
||||
key: ${LIKEI_IM_KEY}
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
package com.red.circle.common.business.dto.rtc;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* RTC credential returned to compatible clients.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RtcCredentialCO extends ClientObject {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* AGORA or TRTC.
|
||||
*/
|
||||
private String rtcProvider;
|
||||
|
||||
/**
|
||||
* Legacy Agora token.
|
||||
*/
|
||||
private String agoraToken;
|
||||
|
||||
/**
|
||||
* Agora channel name, currently the business room id.
|
||||
*/
|
||||
private String agoraChannelName;
|
||||
|
||||
/**
|
||||
* Tencent TRTC sdkAppId.
|
||||
*/
|
||||
private Long trtcSdkAppId;
|
||||
|
||||
/**
|
||||
* TRTC user id. Use business userId string.
|
||||
*/
|
||||
private String trtcUserId;
|
||||
|
||||
/**
|
||||
* TRTC UserSig.
|
||||
*/
|
||||
private String trtcUserSig;
|
||||
|
||||
/**
|
||||
* Numeric TRTC room id when available.
|
||||
*/
|
||||
private Long trtcRoomId;
|
||||
|
||||
/**
|
||||
* String TRTC room id fallback.
|
||||
*/
|
||||
private String trtcStrRoomId;
|
||||
|
||||
/**
|
||||
* TRTC role: 20 anchor, 21 audience.
|
||||
*/
|
||||
private Integer trtcRole;
|
||||
|
||||
/**
|
||||
* UserSig lifetime in seconds.
|
||||
*/
|
||||
private Long trtcUserSigExpireSeconds;
|
||||
|
||||
/**
|
||||
* UserSig expire timestamp in milliseconds.
|
||||
*/
|
||||
private Long trtcUserSigExpireAt;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.red.circle.common.business.dto.rtc;
|
||||
|
||||
/**
|
||||
* RTC provider used by voice rooms.
|
||||
*/
|
||||
public enum RtcProviderEnum {
|
||||
AGORA,
|
||||
TRTC;
|
||||
|
||||
public static RtcProviderEnum of(String provider) {
|
||||
if (provider == null || provider.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
for (RtcProviderEnum value : values()) {
|
||||
if (value.name().equalsIgnoreCase(provider.trim())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.red.circle.common.business.dto.rtc;
|
||||
|
||||
/**
|
||||
* Version based RTC compatibility rules.
|
||||
*/
|
||||
public final class RtcVersionSupport {
|
||||
|
||||
public static final String TRTC_MIN_VERSION = "1.4.0";
|
||||
public static final String ROOM_PROVIDER_KEY_PREFIX = "RTC:ROOM:PROVIDER:";
|
||||
public static final long ROOM_PROVIDER_TTL_SECONDS = 12 * 60 * 60L;
|
||||
|
||||
private RtcVersionSupport() {
|
||||
}
|
||||
|
||||
public static RtcProviderEnum defaultProvider(String version) {
|
||||
return compareVersion(version, TRTC_MIN_VERSION) <= 0
|
||||
? RtcProviderEnum.AGORA
|
||||
: RtcProviderEnum.TRTC;
|
||||
}
|
||||
|
||||
public static String roomProviderKey(Object roomId) {
|
||||
return ROOM_PROVIDER_KEY_PREFIX + roomId;
|
||||
}
|
||||
|
||||
public static int compareVersion(String left, String right) {
|
||||
int[] leftParts = parseVersion(left);
|
||||
int[] rightParts = parseVersion(right);
|
||||
int length = Math.max(leftParts.length, rightParts.length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int leftPart = i < leftParts.length ? leftParts[i] : 0;
|
||||
int rightPart = i < rightParts.length ? rightParts[i] : 0;
|
||||
if (leftPart != rightPart) {
|
||||
return Integer.compare(leftPart, rightPart);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int[] parseVersion(String version) {
|
||||
if (version == null || version.isBlank()) {
|
||||
return new int[]{0};
|
||||
}
|
||||
String normalized = version.trim().split("-", 2)[0];
|
||||
String[] parts = normalized.split("\\.");
|
||||
int[] values = new int[parts.length];
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
values[i] = parseVersionPart(parts[i]);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private static int parseVersionPart(String part) {
|
||||
if (part == null || part.isBlank()) {
|
||||
return 0;
|
||||
}
|
||||
String digits = part.replaceAll("[^0-9].*$", "");
|
||||
if (digits.isBlank()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(digits);
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
package com.red.circle.external.inner.endpoint.message.api;
|
||||
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
package com.red.circle.external.inner.endpoint.message.api;
|
||||
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -50,10 +51,20 @@ public interface TrtcClientApi {
|
||||
@RequestParam("type") String channelName
|
||||
);
|
||||
|
||||
@GetMapping("/createAgoraTokenGoUp")
|
||||
ResultResponse<String> createAgoraTokenGoUp(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("type") String channelName
|
||||
);
|
||||
|
||||
}
|
||||
@GetMapping("/createAgoraTokenGoUp")
|
||||
ResultResponse<String> createAgoraTokenGoUp(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("type") String channelName
|
||||
);
|
||||
|
||||
/**
|
||||
* 创建 TRTC 入房凭证.
|
||||
*/
|
||||
@GetMapping("/createTrtcCredential")
|
||||
ResultResponse<RtcCredentialCO> createTrtcCredential(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("roomIdentifier") String roomIdentifier,
|
||||
@RequestParam(value = "publisher", required = false) Boolean publisher
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
package com.red.circle.external.adapter.app.imtrtc;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.red.circle.auth.inner.endpoint.AuthClient;
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.component.instant.msg.agora.AgoraAuthentication;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImAccountManagerService;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupAvManagerService;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
||||
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult;
|
||||
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult.OnlineStatus;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.red.circle.auth.inner.endpoint.AuthClient;
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||
import com.red.circle.common.business.dto.rtc.RtcVersionSupport;
|
||||
import com.red.circle.component.instant.msg.InstantMessageProperties;
|
||||
import com.red.circle.component.instant.msg.agora.AgoraAuthentication;
|
||||
import com.red.circle.component.instant.msg.tencet.props.TrtcTencetProperties;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImAccountManagerService;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupAvManagerService;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
||||
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult;
|
||||
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult.OnlineStatus;
|
||||
import com.red.circle.component.redis.service.RedisService;
|
||||
import com.red.circle.external.clienobject.TmpSigCO;
|
||||
import com.red.circle.external.cmd.imtrtc.ImRoomRemoveUserCmd;
|
||||
import com.red.circle.external.infra.database.redis.service.UserAgoraTokenCacheService;
|
||||
@ -23,13 +29,15 @@ import com.red.circle.framework.web.controller.BaseController;
|
||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||
import com.red.circle.tool.core.regex.RegexConstant;
|
||||
import com.red.circle.tool.core.text.StringPool;
|
||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import com.tencentyun.TLSSigAPIv2;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.agora.media.RtcTokenBuilder2;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -41,8 +49,9 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* IM操作.
|
||||
@ -62,14 +71,22 @@ public class ImRestController extends BaseController {
|
||||
private final UserProfileClient userProfileClient;
|
||||
private final TencentTrtcService tencentTrtcService;
|
||||
private final AgoraAuthentication agoraAuthentication;
|
||||
private final ImGroupAvManagerService imGroupAvManagerService;
|
||||
private final ImAccountManagerService imAccountManagerService;
|
||||
private final UserAgoraTokenCacheService userAgoraTokenCacheService;
|
||||
|
||||
@Value("${rtc.appId}")
|
||||
private String appId;
|
||||
@Value("${rtc.certificate}")
|
||||
private String certificate;
|
||||
private final ImGroupAvManagerService imGroupAvManagerService;
|
||||
private final ImAccountManagerService imAccountManagerService;
|
||||
private final UserAgoraTokenCacheService userAgoraTokenCacheService;
|
||||
private final RedisService redisService;
|
||||
private final InstantMessageProperties instantMessageProperties;
|
||||
|
||||
@Value("${rtc.appId}")
|
||||
private String appId;
|
||||
@Value("${rtc.certificate}")
|
||||
private String certificate;
|
||||
|
||||
@Value("${red-circle.instant-message.tencet-trtc.userSigExpireSeconds:7200}")
|
||||
private long trtcUserSigExpireSeconds;
|
||||
|
||||
@Value("${red-circle.instant-message.tencet-trtc.userSigKey:${red-circle.instant-message.tencet-trtc.secretKey:}}")
|
||||
private String trtcUserSigKey;
|
||||
|
||||
/**
|
||||
* 认证签名(腾讯).
|
||||
@ -127,13 +144,16 @@ public class ImRestController extends BaseController {
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/tmp/agora/sig")
|
||||
public TmpSigCO userSig(Long userId, String channelName,Boolean isPublisher) {
|
||||
log.warn("/tmp/agora/sig {}, {}, {}", userId, channelName, isPublisher);
|
||||
if (isPublisher == null){
|
||||
isPublisher = false;
|
||||
}
|
||||
String token;
|
||||
@GetMapping("/tmp/agora/sig")
|
||||
public TmpSigCO userSig(AppExtCommand cmd, Long userId, String channelName, Boolean isPublisher) {
|
||||
log.warn("/tmp/agora/sig {}, {}, {}", userId, channelName, isPublisher);
|
||||
if (isPublisher == null){
|
||||
isPublisher = false;
|
||||
}
|
||||
RtcProviderEnum provider = resolveRoomProvider(channelName, currentVersion(cmd));
|
||||
ResponseAssert.isTrue(CommonErrorCode.UPGRADE_VERSION,
|
||||
!Objects.equals(RtcProviderEnum.TRTC, provider));
|
||||
String token;
|
||||
if (isPublisher){
|
||||
token = userAgoraTokenCacheService.getUserAgoraToken(userId, Long.valueOf(channelName));
|
||||
} else {
|
||||
@ -156,36 +176,160 @@ public class ImRestController extends BaseController {
|
||||
|
||||
if (Objects.nonNull(json)) {
|
||||
return getTmpSigByUserCredential(userId, token, json, gson);
|
||||
} else {
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户信息获取用户Servicetoken
|
||||
} else {
|
||||
RtcCredentialCO credential = createAgoraCredential(channelName, token);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setRtcCredential(credential)
|
||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* RTC 凭证,支持按客户端版本和房间级 provider 在 Agora/TRTC 间分流.
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @param roomId 业务房间id,作为房间级 provider 缓存 key
|
||||
* @param channelName 历史 Agora channel,可为空
|
||||
* @param roomAccount TRTC 房间号,优先使用
|
||||
* @param isPublisher 是否主播/上麦
|
||||
*/
|
||||
@GetMapping("/tmp/rtc/sig")
|
||||
public TmpSigCO rtcSig(
|
||||
AppExtCommand cmd,
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam(value = "roomId", required = false) Long roomId,
|
||||
@RequestParam(value = "channelName", required = false) String channelName,
|
||||
@RequestParam(value = "roomAccount", required = false) String roomAccount,
|
||||
@RequestParam(value = "isPublisher", required = false) Boolean isPublisher) {
|
||||
String providerRoomKey = Objects.nonNull(roomId) ? roomId.toString() : channelName;
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
StringUtils.hasText(providerRoomKey));
|
||||
|
||||
RtcProviderEnum provider = resolveRoomProvider(providerRoomKey, currentVersion(cmd));
|
||||
boolean publisher = Boolean.TRUE.equals(isPublisher);
|
||||
if (Objects.equals(RtcProviderEnum.AGORA, provider)) {
|
||||
String agoraChannelName = StringUtils.hasText(channelName) ? channelName : providerRoomKey;
|
||||
String token = publisher
|
||||
? createChannelPublisherToken(agoraChannelName, userId)
|
||||
: createChannelSubscriberToken(agoraChannelName, userId);
|
||||
RtcCredentialCO credential = createAgoraCredential(agoraChannelName, token);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setRtcCredential(credential)
|
||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||
}
|
||||
|
||||
String trtcRoomIdentifier = firstText(roomAccount, channelName, providerRoomKey);
|
||||
RtcCredentialCO credential = createTrtcCredential(userId, trtcRoomIdentifier, publisher);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(credential.getTrtcUserSig())
|
||||
.setRtcProvider(RtcProviderEnum.TRTC.name())
|
||||
.setRtcCredential(credential)
|
||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户信息获取用户Servicetoken
|
||||
*
|
||||
* @param userId
|
||||
* @param token
|
||||
* @param json
|
||||
* @param gson
|
||||
* @return
|
||||
*/
|
||||
private TmpSigCO getTmpSigByUserCredential(Long userId, String token, String json, Gson gson) {
|
||||
try {
|
||||
UserCredential userCredential = gson.fromJson(json, UserCredential.class);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setNewServiceToken(userCredential.token());
|
||||
} catch (JsonSyntaxException e) {
|
||||
log.error("/tmp/agora/sig类型转换错误", e);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||
}
|
||||
}
|
||||
* @return
|
||||
*/
|
||||
private TmpSigCO getTmpSigByUserCredential(Long userId, String token, String json, Gson gson) {
|
||||
RtcCredentialCO credential = createAgoraCredential(null, token);
|
||||
try {
|
||||
UserCredential userCredential = gson.fromJson(json, UserCredential.class);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setRtcCredential(credential)
|
||||
.setNewServiceToken(userCredential.token());
|
||||
} catch (JsonSyntaxException e) {
|
||||
log.error("/tmp/agora/sig类型转换错误", e);
|
||||
return new TmpSigCO()
|
||||
.setRtcToken(token)
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setRtcCredential(credential)
|
||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||
}
|
||||
}
|
||||
|
||||
private RtcProviderEnum resolveRoomProvider(String roomKey, String version) {
|
||||
if (!StringUtils.hasText(roomKey)) {
|
||||
return RtcVersionSupport.defaultProvider(version);
|
||||
}
|
||||
String cacheKey = RtcVersionSupport.roomProviderKey(roomKey.trim());
|
||||
RtcProviderEnum cached = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||
if (Objects.nonNull(cached)) {
|
||||
return cached;
|
||||
}
|
||||
RtcProviderEnum provider = RtcVersionSupport.defaultProvider(version);
|
||||
redisService.setIfAbsent(cacheKey, provider.name(),
|
||||
RtcVersionSupport.ROOM_PROVIDER_TTL_SECONDS, TimeUnit.SECONDS);
|
||||
RtcProviderEnum resolved = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||
return Objects.nonNull(resolved) ? resolved : provider;
|
||||
}
|
||||
|
||||
private String currentVersion(AppExtCommand cmd) {
|
||||
return Optional.ofNullable(cmd)
|
||||
.map(AppExtCommand::getReqAppIntel)
|
||||
.map(reqAppIntel -> reqAppIntel.getVersion())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private RtcCredentialCO createAgoraCredential(String channelName, String token) {
|
||||
return new RtcCredentialCO()
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setAgoraChannelName(channelName)
|
||||
.setAgoraToken(token);
|
||||
}
|
||||
|
||||
private RtcCredentialCO createTrtcCredential(Long userId, String roomIdentifier,
|
||||
boolean publisher) {
|
||||
TrtcTencetProperties trtcProperties = instantMessageProperties.getTencetTrtc();
|
||||
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties);
|
||||
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties.getSdkAppId());
|
||||
ResponseAssert.isTrue(CommonErrorCode.CONFIGURATION_ERROR, StringUtils.hasText(trtcUserSigKey));
|
||||
|
||||
String trtcUserId = userId.toString();
|
||||
String userSig = new TLSSigAPIv2(trtcProperties.getSdkAppId(), trtcUserSigKey)
|
||||
.genUserSig(trtcUserId, trtcUserSigExpireSeconds);
|
||||
RtcCredentialCO credential = new RtcCredentialCO()
|
||||
.setRtcProvider(RtcProviderEnum.TRTC.name())
|
||||
.setTrtcSdkAppId(trtcProperties.getSdkAppId())
|
||||
.setTrtcUserId(trtcUserId)
|
||||
.setTrtcUserSig(userSig)
|
||||
.setTrtcRole(publisher ? 20 : 21)
|
||||
.setTrtcUserSigExpireSeconds(trtcUserSigExpireSeconds)
|
||||
.setTrtcUserSigExpireAt(
|
||||
System.currentTimeMillis() + trtcUserSigExpireSeconds * 1000L);
|
||||
applyTrtcRoomIdentifier(credential, roomIdentifier);
|
||||
return credential;
|
||||
}
|
||||
|
||||
private void applyTrtcRoomIdentifier(RtcCredentialCO credential, String roomIdentifier) {
|
||||
String normalizedRoomIdentifier = roomIdentifier.trim();
|
||||
try {
|
||||
credential.setTrtcRoomId(Long.valueOf(normalizedRoomIdentifier));
|
||||
} catch (NumberFormatException ignored) {
|
||||
credential.setTrtcStrRoomId(normalizedRoomIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
private String firstText(String... values) {
|
||||
for (String value : values) {
|
||||
if (StringUtils.hasText(value)) {
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
package com.red.circle.external.clienobject;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
package com.red.circle.external.clienobject;
|
||||
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 临时签名(兼容服务).
|
||||
@ -20,8 +21,18 @@ public class TmpSigCO extends ClientObject {
|
||||
*/
|
||||
private String rtcToken;
|
||||
|
||||
/**
|
||||
* 新服务token.
|
||||
*/
|
||||
private String newServiceToken;
|
||||
}
|
||||
/**
|
||||
* 新服务token.
|
||||
*/
|
||||
private String newServiceToken;
|
||||
|
||||
/**
|
||||
* RTC provider: AGORA or TRTC.
|
||||
*/
|
||||
private String rtcProvider;
|
||||
|
||||
/**
|
||||
* Provider specific credential.
|
||||
*/
|
||||
private RtcCredentialCO rtcCredential;
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package com.red.circle.external.inner.endpoint.message;
|
||||
|
||||
import com.red.circle.external.inner.endpoint.message.api.TrtcClientApi;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
package com.red.circle.external.inner.endpoint.message;
|
||||
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.external.inner.endpoint.message.api.TrtcClientApi;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
import com.red.circle.external.inner.service.message.TrtcClientService;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -45,8 +46,15 @@ public class TrtcClientEndpoint implements TrtcClientApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<String> createAgoraTokenGoUp(Long userId, String channelName) {
|
||||
return ResultResponse.success(trtcClientService.createAgoraTokenGoUp(userId, channelName));
|
||||
}
|
||||
|
||||
}
|
||||
public ResultResponse<String> createAgoraTokenGoUp(Long userId, String channelName) {
|
||||
return ResultResponse.success(trtcClientService.createAgoraTokenGoUp(userId, channelName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<RtcCredentialCO> createTrtcCredential(Long userId, String roomIdentifier,
|
||||
Boolean publisher) {
|
||||
return ResultResponse.success(
|
||||
trtcClientService.createTrtcCredential(userId, roomIdentifier, publisher));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package com.red.circle.external.inner.service.message;
|
||||
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
package com.red.circle.external.inner.service.message;
|
||||
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
|
||||
/**
|
||||
* trtc 服务.
|
||||
@ -33,8 +34,13 @@ public interface TrtcClientService {
|
||||
/**
|
||||
* 创建声网令牌.
|
||||
*/
|
||||
String createAgoraToken(Long userId, String channelName);
|
||||
|
||||
String createAgoraTokenGoUp(Long userId, String channelName);
|
||||
|
||||
}
|
||||
String createAgoraToken(Long userId, String channelName);
|
||||
|
||||
String createAgoraTokenGoUp(Long userId, String channelName);
|
||||
|
||||
/**
|
||||
* 创建 TRTC 入房凭证.
|
||||
*/
|
||||
RtcCredentialCO createTrtcCredential(Long userId, String roomIdentifier, Boolean publisher);
|
||||
|
||||
}
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
package com.red.circle.external.inner.service.message.impl;
|
||||
|
||||
import com.red.circle.component.instant.msg.agora.AgoraAuthentication;
|
||||
import com.red.circle.component.instant.msg.agora.AgoraProperties;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
import com.red.circle.external.inner.service.message.TrtcClientService;
|
||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import io.agora.media.RtcTokenBuilder2;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
package com.red.circle.external.inner.service.message.impl;
|
||||
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||
import com.red.circle.component.instant.msg.InstantMessageProperties;
|
||||
import com.red.circle.component.instant.msg.tencet.props.TrtcTencetProperties;
|
||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||
import com.red.circle.external.inner.service.message.TrtcClientService;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import com.tencentyun.TLSSigAPIv2;
|
||||
import io.agora.media.RtcTokenBuilder2;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* trtc 服务.
|
||||
@ -22,17 +28,22 @@ import org.springframework.stereotype.Service;
|
||||
@RequiredArgsConstructor
|
||||
public class TrtcClientServiceImpl implements TrtcClientService {
|
||||
|
||||
private final UserProfileClient userProfileClient;
|
||||
private final TencentTrtcService tencentTrtcService;
|
||||
// private final AgoraAuthentication agoraAuthentication;
|
||||
// private final AgoraProperties agoraProperties;
|
||||
|
||||
@Value("${rtc.appId}")
|
||||
private String appId;
|
||||
|
||||
@Value("${rtc.certificate}")
|
||||
private String certificate;
|
||||
|
||||
private final UserProfileClient userProfileClient;
|
||||
private final TencentTrtcService tencentTrtcService;
|
||||
private final InstantMessageProperties instantMessageProperties;
|
||||
|
||||
@Value("${rtc.appId}")
|
||||
private String appId;
|
||||
|
||||
@Value("${rtc.certificate}")
|
||||
private String certificate;
|
||||
|
||||
@Value("${red-circle.instant-message.tencet-trtc.userSigExpireSeconds:7200}")
|
||||
private long trtcUserSigExpireSeconds;
|
||||
|
||||
@Value("${red-circle.instant-message.tencet-trtc.userSigKey:${red-circle.instant-message.tencet-trtc.secretKey:}}")
|
||||
private String trtcUserSigKey;
|
||||
|
||||
@Override
|
||||
public boolean removeUser(TrtcRemoveUserCmd cmd) {
|
||||
return tencentTrtcService.removeUser(cmd.getRoomId(),
|
||||
@ -61,10 +72,50 @@ public class TrtcClientServiceImpl implements TrtcClientService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createAgoraTokenGoUp(Long userId, String channelName) {
|
||||
UserProfileDTO userProfile = userProfileClient.getByUserId(userId).getBody();
|
||||
RtcTokenBuilder2 var3 = new RtcTokenBuilder2();
|
||||
return var3.buildTokenWithUid(appId, certificate, channelName, Integer.parseInt(userProfile.getAccount()), RtcTokenBuilder2.Role.ROLE_PUBLISHER, 21600, 21600);
|
||||
}
|
||||
|
||||
}
|
||||
public String createAgoraTokenGoUp(Long userId, String channelName) {
|
||||
UserProfileDTO userProfile = userProfileClient.getByUserId(userId).getBody();
|
||||
RtcTokenBuilder2 var3 = new RtcTokenBuilder2();
|
||||
return var3.buildTokenWithUid(appId, certificate, channelName, Integer.parseInt(userProfile.getAccount()), RtcTokenBuilder2.Role.ROLE_PUBLISHER, 21600, 21600);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtcCredentialCO createTrtcCredential(Long userId, String roomIdentifier,
|
||||
Boolean publisher) {
|
||||
ResponseAssert.notNull(CommonErrorCode.REQUIRED_FIELDS_CANNOT_BE_IGNORED, userId);
|
||||
ResponseAssert.isTrue(CommonErrorCode.REQUIRED_FIELDS_CANNOT_BE_IGNORED,
|
||||
StringUtils.hasText(roomIdentifier));
|
||||
|
||||
TrtcTencetProperties trtcProperties = instantMessageProperties.getTencetTrtc();
|
||||
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties);
|
||||
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties.getSdkAppId());
|
||||
ResponseAssert.isTrue(CommonErrorCode.CONFIGURATION_ERROR, StringUtils.hasText(trtcUserSigKey));
|
||||
|
||||
String trtcUserId = userId.toString();
|
||||
String userSig = new TLSSigAPIv2(
|
||||
trtcProperties.getSdkAppId(),
|
||||
trtcUserSigKey
|
||||
).genUserSig(trtcUserId, trtcUserSigExpireSeconds);
|
||||
|
||||
RtcCredentialCO credential = new RtcCredentialCO()
|
||||
.setRtcProvider(RtcProviderEnum.TRTC.name())
|
||||
.setTrtcSdkAppId(trtcProperties.getSdkAppId())
|
||||
.setTrtcUserId(trtcUserId)
|
||||
.setTrtcUserSig(userSig)
|
||||
.setTrtcRole(Boolean.TRUE.equals(publisher) ? 20 : 21)
|
||||
.setTrtcUserSigExpireSeconds(trtcUserSigExpireSeconds)
|
||||
.setTrtcUserSigExpireAt(
|
||||
System.currentTimeMillis() + trtcUserSigExpireSeconds * 1000L);
|
||||
applyTrtcRoomIdentifier(credential, roomIdentifier);
|
||||
return credential;
|
||||
}
|
||||
|
||||
private void applyTrtcRoomIdentifier(RtcCredentialCO credential, String roomIdentifier) {
|
||||
String normalizedRoomIdentifier = roomIdentifier.trim();
|
||||
try {
|
||||
credential.setTrtcRoomId(Long.valueOf(normalizedRoomIdentifier));
|
||||
} catch (NumberFormatException ignored) {
|
||||
credential.setTrtcStrRoomId(normalizedRoomIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package com.red.circle.live.app.command.mic;
|
||||
|
||||
import com.red.circle.component.redis.service.RedisService;
|
||||
package com.red.circle.live.app.command.mic;
|
||||
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||
import com.red.circle.common.business.dto.rtc.RtcVersionSupport;
|
||||
import com.red.circle.component.redis.service.RedisService;
|
||||
import com.red.circle.external.inner.endpoint.message.TrtcClient;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||
@ -29,7 +32,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@ -52,16 +56,25 @@ public class LiveMicGoUpCmdExe {
|
||||
private final RedisService redisService;
|
||||
private final RoomDailyTaskClient roomDailyTaskClient;
|
||||
private final RoomManagerClient roomManagerClient;
|
||||
private final RedisTemplate redisTemplate;
|
||||
private final RoomMemberClient roomMemberClient;
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
private final RoomMemberClient roomMemberClient;
|
||||
|
||||
public LiveMicrophoneCO execute(MicUpDownCmd cmd) {
|
||||
boolean targetMicAlreadySelf = false;
|
||||
boolean goUpCompleted = false;
|
||||
RtcProviderEnum rtcProvider = null;
|
||||
try {
|
||||
checkPermissions(cmd);
|
||||
targetMicAlreadySelf = checkTargetMicAvailableOrSelf(cmd);
|
||||
String roomToken = createPublisherToken(cmd);
|
||||
rtcProvider = resolveRoomProvider(cmd);
|
||||
String roomToken = null;
|
||||
RtcCredentialCO rtcCredential;
|
||||
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||
roomToken = createPublisherToken(cmd);
|
||||
rtcCredential = createAgoraCredential(cmd, roomToken);
|
||||
} else {
|
||||
rtcCredential = createTrtcCredential(cmd, true);
|
||||
}
|
||||
|
||||
LiveMicrophoneNoticeDTO noticeDTO = liveMicrophoneGateway.goUp(
|
||||
cmd.getRoomId(),
|
||||
@ -70,16 +83,22 @@ public class LiveMicGoUpCmdExe {
|
||||
);
|
||||
goUpCompleted = true;
|
||||
|
||||
cachePublisherToken(cmd, roomToken);
|
||||
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||
cachePublisherToken(cmd, roomToken);
|
||||
}
|
||||
LiveMicrophoneCO notice = returnMicrophoneCO(cmd, noticeDTO);
|
||||
notice.setRoomToken(roomToken);
|
||||
notice.setRoomToken(roomToken)
|
||||
.setRtcProvider(rtcProvider.name())
|
||||
.setRtcCredential(rtcCredential);
|
||||
|
||||
// 房主邀请成员上麦
|
||||
handleRoomDailyTask(cmd);
|
||||
return notice;
|
||||
} catch (RuntimeException e) {
|
||||
if (goUpCompleted) {
|
||||
rollbackPublisherToken(cmd);
|
||||
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||
rollbackPublisherToken(cmd);
|
||||
}
|
||||
if (!targetMicAlreadySelf) {
|
||||
rollbackMicSeat(cmd, e);
|
||||
}
|
||||
@ -103,6 +122,60 @@ public class LiveMicGoUpCmdExe {
|
||||
userAgoraTokenCacheService.save(roomToken, cmd.requiredReqUserId(), cmd.getRoomId());
|
||||
}
|
||||
|
||||
private RtcProviderEnum resolveRoomProvider(MicUpDownCmd cmd) {
|
||||
if (Objects.isNull(redisService)) {
|
||||
return RtcVersionSupport.defaultProvider(currentVersion(cmd));
|
||||
}
|
||||
String cacheKey = RtcVersionSupport.roomProviderKey(cmd.getRoomId());
|
||||
RtcProviderEnum requestedProvider = RtcVersionSupport.defaultProvider(currentVersion(cmd));
|
||||
RtcProviderEnum cachedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||
if (Objects.nonNull(cachedProvider)) {
|
||||
ResponseAssert.isTrue(CommonErrorCode.UPGRADE_VERSION,
|
||||
!Objects.equals(RtcProviderEnum.AGORA, requestedProvider)
|
||||
|| !Objects.equals(RtcProviderEnum.TRTC, cachedProvider));
|
||||
return cachedProvider;
|
||||
}
|
||||
redisService.setIfAbsent(cacheKey, requestedProvider.name(),
|
||||
RtcVersionSupport.ROOM_PROVIDER_TTL_SECONDS, TimeUnit.SECONDS);
|
||||
RtcProviderEnum resolvedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||
return Objects.nonNull(resolvedProvider) ? resolvedProvider : requestedProvider;
|
||||
}
|
||||
|
||||
private String currentVersion(MicUpDownCmd cmd) {
|
||||
return Optional.ofNullable(cmd)
|
||||
.map(MicUpDownCmd::getReqAppIntel)
|
||||
.map(reqAppIntel -> reqAppIntel.getVersion())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private RtcCredentialCO createAgoraCredential(MicUpDownCmd cmd, String token) {
|
||||
return new RtcCredentialCO()
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setAgoraChannelName(cmd.getRoomId().toString())
|
||||
.setAgoraToken(token);
|
||||
}
|
||||
|
||||
private RtcCredentialCO createTrtcCredential(MicUpDownCmd cmd, boolean publisher) {
|
||||
ResultResponse<RtcCredentialCO> response = trtcClient.createTrtcCredential(
|
||||
cmd.requiredReqUserId(),
|
||||
resolveTrtcRoomIdentifier(cmd),
|
||||
publisher
|
||||
);
|
||||
RtcCredentialCO credential = Objects.nonNull(response) ? response.getBody() : null;
|
||||
ResponseAssert.notNull(CommonErrorCode.THIRD_PARTY_SERVER_ERROR, credential);
|
||||
return credential;
|
||||
}
|
||||
|
||||
private String resolveTrtcRoomIdentifier(MicUpDownCmd cmd) {
|
||||
ResultResponse<RoomProfileDTO> response = roomManagerClient.getById(cmd.getRoomId());
|
||||
RoomProfileDTO roomProfile = Objects.nonNull(response) ? response.getBody() : null;
|
||||
if (Objects.nonNull(roomProfile) && Objects.nonNull(roomProfile.getRoomAccount())
|
||||
&& !roomProfile.getRoomAccount().isBlank()) {
|
||||
return roomProfile.getRoomAccount();
|
||||
}
|
||||
return cmd.getRoomId().toString();
|
||||
}
|
||||
|
||||
private boolean checkTargetMicAvailableOrSelf(MicUpDownCmd cmd) {
|
||||
boolean targetMicAlreadySelf = liveMicCacheService.checkEqSelf(
|
||||
cmd.getRoomId(),
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package com.red.circle.live.app.dto.clientobject;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
package com.red.circle.live.app.dto.clientobject;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@ -47,9 +48,19 @@ public class LiveMicrophoneCO extends ClientObject {
|
||||
*/
|
||||
private LiveMicUserCO user;
|
||||
|
||||
/**
|
||||
* 上麦token信息
|
||||
*/
|
||||
private String roomToken;
|
||||
|
||||
}
|
||||
/**
|
||||
* 上麦token信息
|
||||
*/
|
||||
private String roomToken;
|
||||
|
||||
/**
|
||||
* RTC provider: AGORA or TRTC.
|
||||
*/
|
||||
private String rtcProvider;
|
||||
|
||||
/**
|
||||
* RTC credential for clients that support provider negotiation.
|
||||
*/
|
||||
private RtcCredentialCO rtcCredential;
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package com.red.circle.other.app.command.room;
|
||||
|
||||
package com.red.circle.other.app.command.room;
|
||||
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||
import com.red.circle.common.business.dto.rtc.RtcVersionSupport;
|
||||
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
|
||||
import com.red.circle.external.inner.endpoint.message.TrtcClient;
|
||||
import com.red.circle.external.inner.model.cmd.message.CreateGroupCmd;
|
||||
@ -121,13 +124,21 @@ public class RoomEnterCmdExe {
|
||||
);
|
||||
|
||||
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, ownUserProfile);
|
||||
//String token = createAgoraToken(cmd);
|
||||
String token = userAgoraTokenCacheService.getUserAgoraToken(cmd.getReqUserId(), cmd.getRoomId());
|
||||
if (Objects.isNull(token)) {
|
||||
token = trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody();
|
||||
log.warn("进房间token:{}", token);
|
||||
userAgoraTokenCacheService.save(token, cmd.getReqUserId(), cmd.getRoomId());
|
||||
}
|
||||
RtcProviderEnum rtcProvider = resolveRoomProvider(cmd);
|
||||
String token = null;
|
||||
RtcCredentialCO rtcCredential;
|
||||
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||
token = userAgoraTokenCacheService.getUserAgoraToken(cmd.getReqUserId(), cmd.getRoomId());
|
||||
if (Objects.isNull(token)) {
|
||||
token = trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString())
|
||||
.getBody();
|
||||
log.warn("进房间token:{}", token);
|
||||
userAgoraTokenCacheService.save(token, cmd.getReqUserId(), cmd.getRoomId());
|
||||
}
|
||||
rtcCredential = createAgoraCredential(cmd, token);
|
||||
} else {
|
||||
rtcCredential = createTrtcCredential(cmd, manager, false);
|
||||
}
|
||||
|
||||
try {
|
||||
// 无法操作,错误归属
|
||||
@ -159,10 +170,12 @@ public class RoomEnterCmdExe {
|
||||
.setEntrants(
|
||||
new EntryRoomEntrantsCO()
|
||||
.setRoles(roomManagerCacheService.getRoomUserRoles(cmd.getReqUserId(),
|
||||
cmd.getRoomId()))
|
||||
.setLevel(getUserLevel(cmd.requireReqSysOriginEnum(), cmd.getReqUserId()))
|
||||
.setNobleVipAbility(listUserPropsVipActualEquity(cmd))
|
||||
.setRoomToken(token)
|
||||
cmd.getRoomId()))
|
||||
.setLevel(getUserLevel(cmd.requireReqSysOriginEnum(), cmd.getReqUserId()))
|
||||
.setNobleVipAbility(listUserPropsVipActualEquity(cmd))
|
||||
.setRoomToken(token)
|
||||
.setRtcProvider(rtcProvider.name())
|
||||
.setRtcCredential(rtcCredential)
|
||||
);
|
||||
}
|
||||
|
||||
@ -210,9 +223,9 @@ public class RoomEnterCmdExe {
|
||||
* @param cmd
|
||||
* @return
|
||||
*/
|
||||
private String createAgoraToken(RoomEntryCmd cmd) {
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
AtomicReference<String> agoraToken = new AtomicReference<>("BaHrIypJdFWqwWtoZLToRucRyoGrVgYCONBFvGynmlJsevFYsWBfEIcaWUUGijQBjycTtmSvkmBINoSltJMmgiPeBnkaWErixaxg");
|
||||
private String createAgoraToken(RoomEntryCmd cmd) {
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
AtomicReference<String> agoraToken = new AtomicReference<>("BaHrIypJdFWqwWtoZLToRucRyoGrVgYCONBFvGynmlJsevFYsWBfEIcaWUUGijQBjycTtmSvkmBINoSltJMmgiPeBnkaWErixaxg");
|
||||
Future<?> future = executor.submit(() -> {
|
||||
agoraToken.set(trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody());
|
||||
});
|
||||
@ -227,13 +240,63 @@ public class RoomEnterCmdExe {
|
||||
log.error("上麦获取声网token其他异常: {}", e.getMessage());
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
return agoraToken.get();
|
||||
}
|
||||
|
||||
private List<PropsVipActualEquityEnum> listUserPropsVipActualEquity(RoomEntryCmd cmd) {
|
||||
return userProfileGateway.listUserActualEquityEnum(cmd.requiredReqUserId());
|
||||
}
|
||||
executor.shutdown();
|
||||
return agoraToken.get();
|
||||
}
|
||||
|
||||
private RtcProviderEnum resolveRoomProvider(RoomEntryCmd cmd) {
|
||||
String cacheKey = RtcVersionSupport.roomProviderKey(cmd.getRoomId());
|
||||
RtcProviderEnum requestedProvider = RtcVersionSupport.defaultProvider(currentVersion(cmd));
|
||||
RtcProviderEnum cachedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||
if (Objects.nonNull(cachedProvider)) {
|
||||
ResponseAssert.isTrue(CommonErrorCode.UPGRADE_VERSION,
|
||||
!Objects.equals(RtcProviderEnum.AGORA, requestedProvider)
|
||||
|| !Objects.equals(RtcProviderEnum.TRTC, cachedProvider));
|
||||
return cachedProvider;
|
||||
}
|
||||
redisService.setIfAbsent(cacheKey, requestedProvider.name(),
|
||||
RtcVersionSupport.ROOM_PROVIDER_TTL_SECONDS, TimeUnit.SECONDS);
|
||||
RtcProviderEnum resolvedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||
return Objects.nonNull(resolvedProvider) ? resolvedProvider : requestedProvider;
|
||||
}
|
||||
|
||||
private String currentVersion(RoomEntryCmd cmd) {
|
||||
return Optional.ofNullable(cmd)
|
||||
.map(RoomEntryCmd::getReqAppIntel)
|
||||
.map(reqAppIntel -> reqAppIntel.getVersion())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private RtcCredentialCO createAgoraCredential(RoomEntryCmd cmd, String token) {
|
||||
return new RtcCredentialCO()
|
||||
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||
.setAgoraChannelName(cmd.getRoomId().toString())
|
||||
.setAgoraToken(token);
|
||||
}
|
||||
|
||||
private RtcCredentialCO createTrtcCredential(RoomEntryCmd cmd, RoomProfileManager manager,
|
||||
boolean publisher) {
|
||||
ResultResponse<RtcCredentialCO> response = trtcClient.createTrtcCredential(
|
||||
cmd.getReqUserId(),
|
||||
resolveTrtcRoomIdentifier(cmd, manager),
|
||||
publisher
|
||||
);
|
||||
RtcCredentialCO credential = Objects.nonNull(response) ? response.getBody() : null;
|
||||
ResponseAssert.notNull(CommonErrorCode.THIRD_PARTY_SERVER_ERROR, credential);
|
||||
return credential;
|
||||
}
|
||||
|
||||
private String resolveTrtcRoomIdentifier(RoomEntryCmd cmd, RoomProfileManager manager) {
|
||||
if (Objects.nonNull(manager) && Objects.nonNull(manager.getRoomAccount())
|
||||
&& !manager.getRoomAccount().isBlank()) {
|
||||
return manager.getRoomAccount();
|
||||
}
|
||||
return cmd.getRoomId().toString();
|
||||
}
|
||||
|
||||
private List<PropsVipActualEquityEnum> listUserPropsVipActualEquity(RoomEntryCmd cmd) {
|
||||
return userProfileGateway.listUserActualEquityEnum(cmd.requiredReqUserId());
|
||||
}
|
||||
|
||||
private WealthAndCharmLevelDTO getUserLevel(SysOriginPlatformEnum sysOrigin, Long userId) {
|
||||
return Optional.ofNullable(
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package com.red.circle.other.app.dto.clientobject.room;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import com.red.circle.other.inner.enums.live.RoomUserRolesEnum;
|
||||
import com.red.circle.other.inner.enums.material.PropsVipActualEquityEnum;
|
||||
import com.red.circle.other.inner.model.dto.user.WealthAndCharmLevelDTO;
|
||||
package com.red.circle.other.app.dto.clientobject.room;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import com.red.circle.other.inner.enums.live.RoomUserRolesEnum;
|
||||
import com.red.circle.other.inner.enums.material.PropsVipActualEquityEnum;
|
||||
import com.red.circle.other.inner.model.dto.user.WealthAndCharmLevelDTO;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -36,9 +37,19 @@ public class EntryRoomEntrantsCO extends ClientObject {
|
||||
*/
|
||||
private List<PropsVipActualEquityEnum> nobleVipAbility;
|
||||
|
||||
/**
|
||||
* 进入房间token信息
|
||||
*/
|
||||
private String roomToken;
|
||||
|
||||
}
|
||||
/**
|
||||
* 进入房间token信息
|
||||
*/
|
||||
private String roomToken;
|
||||
|
||||
/**
|
||||
* RTC provider: AGORA or TRTC.
|
||||
*/
|
||||
private String rtcProvider;
|
||||
|
||||
/**
|
||||
* RTC credential for clients that support provider negotiation.
|
||||
*/
|
||||
private RtcCredentialCO rtcCredential;
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user