UNPKG

agora-edu-core

Version:

Core APIs for building an online classroom

625 lines (602 loc) 22.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GroupStore = void 0; require("core-js/modules/esnext.map.delete-all.js"); require("core-js/modules/esnext.map.every.js"); require("core-js/modules/esnext.map.filter.js"); require("core-js/modules/esnext.map.find.js"); require("core-js/modules/esnext.map.find-key.js"); require("core-js/modules/esnext.map.includes.js"); require("core-js/modules/esnext.map.key-of.js"); require("core-js/modules/esnext.map.map-keys.js"); require("core-js/modules/esnext.map.map-values.js"); require("core-js/modules/esnext.map.merge.js"); require("core-js/modules/esnext.map.reduce.js"); require("core-js/modules/esnext.map.some.js"); require("core-js/modules/esnext.map.update.js"); var _agoraRteSdk = require("agora-rte-sdk"); var _cloneDeep = _interopRequireDefault(require("lodash/cloneDeep")); var _startsWith = _interopRequireDefault(require("lodash/startsWith")); var _get = _interopRequireDefault(require("lodash/get")); var _mobx = require("mobx"); var _configs = require("../../../../configs"); var _eventCenter = require("../../../../event-center"); var _type = require("../../../../type"); var _error = require("../../../../utils/error"); var _base = require("../base"); var _type2 = require("./type"); var _dec, _dec2, _dec3, _dec4, _class, _class2, _descriptor, _descriptor2, _descriptor3, _GroupStore; function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _initializerDefineProperty(e, i, r, l) { r && Object.defineProperty(e, i, { enumerable: r.enumerable, configurable: r.configurable, writable: r.writable, value: r.initializer ? r.initializer.call(l) : void 0 }); } function _applyDecoratedDescriptor(i, e, r, n, l) { var a = {}; return Object.keys(n).forEach(function (i) { a[i] = n[i]; }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) { return n(i, e, r) || r; }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a; } function _initializerWarningHelper(r, e) { throw Error("Decorating class property failed. Please ensure that transform-class-properties is enabled and runs after the decorators transform."); } /** * `GroupStore` 类提供分组讨论功能相关的能力。 */ /** @en * The `GroupStore` class provides abilities related to breakout rooms. */ let GroupStore = exports.GroupStore = (_dec = _agoraRteSdk.Log.attach({ proxyMethods: false }), _dec2 = _mobx.action.bound, _dec3 = _mobx.action.bound, _dec4 = _mobx.action.bound, _dec(_class = (_class2 = (_GroupStore = class GroupStore extends _base.EduStoreBase { constructor(...args) { super(...args); this._currentGroupUuid = void 0; this._inviting = false; this._disposers = []; _initializerDefineProperty(this, "_operationQueue", _descriptor, this); /** * 分组状态 */ /** @en * The current state of grouping */ _initializerDefineProperty(this, "state", _descriptor2, this); /** * 分组详情 */ /** @en * Details of groups */ _initializerDefineProperty(this, "groupDetails", _descriptor3, this); } /** Methods */ _handleRoomPropertiesChange(changedRoomProperties, roomProperties, operator, cause) { changedRoomProperties.forEach(key => { if (key === 'groups') { const groups = (0, _get.default)(roomProperties, 'groups', {}); const processes = (0, _get.default)(roomProperties, 'processes', {}); const progress = this._getProgress(processes); this._setDetails(groups.details || {}, progress); this.state = groups.state; this._checkSubRoom(); } if (key === 'processes') { const groups = (0, _get.default)(roomProperties, 'groups', {}); const processes = (0, _get.default)(roomProperties, 'processes', {}); const progress = this._getProgress(processes); this._setDetails(groups.details || {}, progress); this.state = groups.state; } }); if (cause) { const { cmd, data } = cause; // Emit event when local user is invited by teacher if (cmd === 501 && (0, _startsWith.default)(data.processUuid, GroupStore.CMD_PROCESS_PREFIX)) { const groupUuid = data.processUuid.substring(GroupStore.CMD_PROCESS_PREFIX.length); const progress = data.addProgress || []; const accepted = data.addAccepted || []; const actionType = data.actionType; const removeProgress = data.removeProgress || []; const { userUuid: localUuid } = _configs.EduClassroomConfig.shared.sessionInfo; const invitedLocal = progress.find(({ userUuid }) => userUuid === localUuid); if (invitedLocal) { _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.InvitedToGroup, invitedLocal.payload); } // accepted if (actionType === 2 && accepted.length) { _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.AcceptedToGroup, { groupUuid, accepted }); } // reject invitation if ((actionType === 3 || actionType === 7) && removeProgress.length) { const inviting = this._inviting; this._inviting = false; _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.RejectedToGroup, { groupUuid, removeProgress, inviting }); } } // user in out if (cmd === 11 && data.actionType === 4) { const groups = data.changeGroups || []; groups.forEach(({ groupUuid, addUsers, removeUsers }) => { if (addUsers.length) { _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.UserJoinGroup, { groupUuid, users: addUsers.map(({ userUuid }) => userUuid) }); } if (removeUsers.length) { _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.UserLeaveGroup, { groupUuid, users: removeUsers.map(({ userUuid }) => userUuid) }); } }); } } } _getProgress(processes) { const progress = Object.keys(processes).reduce((prev, k) => { if (k.startsWith(GroupStore.CMD_PROCESS_PREFIX)) { const groupUuid = k.substring(GroupStore.CMD_PROCESS_PREFIX.length); const users = processes[k].progress.map(({ userUuid }) => userUuid); prev.set(groupUuid, users); } return prev; }, new Map()); return progress; } _setDetails(details, progress) { const newGroupDetails = new Map(); const cloneDetails = (0, _cloneDeep.default)(details); Object.entries(cloneDetails).forEach(([groupUuid, groupDetail]) => { if (progress.has(groupUuid)) { var _progress$get; const notJoinedUsers = ((_progress$get = progress.get(groupUuid)) === null || _progress$get === void 0 ? void 0 : _progress$get.map(userUuid => ({ userUuid, notJoined: true }))) || []; groupDetail.users.unshift(...notJoinedUsers); } newGroupDetails.set(groupUuid, groupDetail); }); this.groupDetails = newGroupDetails; } _checkSubRoom() { const { userUuid: localUuid } = _configs.EduClassroomConfig.shared.sessionInfo; let lastGroupUuid = ''; for (const [groupUuid, group] of this.groupDetails.entries()) { const local = group.users.find(({ userUuid, notJoined }) => userUuid === localUuid && !notJoined); if (local) { this.logger.info('found user has joined sub room', groupUuid); lastGroupUuid = groupUuid; break; } } if (lastGroupUuid) { if (this._currentGroupUuid && lastGroupUuid !== this._currentGroupUuid) { this.logger.info(`user move into group ${lastGroupUuid}, from group ${this._currentGroupUuid}`); this._operationQueue.push({ fromGroupUuid: this._currentGroupUuid, toGroupUuid: lastGroupUuid, type: _type2.OperationType.Move }); } else if (!this._currentGroupUuid) { this.logger.info(`user join group ${lastGroupUuid}`); this._operationQueue.push({ toGroupUuid: lastGroupUuid, type: _type2.OperationType.Join }); } } else { if (this._currentGroupUuid) { this.logger.info(`user leave group ${this._currentGroupUuid}`); this._operationQueue.push({ fromGroupUuid: this._currentGroupUuid, type: _type2.OperationType.Leave }); } } setTimeout(this._run); } /** * 新建小组 * @param groupDetail 分组配置 **/ /** @en * Creates a group * @param groupDetail the grouping options */ async addGroups(groupDetails, inProgress = true) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.addGroup(roomUuid, { groups: groupDetails, inProgress: inProgress }); } /** * 移除小组 * @param groups 小组 ID 列表 **/ /** @en * Removes groups * @param groups A list of group IDs */ async removeGroups(groups) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.removeGroup(roomUuid, { removeGroupUuids: groups }); } /** * 更新分组配置 * @param groups 分组配置数组 **/ /** @en * Updates the grouping options * @param groups An array of the grouping options */ async updateGroupInfo(groups) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.updateGroupInfo(roomUuid, { groups }); } /** * 开启分组讨论 * @param groupDetails 分组配置数组 **/ /** @en * Starts the breakout session * @param groupDetails An array of the grouping options */ async startGroup(groupDetails, syncBoardScenes) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.updateGroupState(roomUuid, { groups: groupDetails, inProgress: true, syncBoardScenes }, _type2.GroupState.OPEN); } /** * 结束分组讨论 **/ /** @en * Stops the breakout session */ async stopGroup() { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.updateGroupState(roomUuid, { groups: [] }, _type2.GroupState.CLOSE); } /** * 更新小组成员列表 * @param patches 更新配置 * @param sendInvitation 是否发送邀请 **/ /** @en * Updates the grouping options * @param patches The update options * @param sendInvitation Whether to send an invitation */ async updateGroupUsers(patches, sendInvitation = false) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.updateGroupUsers(roomUuid, { groups: patches, inProgress: sendInvitation }); if (sendInvitation) { this._inviting = true; } } /** * 将用户从小组中移除 * @param fromGroupUuid 组 ID * @param users 用户 ID 列表 **/ /** @en * Removes users from a group * @param fromGroupUuid The group ID * @param users A list of user IDs * */ async removeGroupUsers(fromGroupUuid, users) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; const fromGroup = { groupUuid: fromGroupUuid, removeUsers: users }; await this.api.updateGroupUsers(roomUuid, { groups: [fromGroup], inProgress: false }); } /** * * 将用户从某小组移入另一小组 * @param fromGroupUuid 原组 ID * @param toGroupUuid 目标组 ID * @param users 用户 ID 列表 **/ /** @en * Moves users from a group to another group * @param fromGroupUuid The ID of the group from which the users are * @param toGroupUuid The ID of the group to which the users are moved * @param users A list of user IDs */ async moveUsersToGroup(fromGroupUuid, toGroupUuid, users) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; const fromGroup = { groupUuid: fromGroupUuid, removeUsers: users }; const toGroup = { groupUuid: toGroupUuid, addUsers: users }; const groups = [fromGroup, toGroup]; await this.api.updateGroupUsers(roomUuid, { groups, inProgress: false }); } /** * * 接受加入小组的邀请 * @param groupUuid 组 ID * **/ /** @en * Accepts the invitation of joining a group * @param groupUuid The group ID */ async acceptGroupInvite(groupUuid) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.acceptGroupInvite(roomUuid, groupUuid, this._currentGroupUuid ? { leaveGroupUuids: [this._currentGroupUuid] } : undefined); } /** * * 拒绝加入小组的邀请 * @param groupUuid 组 ID **/ /** @en * Rejects the invitation of joining a group * @param groupUuid The group ID * */ async rejectGroupInvite(groupUuid) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; await this.api.rejectGroupInvite(roomUuid, groupUuid); } /** * * 进入子房间 * @param groupUuid 组 ID **/ /** @en * Joins a group * @param groupUuid The group ID */ joinSubRoom(groupUuid) { this._currentGroupUuid = groupUuid; _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.JoinSubRoom); } /** * * 用户主动从某房间移动至另一房间 * @param fromGroupUuid 原组 ID * @param toGroupUuid 目标组 ID * **/ /** @en * A user moves from a group to another group * @param fromGroupUuid The ID of the group from which the user is * @param toGroupUuid The ID of the group to which the user moves */ moveIntoSubRoom(fromGroupUuid, toGroupUuid) { this._currentGroupUuid = toGroupUuid; _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.MoveToOtherGroup, { fromGroupUuid, toGroupUuid }); } /** * 离开小组 **/ /** @en * Leaves the group */ leaveSubRoom() { if (this._currentGroupUuid) { this._currentGroupUuid = undefined; _eventCenter.EduEventCenter.shared.emitClasroomEvents(_type.AgoraEduClassroomEvent.LeaveSubRoom); } } /** * * 发送全体消息 * @param messageText 消息 * **/ /** @en * Sends a broadcast message * @param messageText The message text */ broadcastMessage(messageText) { const roomUuid = _configs.EduClassroomConfig.shared.sessionInfo.roomUuid; try { this.api.broadcastHxChatMessage(roomUuid, { range: _type2.BroadcastMessageRange.All, type: _type2.BroadcastMessageType.Text, msg: messageText }); } catch (e) { _error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_GROUP_BROADCAST_FAIL, e); } } /** * 执行队列任务 * @returns */ async _run() { const operation = this._operationQueue.pop(); if (!operation) { return; } this.logger.info(`handle group operation`, (0, _mobx.toJS)(operation)); switch (operation.type) { case _type2.OperationType.Join: this.joinSubRoom(operation.toGroupUuid); break; case _type2.OperationType.Leave: this.leaveSubRoom(); break; case _type2.OperationType.Move: this.moveIntoSubRoom(operation.fromGroupUuid, operation.toGroupUuid); break; } } /** * @internal * @deprecated * * 是否发送邀请 **/ /** @en * @internal * @deprecated * * Whether to send an invitation */ get inviting() { return this._inviting; } /** * 当前所在小组 * **/ /** @en * The current group */ get currentSubRoom() { return this._currentGroupUuid; } /** * * 用户所在组 ID 映射关系 **/ /** @en * The mapping relation between the group ID and the user ID */ get groupUuidByUserUuid() { const map = new Map(); this.groupDetails.forEach((group, groupUuid) => { group.users.forEach(({ userUuid, notJoined }) => { if (!notJoined) { map.set(userUuid, groupUuid); } }); }); return map; } /** * * 返回 userUuid 组成的 map 数据 **/ /** @en * The map data by userUuid */ get userByUuid() { const map = new Map(); this.groupDetails.forEach(group => { group.users.forEach(user => { map.set(user.userUuid, user); }); }); return map; } //others _addEventHandlers(scene) { scene.on(_agoraRteSdk.AgoraRteEventType.RoomPropertyUpdated, this._handleRoomPropertiesChange); } _removeEventHandlers(scene) { scene.off(_agoraRteSdk.AgoraRteEventType.RoomPropertyUpdated, this._handleRoomPropertiesChange); } /** * @internal */ /** @en * @internal */ onInstall() { this._disposers.push((0, _mobx.computed)(() => this.classroomStore.connectionStore.mainRoomScene).observe(({ newValue, oldValue }) => { if (oldValue) { this._removeEventHandlers(oldValue); } if (newValue) { //bind events this._addEventHandlers(newValue); } })); } /** * @internal */ /** @en * @internal */ onDestroy() { this._disposers.forEach(d => d()); this._disposers = []; } }, _GroupStore.MAX_GROUP_COUNT = 20, _GroupStore.MIN_GROUP_COUNT = 2, _GroupStore.MAX_PER_GROUP_PERSON = 15, _GroupStore.CMD_PROCESS_PREFIX = 'groups-', _GroupStore), _descriptor = _applyDecoratedDescriptor(_class2.prototype, "_operationQueue", [_mobx.observable], { configurable: true, enumerable: true, writable: true, initializer: function () { return []; } }), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, "state", [_mobx.observable], { configurable: true, enumerable: true, writable: true, initializer: function () { return _type2.GroupState.CLOSE; } }), _descriptor3 = _applyDecoratedDescriptor(_class2.prototype, "groupDetails", [_mobx.observable], { configurable: true, enumerable: true, writable: true, initializer: function () { return new Map(); } }), _applyDecoratedDescriptor(_class2.prototype, "_handleRoomPropertiesChange", [_dec2], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleRoomPropertiesChange"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_setDetails", [_dec3], Object.getOwnPropertyDescriptor(_class2.prototype, "_setDetails"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "addGroups", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "addGroups"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "removeGroups", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "removeGroups"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "updateGroupInfo", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "updateGroupInfo"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "startGroup", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "startGroup"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "stopGroup", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "stopGroup"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "updateGroupUsers", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "updateGroupUsers"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "removeGroupUsers", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "removeGroupUsers"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "moveUsersToGroup", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "moveUsersToGroup"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "acceptGroupInvite", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "acceptGroupInvite"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "rejectGroupInvite", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "rejectGroupInvite"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "joinSubRoom", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "joinSubRoom"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "moveIntoSubRoom", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "moveIntoSubRoom"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "leaveSubRoom", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "leaveSubRoom"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "broadcastMessage", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class2.prototype, "broadcastMessage"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_run", [_dec4], Object.getOwnPropertyDescriptor(_class2.prototype, "_run"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "groupUuidByUserUuid", [_mobx.computed], Object.getOwnPropertyDescriptor(_class2.prototype, "groupUuidByUserUuid"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "userByUuid", [_mobx.computed], Object.getOwnPropertyDescriptor(_class2.prototype, "userByUuid"), _class2.prototype), _class2)) || _class);