UNPKG

fcr-core

Version:

Core APIs for building online scenes

232 lines (216 loc) 8.86 kB
"use strict"; require("core-js/modules/es.array.push.js"); require("core-js/modules/esnext.iterator.filter.js"); require("core-js/modules/esnext.iterator.for-each.js"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.FcrJoinHelper = void 0; exports.handleJoinRetryFailure = handleJoinRetryFailure; require("core-js/modules/es.regexp.exec.js"); require("core-js/modules/esnext.iterator.constructor.js"); require("core-js/modules/esnext.iterator.map.js"); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _imports = require("../imports"); var _type = require("../type"); var _retryHelpers = require("./retry-helpers"); var _error = require("./error"); var _constants = require("../room-control/helpers/constants"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /** * 房间加入辅助工具 * * 提供房间控制相关的加入逻辑和参数构建,统一处理 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) { let logPrefix = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'join room'; onAborted === null || onAborted === void 0 || onAborted(); if (!canRetryFn(error)) { throw error; } // 记录重试信息 console.warn("Retry attempt ".concat(attemptCount + 1, " to ").concat(logPrefix, ": ").concat(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) { var _options$platform, _options$createStream; return _objectSpread(_objectSpread({ userName: options.userName, userId, userRole: _type.FcrUserRoleToStringMap[options.userRole], userProperties: options.userProperties, roomId, platform: (_options$platform = options.platform) !== null && _options$platform !== void 0 ? _options$platform : (0, _imports.getPlatform)(), streams: (_options$createStream = options.createStreamConfigs) === null || _options$createStream === void 0 ? void 0 : _options$createStream.map(s => _objectSpread(_objectSpread({ 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 === null || extraParams === void 0 ? void 0 : extraParams.bypass) !== undefined && { bypass: extraParams.bypass }), (extraParams === null || extraParams === void 0 ? void 0 : 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) { let useInternalApi = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 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 _ref => { let { error, timeFn: waitBeforeRetry, currentRetry: attemptCount } = _ref; 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;