UNPKG

fcr-core

Version:

Core APIs for building online scenes

225 lines (208 loc) 7.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FcrJoinHelper = void 0; exports.handleJoinRetryFailure = handleJoinRetryFailure; require("core-js/modules/esnext.iterator.constructor.js"); require("core-js/modules/esnext.iterator.map.js"); var _imports = require("../imports"); var _type = require("../type"); var _retryHelpers = require("./retry-helpers"); var _error = require("./error"); var _constants = require("../room-control/helpers/constants"); /** * 房间加入辅助工具 * * 提供房间控制相关的加入逻辑和参数构建,统一处理 room-control 和 room-router 中的公共逻辑 */ /** * 通用的加入房间重试失败处理器 * @param error 错误对象 * @param waitBeforeRetry 等待重试函数 * @param attemptCount 当前重试次数 * @param canRetryFn 判断是否可以重试的函数 * @param onAborted 中止回调函数 * @param logPrefix 日志前缀 * @returns 是否继续重试 */ async function handleJoinRetryFailure(error, waitBeforeRetry, attemptCount, canRetryFn, onAborted, logPrefix = 'join room') { onAborted?.(); if (!canRetryFn(error)) { throw error; } // 记录重试信息 console.warn(`Retry attempt ${attemptCount + 1} to ${logPrefix}: ${error.message}`); await waitBeforeRetry(); return true; } /** * 房间加入辅助工具类 * * 封装了房间加入的公共逻辑,包括: * - 快照方式加入房间 * - CheckIn 流程处理 * - 重试机制 * - 错误处理 */ class FcrJoinHelper { constructor(_userId, _scene, _api) { this._userId = _userId; this._scene = _scene; this._api = _api; } /** * 构建CheckIn请求参数(统一的参数构建方法) * @static * @param options 加入选项 * @param userId 用户ID * @param roomId 房间ID * @param extraParams 额外参数(bypass, avatar等) * @returns CheckIn参数对象 */ static buildCheckInParams(options, userId, roomId, extraParams) { return { userName: options.userName, userId, userRole: _type.FcrUserRoleToStringMap[options.userRole], userProperties: options.userProperties, roomId, platform: options.platform ?? (0, _imports.getPlatform)(), streams: options.createStreamConfigs?.map(s => ({ videoSourceUuid: s.videoSourceId, audioSourceUuid: s.audioSourceId, streamName: s.streamName, ...(0, _imports.convertStreamTypeToPublishState)(s.streamType), videoSourceType: s.videoSourceType, audioSourceType: s.audioSourceType, audioSourceState: s.audioSourceState, videoSourceState: s.videoSourceState })), version: (0, _imports.getVersion)(), password: options.password, // 只有在提供了额外参数时才添加 ...(extraParams?.bypass !== undefined && { bypass: extraParams.bypass }), ...(extraParams?.avatar !== undefined && { avatar: extraParams.avatar }) }; } /** * 构建CheckIn请求参数的便捷方法(使用当前实例的配置) * @private * @param options 加入选项 * @param extraParams 额外参数(bypass, avatar等) * @returns CheckIn参数对象 */ _buildCheckInParams(options, extraParams) { const userId = this._userId; const roomId = this._scene.sceneId; // 使用静态方法,但参数来自实例 return FcrJoinHelper.buildCheckInParams(options, userId, roomId, extraParams); } /** * * @param options 加入选项 * @param extraParams 额外参数(bypass, avatar等) * @param useInternalApi 是否使用 checkInInternal API(默认 true) * @returns CheckIn响应数据 */ async performCheckIn(options, extraParams, useInternalApi = true) { const checkInParams = this._buildCheckInParams(options, extraParams); const apiCall = useInternalApi ? () => this._api.checkInInternal(checkInParams) : () => this._api.checkIn(checkInParams); const errorMessage = useInternalApi ? 'check in internal failed' : 'check in failed'; const res = await (0, _error.handleRequestError)(apiCall, _error.FcrErrorModuleCode.ROOM, errorMessage); return res; } /** * 通过 CheckIn 流程加入房间(包含重试逻辑) * * 重试逻辑说明: * - 重试范围:整个 "CheckIn + Join" 流程 * - 重试原因:CheckIn 和 Join 是关联操作,如果 Join 失败需要重新 CheckIn * - 重试判断:使用 canRetryJoinError 判断错误是否可重试 * - 最大重试次数:ROOM_CONTROL_CONSTANTS.MAX_JOIN_ATTEMPTS * * @param options 加入选项 * @param onJoinAborted 加入中止检查函数 * @returns Promise<void> */ async joinWithCheckIn(options, onJoinAborted) { await (0, _imports.retryAttempt)(async () => { // 1. 执行 CheckIn(单次调用,无内部重试) const { data, ts } = await this.performCheckIn(options); // 2. 检查是否中止 if (onJoinAborted) { onJoinAborted(); } // 3. 使用 CheckIn 结果加入房间 await this._joinScene(options.streamLatency, options.streamEncryptionConfig, data, ts); // 4. 再次检查是否中止 if (onJoinAborted) { onJoinAborted(); } }, [], { retriesMax: _constants.ROOM_CONTROL_CONSTANTS.MAX_JOIN_ATTEMPTS }).fail(async ({ error, timeFn: waitBeforeRetry, currentRetry: attemptCount }) => { return handleJoinRetryFailure(error, waitBeforeRetry, attemptCount, _retryHelpers.canRetryJoinError, onJoinAborted, 'join room via CheckIn'); }).exec(); } /** * 使用快照数据加入房间的核心方法 * @private */ async _joinScene(streamLatency, streamEncryptionConfig, snapshot, timestamp, onJoinAborted) { await this._scene.join({ streamLatency: streamLatency, streamEncryptionConfig, snapshot, timestamp }); // 执行中止检查(如果提供了回调) if (onJoinAborted) { onJoinAborted(); } } /** * 统一的房间加入处理 * * 根据选项类型自动选择合适的加入方式: * - 如果有 snapshot 属性:直接使用快照数据加入 * - 否则:执行 CheckIn 流程后加入 * * @param options 加入选项(支持普通加入和快照加入) * @param onJoinAborted 加入中止检查函数 * @returns Promise<void> */ async join(options, onJoinAborted) { if (this._isSnapshotJoin(options)) { await this._joinWithSnapshot(options, onJoinAborted); } else { await this.joinWithCheckIn(options, onJoinAborted); } } /** * 判断是否为快照加入模式 * @private */ _isSnapshotJoin(options) { return 'snapshot' in options; } /** * 快照加入模式:直接使用快照数据加入房间 * @private */ async _joinWithSnapshot(options, onJoinAborted) { await this._joinScene(options.streamLatency || _type.FcrStreamLatencyLevel.ULTRA_LOW, options.streamEncryptionConfig, options.snapshot, options.timestamp, onJoinAborted); } } exports.FcrJoinHelper = FcrJoinHelper;