package cn.iocoder.yudao.module.im.dal.redis.rtc; import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.stereotype.Repository; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.IM_RTC_CALL_LOCK; import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.RTC_INVITE_BUSY; /** * IM 通话同对 / 同群活跃唯一性的锁 Redis DAO *
* invite 入口包一层;锁内做「SELECT 已有活跃通话 → 命中即加入分支;否则 INSERT 新通话」
*
* @author 芋道源码
*/
@Repository
@Slf4j
public class ImRtcCallLockRedisDAO {
/**
* 等待获取锁的最长时间;超时抛 RTC_INVITE_BUSY
*/
private static final long LOCK_WAIT_MS = 5_000L;
/**
* 持有锁的最长时间;自动释放兜底;给 LiveKit / DB / 推送偶发慢留余地
*/
private static final long LOCK_LEASE_MS = 30_000L;
@Resource
private RedissonClient redissonClient;
/**
* 私聊通话锁;按 userId 排序拼 key 保对称(同对呼叫和反向呼叫共用一把锁)
*/
public
* unlock 前用 isHeldByCurrentThread 兜底;业务超过 leaseTime 时锁已自动释放,不再抛 IllegalMonitorStateException
*/
private