import type { UniplatSdk } from "uniplat-sdk"; import { EmojiService } from "../service/emoji"; import { ChatOption, TokenStringGetter, ServiceType, CustomerServiceProduct, } from "./../model"; import { ChatLoggerService } from "./logger"; import tokenManager from "./token"; import xim from "./xim"; import { dbController } from "../database"; class Chat { private _sdk?: () => UniplatSdk; private _orgId: () => string | number = () => "0"; private token!: TokenStringGetter; private serviceType = ServiceType.Backend; private product = CustomerServiceProduct.Default; private eventHub: Vue | null = null; private keywords: string[] = []; private ws = ""; private connectedActions: (() => void)[] = []; private connected = false; private userMapping: { [key: string]: { name: string; avatar: string } } = {}; public onReady(action: () => void) { if (this.connected) { action(); } else { this.connectedActions.push(action); } } public async setup(option: ChatOption) { if (!option) { throw new Error(`You must specify a chat option for chat service`); } if (!option.webSocketUri) { throw new Error( `You must specify a web socket address for chat service` ); } this._sdk = option.sdk; this._orgId = option.orgId; option.serviceType !== undefined && (this.serviceType = option.serviceType); option.product && (this.product = option.product); this.eventHub = option.eventHub || null; if (option.user) { this.userMapping[this._sdk().global.uid] = { name: option.user.username || "", avatar: option.user.icon || "", }; } this.setupIndexDb(); this.token = async () => option.sdk().global.jwtToken; tokenManager.save(this.token); EmojiService.raiseOnReady(this.token); option .sdk() .events.addTokenChanged((token) => this.setToken(() => new Promise((resolve) => resolve(token))) ); // this.keywords = ["社保"]; return this.initChatSdk((this.ws = option.webSocketUri)).finally(() => { this.connected = true; for (const item of this.connectedActions) { item(); } }); } private setupIndexDb() { if (this._sdk) { const s = this._sdk(); return dbController.setup( s.global.uid + "-" + (s.global.initData.orgId || 0) ); } return Promise.reject(); } public resetup(org: () => string | number) { this._orgId = org; xim.onConnected(); return this.setupIndexDb(); } public unSetup() { xim.close(); } public getSdk = () => { if (!this._sdk) { throw new Error("sdk shouldn't undefined"); } return this._sdk(); }; public getServiceType() { return this.serviceType; } public isBackend() { return this.serviceType === ServiceType.Backend; } public getProduct() { return this.product; } public getOrgId = () => { return this._orgId(); }; public setToken(token: TokenStringGetter) { return xim.setToken(token); } private trimToken(token: string) { return token.replace(/^Bearer\s/, ""); } public async getToken() { return this.trimToken(await this.token()); } private async initChatSdk(uri: string) { if (xim.isConnected()) { return Promise.resolve(uri); } return new Promise((resolve) => { xim.open(uri, this.token).finally(() => { this.registerXimEvent(); if (xim.isConnected()) { resolve(); } else { setTimeout(() => resolve(), 2000); } }); }); } public registerXimEvent(onConnected?: () => void) { xim.off("status", (e) => this.raiseOnStatusChanged(e, onConnected)); xim.on("status", (e) => this.raiseOnStatusChanged(e, onConnected)); } private raiseOnStatusChanged(e: any, onConnected?: () => void) { if (e === "CONNECTED") { if (onConnected) { onConnected(); } } this.debug(`client status ${e}`); } public getUserMapping() { return this.userMapping; } private debug(message: string) { ChatLoggerService.logger?.debug(message); } public $emit(event: string, ...args: any[]) { if (this.eventHub) { this.eventHub.$emit(event, ...args); } } public $on(event: string, callback: Function) { if (this.eventHub) { this.eventHub.$on(event, callback); } } public getMatchedTextKeywords() { return this.keywords; } } export default new Chat();