import { DataNotFoundError, TcContext } from 'tailchat-server-sdk'; import { TcService, TcDbService } from 'tailchat-server-sdk'; import type { AgoraDocument, AgoraModel } from '../models/agora'; import { RtcTokenBuilder, Role as RtcRole } from './utils/RtcTokenBuilder2'; import got from 'got'; // Reference: https://docs.agora.io/cn/metachat/rtc_channel_management_restfulapi#查询用户列表 interface ChannelUserListRet { success: boolean; data: | { channel_exist: false; } | { channel_exist: true; mode: 1 | 2; total: number; users: string[]; // 频道内所有用户的用户 ID broadcasters: string[]; // 频道内所有主播的用户 ID。该字段仅在直播场景 audience: string[]; // 频道内观众的用户 ID。最多包含当前频道内前 10,000 名观众的用户 ID。该字段仅在直播场景 (mode 的值为 2)下返回。 audience_total: number; // 频道内的观众总人数。该字段仅在直播场景 (mode 的值为 2)下返回。 }; } /** * 声网音视频 * * 为Tailchat增加声网音视频通信功能 */ interface AgoraService extends TcService, TcDbService {} class AgoraService extends TcService { get serviceName() { return 'plugin:com.msgbyte.agora'; } /** * 声网服务端的appid */ get serverAppId() { return process.env.AGORA_APP_ID; } /** * 声网服务端的app证书 */ get serverAppCertificate() { return process.env.AGORA_APP_CERT; } /** * 声网服务端restful的客户 ID */ get serverCustomerKey() { return process.env.AGORA_CUSTOMER_KEY; } /** * 声网服务端restful的客户 秘钥 */ get serverCustomerSecret() { return process.env.AGORA_CUSTOMER_SECRET; } onInit() { if ( !this.serverAppId || !this.serverAppCertificate || !this.serverCustomerKey || !this.serverCustomerSecret ) { this.logger.warn( '声网服务启动失败, 缺少必要的环境变量。AGORA_APP_ID, AGORA_APP_CERT, AGORA_CUSTOMER_KEY, AGORA_CUSTOMER_SECRET' ); return; } // this.registerLocalDb(require('../models/agora').default); this.registerAction('generateToken', this.generateToken, { params: { channelName: 'string', appId: { type: 'string', optional: true }, appCert: { type: 'string', optional: true }, }, }); this.registerAction('getChannelUserList', this.getChannelUserList, { params: { channelName: 'string', }, }); } generateToken( ctx: TcContext<{ channelName: string; appId?: string; appCert?: string; }> ) { const { channelName, appId = this.serverAppId, appCert = this.serverAppCertificate, } = ctx.params; if (!appId || !appCert) { throw new Error('Agora.io AppId/AppCert not init'); } const role = RtcRole.PUBLISHER; const userId = ctx.meta.userId; const tokenExpirationInSecond = 3600; // 1h const privilegeExpirationInSecond = 3600; // 1h // Build token with user account const token = RtcTokenBuilder.buildTokenWithUserAccount( appId, appCert, channelName, userId, role, tokenExpirationInSecond, privilegeExpirationInSecond ); return token; } /** * 获取频道用户列表 */ async getChannelUserList( ctx: TcContext<{ channelName: string; }> ): Promise { const { channelName } = ctx.params; const { data } = await got .get( `https://api.agora.io/dev/v1/channel/user/${this.serverAppId}/${channelName}`, { headers: this.generateRESTfulHeaders(), } ) .json(); if (data.channel_exist === false) { throw new DataNotFoundError('Channel not exist'); } return data; } /** * 生成restful api需要的请求头 */ private generateRESTfulHeaders() { const encodedCredential = Buffer.from( this.serverCustomerKey + ':' + this.serverCustomerSecret ).toString('base64'); return { Authorization: 'Basic ' + encodedCredential, 'Content-Type': 'application/json', }; } } export default AgoraService;