From f444fb51435e47e9a9421af295ab6c5255db297e Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sun, 25 Dec 2022 21:37:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A3=B0=E7=BD=91=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2=E9=A2=91=E9=81=93=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pnpm-lock.yaml | 47 +++++----- server/plugins/com.msgbyte.agora/package.json | 1 + .../services/agora.service.dev.ts | 91 ++++++++++++++++++- 3 files changed, 114 insertions(+), 25 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1be72b14..166849ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -948,9 +948,11 @@ importers: server/plugins/com.msgbyte.agora: specifiers: '@types/react': 18.0.20 + got: 11.8.6 mini-star: '*' tailchat-server-sdk: '*' dependencies: + got: 11.8.6 tailchat-server-sdk: link:../../packages/sdk devDependencies: '@types/react': 18.0.20 @@ -10661,7 +10663,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 18.7.11 + '@types/node': 18.11.16 '@types/responselike': 1.0.0 dev: false @@ -11005,10 +11007,6 @@ packages: resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==} dev: false - /@types/json-buffer/3.0.0: - resolution: {integrity: sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==} - dev: false - /@types/json-schema/7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} @@ -11027,7 +11025,7 @@ packages: /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.7.11 + '@types/node': 18.11.16 /@types/koa-bodyparser/4.3.8: resolution: {integrity: sha512-/Tk3xdaj/3y9VZ6K8z9fQ8myZOR2EEfwrlkbO4SjzLizRZaDFARSA8OGAC3B9lhC1R4wG0nCrTdd6o0NL2jrEQ==} @@ -11458,7 +11456,7 @@ packages: /@types/responselike/1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 18.7.11 + '@types/node': 18.11.16 /@types/retry/0.12.0: resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} @@ -14125,7 +14123,7 @@ packages: clone-response: 1.0.3 get-stream: 5.2.0 http-cache-semantics: 4.1.0 - keyv: 4.4.1 + keyv: 4.5.2 lowercase-keys: 2.0.0 normalize-url: 6.1.0 responselike: 2.0.1 @@ -14867,14 +14865,6 @@ packages: /component-emitter/1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} - /compress-brotli/1.3.8: - resolution: {integrity: sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==} - engines: {node: '>= 12'} - dependencies: - '@types/json-buffer': 3.0.0 - json-buffer: 3.0.1 - dev: false - /compressible/2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -19984,6 +19974,23 @@ packages: responselike: 2.0.1 dev: false + /got/11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.2 + '@types/responselike': 1.0.0 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.2 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + dev: false + /got/12.5.3: resolution: {integrity: sha512-8wKnb9MGU8IPGRIo+/ukTy9XLJBwDiCpIf5TVzQ9Cpol50eMTpBq2GAuDsuDIz7hTYmZgMgC1e9ydr6kSDWs3w==} engines: {node: '>=14.16'} @@ -22947,18 +22954,10 @@ packages: dependencies: json-buffer: 3.0.0 - /keyv/4.4.1: - resolution: {integrity: sha512-PzByhNxfBLnSBW2MZi1DF+W5+qB/7BMpOokewqIvqS8GFtP7xHm2oeGU72Y1fhtfOv/FiEnI4+nyViYDmUChnw==} - dependencies: - compress-brotli: 1.3.8 - json-buffer: 3.0.1 - dev: false - /keyv/4.5.2: resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==} dependencies: json-buffer: 3.0.1 - dev: true /kind-of/3.2.2: resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} diff --git a/server/plugins/com.msgbyte.agora/package.json b/server/plugins/com.msgbyte.agora/package.json index 758175e5..fed503ab 100644 --- a/server/plugins/com.msgbyte.agora/package.json +++ b/server/plugins/com.msgbyte.agora/package.json @@ -15,6 +15,7 @@ "mini-star": "*" }, "dependencies": { + "got": "11.8.6", "tailchat-server-sdk": "*" } } diff --git a/server/plugins/com.msgbyte.agora/services/agora.service.dev.ts b/server/plugins/com.msgbyte.agora/services/agora.service.dev.ts index c5f134ae..8fbb668a 100644 --- a/server/plugins/com.msgbyte.agora/services/agora.service.dev.ts +++ b/server/plugins/com.msgbyte.agora/services/agora.service.dev.ts @@ -1,7 +1,26 @@ -import type { TcContext } from 'tailchat-server-sdk'; +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)下返回。 + }; +} /** * 声网音视频 @@ -30,7 +49,32 @@ class AgoraService extends TcService { 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, { @@ -40,6 +84,11 @@ class AgoraService extends TcService { appCert: { type: 'string', optional: true }, }, }); + this.registerAction('getChannelUserList', this.getChannelUserList, { + params: { + channelName: 'string', + }, + }); } generateToken( @@ -79,6 +128,46 @@ class AgoraService extends TcService { 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;