Browse Source

♻️ refactor(core): 重构错误码定义与RTM管理器

- 将SttErrorCode从stt-error.ts迁移到types/stt-error-types.ts
- 导出SttErrorCode类型供外部使用

✨ feat(rtm): 添加证书支持与自动Token生成

- RtmManagerAdapter构造函数新增certificate参数
- 添加证书验证,缺失时抛出CERTIFICATE_REQUIRED错误
- 实现_apiGetAgoraToken方法自动获取RTM token
- 添加baseUrl配置用于Token请求

🐛 fix(sdk): 修复RTM管理器初始化参数缺失问题

- SttSdk创建RtmManagerAdapter时传入certificate参数
- 完善RTM连接配置,增强认证安全性
yourname 2 months ago
parent
commit
68ae60e34e

+ 2 - 15
packages/stt-sdk-core/src/core/stt-error.ts

@@ -1,18 +1,5 @@
-export type SttErrorCode =
-  | 'NOT_INITIALIZED'
-  | 'NOT_JOINED'
-  | 'INVALID_CONFIG'
-  | 'INVALID_LANGUAGES'
-  | 'ALREADY_JOINED'
-  | 'NETWORK_ERROR'
-  | 'AUTHENTICATION_ERROR'
-  | 'PERMISSION_DENIED'
-  | 'TIMEOUT'
-  | 'UNKNOWN_ERROR'
-  | 'APP_ID_REQUIRED'
-  | 'TOKEN_ERROR'
-  | 'TASK_NOT_FOUND'
-  | 'TOKEN_NOT_FOUND'
+import type { SttErrorCode } from '../types'
+export { SttErrorCode }
 
 export class SttError extends Error {
   public readonly code: SttErrorCode

+ 1 - 1
packages/stt-sdk-core/src/core/stt-sdk.ts

@@ -79,7 +79,7 @@ export class SttSdk
       throw new SttError('NOT_INITIALIZED', 'SDK must be initialized before creating managers')
     }
 
-    const manager = new RtmManagerAdapter(this._config!.appId)
+    const manager = new RtmManagerAdapter(this._config!.appId, this._config!.certificate)
     this._rtmManagers.add(manager)
 
     // 监听管理器错误事件并转发

+ 55 - 1
packages/stt-sdk-core/src/managers/rtm-manager-adapter.ts

@@ -21,13 +21,18 @@ export class RtmManagerAdapter extends AGEventEmitter<RtmEventMap> implements IR
   private _userMap: Map<string, RtmUserInfo> = new Map()
   private _client?: RTMClient
   private _appId: string = ''
+  private _certificate: string = ''
   private _rtmConfig: RTMConfig = {}
+  private _baseUrl = 'https://service.agora.io/toolbox-overseas'
 
-  constructor(appId?: string) {
+  constructor(appId?: string, certificate?: string) {
     super()
     if (appId) {
       this._appId = appId
     }
+    if (certificate) {
+      this._certificate = certificate
+    }
   }
 
   async join(config: RtmManagerConfig): Promise<void> {
@@ -46,12 +51,25 @@ export class RtmManagerAdapter extends AGEventEmitter<RtmEventMap> implements IR
         throw new SttError('APP_ID_REQUIRED', 'App ID is required for RTM connection')
       }
 
+      if (!this._certificate) {
+        throw new SttError(
+          'CERTIFICATE_REQUIRED',
+          'Certificate is required for RTM token generation'
+        )
+      }
+
       this._userId = userId
       this._channel = channel
       this._config = config
 
       this.emit('connecting', { channel, userId })
 
+      // 获取RTM token
+      const token = await this._apiGetAgoraToken({ uid: userId, channel })
+      if (token) {
+        this._rtmConfig.token = token
+      }
+
       // 创建RTM客户端
       this._client = new RTM(this._appId, userId, this._rtmConfig)
 
@@ -434,4 +452,40 @@ export class RtmManagerAdapter extends AGEventEmitter<RtmEventMap> implements IR
       await this._client?.lock.setLock(this._channel, CHANNEL_TYPE, LOCK_STT)
     }
   }
+
+  private async _apiGetAgoraToken(config: {
+    uid: string | number
+    channel: string
+  }): Promise<string | null> {
+    const { uid, channel } = config
+    const url = `${this._baseUrl}/v2/token/generate`
+    const data = {
+      appId: this._appId,
+      appCertificate: this._certificate,
+      channelName: channel,
+      expire: 7200,
+      src: 'web',
+      types: [1, 2],
+      uid: uid.toString(),
+    }
+
+    try {
+      const response = await fetch(url, {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify(data),
+      })
+
+      if (response.ok) {
+        const result = await response.json()
+        return result?.data?.token || null
+      }
+      return null
+    } catch (error) {
+      console.error('Token generation failed:', error)
+      return null
+    }
+  }
 }

+ 1 - 0
packages/stt-sdk-core/src/types/stt-error-types.ts

@@ -10,6 +10,7 @@ export type SttErrorCode =
   | 'TIMEOUT'
   | 'UNKNOWN_ERROR'
   | 'APP_ID_REQUIRED'
+  | 'CERTIFICATE_REQUIRED'
   | 'TOKEN_ERROR'
   | 'TASK_NOT_FOUND'
   | 'TOKEN_NOT_FOUND'