// import { GraphqlClient } from "../common/GraphqlClient"; import { HttpClient } from "../common/HttpClient"; import { PublicKeyManager } from "../common/PublicKeyManager"; import { ManagementTokenProvider } from "./ManagementTokenProvider"; import { ManagementClientOptions } from "./types"; import { SDK_VERSION } from '../version'; // import { buildAuthorization, buildStringToSign } from "../buildSignature"; export class EventManagementClient { options: ManagementClientOptions; // graphqlClient: GraphqlClient; httpClient: HttpClient; tokenProvider: ManagementTokenProvider; publicKeyManager: PublicKeyManager; private wsMap: {[propName: string]: { socket: WebSocket, lockConnect: boolean, timeConnect: number }}; private eventBus: {[propName: string]: [Function, Function][]}; constructor( options: ManagementClientOptions, // graphqlClient: GraphqlClient, httpClient: HttpClient, tokenProvider: ManagementTokenProvider, ){ this.options = options; // this.graphqlClient = graphqlClient; this.tokenProvider = tokenProvider; this.httpClient = httpClient; this.wsMap = {}; this.eventBus = {} } private reconnect(eventName: string) { return new Promise((resolve, reject) => { if (this.options.retryTimes && this.wsMap[eventName].timeConnect < this.options.retryTimes) { if (!this.wsMap[eventName].lockConnect) { this.wsMap[eventName].lockConnect = true this.wsMap[eventName].timeConnect ++ setTimeout(() => { this.wsMap[eventName].lockConnect = false this.initWebSocket(eventName, true).then(() => { resolve(true) }).catch((e) => { reject(e) }) }, 2000); } } else { reject(`socket 服务器连接超时`); } }) } private initWebSocket(eventName: string, retry?: boolean) { return new Promise(async(resolve, reject) => { if (!this.wsMap[eventName] || retry) { const token = await this.tokenProvider.getToken(); this.wsMap[eventName] = { socket: new WebSocket(`${this.options.socketUri}/events/v1/management/sub?code=${eventName}&token=${token}`), timeConnect: retry ? this.wsMap[eventName].timeConnect : 0, lockConnect: false } this.wsMap[eventName].socket.onopen = () => { resolve(true) } this.wsMap[eventName].socket.addEventListener('message', (event) => { try { if (this.eventBus[eventName]) { this.eventBus[eventName].forEach(callback => { callback[0](event.data.toString("utf8")) }) } else { // 未订阅事件 console.warn("未订阅的事件:", eventName); } } catch (error) { return reject(`数据格式化错误,检查传输数据格式!!! ${error}`); } }) this.wsMap[eventName].socket.addEventListener('error', async(e) => { try { await this.reconnect(eventName) resolve(true) } catch (error) { return reject(`socket 连接异常:${JSON.stringify(e)}`) } }) this.wsMap[eventName].socket.onclose = async() => { try { await this.reconnect(eventName) resolve(true) } catch (error) { return reject('socket 服务器连接超时') } } } else { resolve(true) } }) } public sub(eventName: string, callback: Function, errCallback: Function) { /** * 1. 判断是否连接 socket * 2. 获取 socket 实例 * 3. 订阅 */ if (typeof eventName !== 'string') { throw new Error("订阅事件名称为 string 类型!!!") } if (typeof callback !== 'function') { throw new Error("订阅事件回调函数需要为 function 类型!!!"); } if (!this.options.socketUri) { throw new Error("订阅事件需要添加 socketUri 连接地址!!!") } this.initWebSocket(eventName).catch(e => { this.eventBus[eventName].forEach((item) => { item[1]?.(e) }) }) if (this.eventBus[eventName]) { this.eventBus[eventName].push([callback, errCallback]) } else { this.eventBus[eventName] = [[callback, errCallback]] } } public async pub(eventName: string, data: string) { if (typeof eventName !== 'string') { throw new Error("事件名称为 string 类型!!!") } if (typeof data !== 'string') { throw new Error("发布数据为 string 类型!!!") } return await this.httpClient.request({ method: "POST", url: `${this.options.host}/api/v3/pub-event`, data: { eventType: eventName, source: `authing-js-sdk: ${SDK_VERSION}`, eventData: data }, }); } }