sdk 只会给前 100 个人触发 user-in 和 user-out 事件;如果想看更多用户可以使用 client.user.requestMore 方法拉取更多 user。 但注意超过 100 位拉取下来的 user 不会触发 user-out,这些 user 可能一直留在列表里面
建议用户列表和聊天列表实现大列表渲染优化,否则会有性能问题。每次只渲染少量的 dom,上下滚动的时候动态加载。
不要使用单播去做广播的功能,更不要在 user-in 里面有发单播的逻辑,因为不是所有人进房都有 user-in 事件。
RTM 的主要功能就是信令的分发,信令分为单播信令和广播信令;单播信令就是指定发给某个人的信令,广播信令就是发送给房间内所有人的信令。信令的接口主要 是发送和接收。
信令发送如下:
// 单播信令 // messageType 业务自己定义的消息类型 // message 支持基本类型和可以 stringify 的对象 client.sendMessage(userId: UserId, messageType: string, message: any).then(() => { // 发送成功 }) .catch((error) => { // 发送失败,可以选择重试 }) // 广播信令 // messageType 业务自己定义的消息类型 // message 支持基本类型和可以 stringify 的对象 // options 广播的配置。 // options.all true 表示发给所有人,false 只发给 role 为 root 和 admin 的用户 默认 true // options.cache true 表示此广播需要缓存 默认 true client.sendBroadcastMessage(messageType: string, message: any, options?: BroadcastMessageOptions).then(() => { // 发送成功 }) .catch((error) => { // 发送失败,可以选择重试 })
信令接收如下:
// 主动拉取广播缓存,设置 options.cache 的有效 // 一般会在进房成功之后拉取广播缓存恢复房间内的一些状态 client.getCachedBroadcastMessage(messageType: string).then((data) => { const message = data.message }) // 设置单播消息监听 // messageType 业务自己定义的消息类型 client.onMessage(messageType: string, (message, fromId) => { // 处理信令逻辑 }) // 设置广播消息监听 // messageType 业务自己定义的消息类型 client.onBroadcastMessage(messageType: string, (message, fromId) => { // 处理信令逻辑 }) // 可以取消信令监听函数 // 传 listener 取消 listener 函数的监听,不传取消 messageType 的所有监听 client.offMessage(messageType: string, listener?: Function) client.offBroadcastMessage(messageType: string, listener?: Function) // 信令的监听可以设置命名空间,这样可以批量取消监听 // 以 . 开头 const namespace = '.my_namespace' client.onMessage('message1' + namespace, (message, fromId) => { // 处理信令逻辑 }) client.onMessage('message2' + namespace, (message, fromId) => { // 处理信令逻辑 }) client.onBroadcastMessage('message3' + namespace, (message, fromId) => { // 处理信令逻辑 }) client.onBroadcastMessage('message4' + namespace, (message, fromId) => { // 处理信令逻辑 }) // 使用 namespace 取消监听,当有大量的 messageType,每个 messageType 有不同的监听函数,可以灵活批量取消 client.offMessage(namespace) client.offBroadcastMessage(namespace)
进入房间后可以通过 client.user.all() 获取当前所有用户。
// 本地用户缓存 const userList = client.user.all() client.user /** * 用户加入 */ .on(BRTM.Events.User.USER_IN, (user) => { userList.push(user) }) // 用户退出 .on(BRTM.Events.User.USER_OUT, user => { removeUser(user) }) client.user.requestMore(count).then((data) => { const { hasMore, userList } = data // userList 加入就缓存,根据业务逻辑判断是否还需要拉取 })
使用文档功能需要先开启 RTM 的文档功能,文档功能单独计费,调用 client.enableDocumentAbility() 开启收费,调用 client.disableDocumentAbility() 结束收费。可在 client.join() 成功之后调用 client.getAbilities() 来获取当前的房间有没有开启文档功能,之后再决定是否调用开启文档接口。
文档上传需要通过 client.createDocUploader() 来获取文档上传器 DocUploader,文档上传的所有操作都使用 DocUploader 来操作。大致流程如下:
// 本地维护的文档列表 let docList = [] const docUploader = client.createDocUploader({ // 文档上传进度报告,共分为 md5 计算、上传排队、上传中、转码排队、转码中、成功等阶段 // file 是报告进度的文档 file 实例 // type 为进度阶段类型 // progress 为当前阶段完成百分比 onprogress: (file, type, progress) => { } }) // 用于得到上传文档的过程中的一些重要数据,比如 fid const extra = {} // 通过用户交互得到一个待上传的文件对象 docUploader.addDoc(file, { fileName: file.name, // 标记是否转码为动态文档,ppt 文件若转为动态文档会保留 ppt 中的动画特效,若转为静态文档则只是一些静态图片 // doc pdf jpg png 等这些文件就只能转为静态文档 isAnimated: false }, extra).then(doc => { // 成功了将文档加入本地缓存 docList.push(doc) }) .catch((error) => { if (error === 'abort') { // 自己主动取消的 } else if (error && error.getCode && error.getCode() === 6001) { // 某些 ppt 会存在转码为动态文档失败的情况,此时可以选择不使用动态直接用静态,也可不使用了 // 动态转失败,如果想使用静态的 docUploader.switchToStaticDocument(extra.fid, { fileName: file.name, ext: '.' + file.name.split('.').pop() }).then((doc) => { docList.push(doc) }) } }) // 上层过程中可以随时取消各个阶段的上传 // file 文件对象 docUploader.cancel(file)
房间内的文档维护,文档维护就是维护当前房间内的 docList 缓存,当添加,删除时做相应更改。
// 本地维护的文档列表 let docList = [] client.document /** * 远端添加了一个文档,追加到本地缓存列表 */ .on(BRTM.Events.Document.DOC_ADDED, data => { docList.push(data.doc) }) /** * 远端删除了一个文档,删除本地缓存列表 */ .on(BRTM.Events.Document.DOC_REMOVED, data => { removeDoc(data.docId) }) /** * 服务器更新了所有 doc,直接替换本地缓存(比如后台更新了房间内的文档就是通过这个来更新的) */ .on(BRTM.Events.Document.DOC_ALL, data => { docList = data.docList }) // 每个房间有一个默认的文档白板,其 docId 为 '0',当我们打开某个文档时可以发一个广播告诉其他人打开的文档 id // 这样通过这个广播就可以同步打开对应的文档 const KEY_OPEN_DOC_ID = 'open_doc_id' client.onBroadcastMessage(KEY_OPEN_DOC_ID, (message, fromId) => { const activeDocId = message || '0' // 使用 activeDocId 打开文档 }) // 请求当前房间内的所有文档(只调用一次) client.document.requestAllDocs().then(data => { // 拿到所有文档 docList = data.docList // 去拉取当前打开的文档广播缓存,用于重进教室之后以及后进的用户怎么知道当前打开的文档是哪个(只调用一次) client.getCachedBroadcastMessage(KEY_OPEN_DOC_ID).then(data => { const activeDocId = data.message || '0' // 使用 activeDocId 打开文档 }) })
打开文档。当我们进入房间内已经知道需要显示哪一个文档时,就可以根据 docId 创建文档播放器。
// 根据 docId 得到 doc 信息 const doc = client.document.docData.getDocumentById(activeDocId) // 创建画笔配置器,可以所有文档播放器共用一个,也可以每一个文档播放器自己使用一个 const config = BRTM.createPainterConfig() // 创建文档播放器,可以同时支持创建多个,UI 上显示多个,每一个单独操作翻页标注互不影响 const player = BRTM.createDocumentPlayer(doc, client, { // 文档组件挂载的父元素 container: container, // 是否响应动态文档中的事件 allowClick: true, // 是否有画笔 hasPainter: true, // 当前能否使用画笔,可通过 player.setCanDrawing(enable) 随时更改权限,可用于授权画笔使用 canDrawing: canPaint, onLoadingStart: (page, step, pageChanged) => { }, onLoadingEnd: (page, step, pageChanged, status) => { }, onPageChange: (page, step) => { }, onStepChange: (page, step) => { }, onPageCountChage: (totalPage) => { }, // 获取文档显示高宽,会传入图片的分辨率,根据业务需求显示比例,父元素的大小计算正确的显示高宽返回 getImageDimension: (width, height) => { } }, config) // 当老师通过交互新打开一个文档,创建文档播放器之后发广播通知(注意如果 activeDocId 的更新来自于广播接收或广播缓存则不能发广播,因为打开的 docId 并没有更改) client.sendBroadcastMessage(KEY_OPEN_DOC_ID, activeDocId)
// 本地聊天缓存 const messageList = [] // 聊天通道打开,在此事件之后做聊天的相关操作 client.on(BRTM.Events.Room.MESSAGE_CHANNEL_OPENED, () => { client.chat.pull(channel: string, next: number = -1, count: number = 10).then((data) => { const { next, channel, hasMore, messageList } = data // messageList 加入缓存 if (hasMore) { // 根据业务逻辑判断是否需要继续拉取历史消息 // 如 UI 向上滚动查看 // 使用 next 作为下一次的 pull 的 next 参数 } }) // 收到新消息 client.chat.on(BRTM.Events.Chat.MESSAGE_RECEIVED, (message) => { // message 加入缓存 }) // 收到新的私聊消息 .on(BRTM.Events.Chat.MESSAGE_WHISPER_RECEIVED, (message) => { // message 加入缓存 }) // 收到撤回消息 .on(BRTM.Events.Chat.MESSAGE_REVOKED, (message) => { // 将撤回的消息从本地缓存删除 }) })
Web
用户列表实现
sdk 只会给前 100 个人触发 user-in 和 user-out 事件;如果想看更多用户可以使用 client.user.requestMore 方法拉取更多 user。 但注意超过 100 位拉取下来的 user 不会触发 user-out,这些 user 可能一直留在列表里面
大列表渲染
建议用户列表和聊天列表实现大列表渲染优化,否则会有性能问题。每次只渲染少量的 dom,上下滚动的时候动态加载。
广播单播使用
不要使用单播去做广播的功能,更不要在 user-in 里面有发单播的逻辑,因为不是所有人进房都有 user-in 事件。
信令使用
RTM 的主要功能就是信令的分发,信令分为单播信令和广播信令;单播信令就是指定发给某个人的信令,广播信令就是发送给房间内所有人的信令。信令的接口主要 是发送和接收。
信令发送如下:
信令接收如下:
用户列表维护
进入房间后可以通过 client.user.all() 获取当前所有用户。
文档上传播放流程
使用文档功能需要先开启 RTM 的文档功能,文档功能单独计费,调用 client.enableDocumentAbility() 开启收费,调用 client.disableDocumentAbility() 结束收费。可在 client.join() 成功之后调用 client.getAbilities() 来获取当前的房间有没有开启文档功能,之后再决定是否调用开启文档接口。
文档上传需要通过 client.createDocUploader() 来获取文档上传器 DocUploader,文档上传的所有操作都使用 DocUploader 来操作。大致流程如下:
房间内的文档维护,文档维护就是维护当前房间内的 docList 缓存,当添加,删除时做相应更改。
打开文档。当我们进入房间内已经知道需要显示哪一个文档时,就可以根据 docId 创建文档播放器。
聊天处理流程