فهرست منبع

重构 TgMsgSendService,整合 TgClientService 以简化消息发送流程,移除冗余代码,提升可读性和维护性。

wuyi 2 ماه پیش
والد
کامیت
3c225111d3
2فایلهای تغییر یافته به همراه273 افزوده شده و 188 حذف شده
  1. 18 188
      src/services/tg-msg-send.service.ts
  2. 255 0
      src/services/tgClient.service.ts

+ 18 - 188
src/services/tg-msg-send.service.ts

@@ -1,13 +1,14 @@
-import { Api, TelegramClient } from 'telegram'
-import { StringSession } from 'telegram/sessions'
+import { TelegramClient } from 'telegram'
 import { SendMessageResult } from '../dto/tg-msg-send.dto'
-import bigInt from 'big-integer'
+import { TgClientService } from './tgClient.service'
 
 export class TgMsgSendService {
   private app: any
+  private tgClientService: TgClientService
 
   constructor(app: any) {
     this.app = app
+    this.tgClientService = TgClientService.getInstance()
   }
 
   async sendMessage(sessionString: string, target: string, message: string): Promise<SendMessageResult> {
@@ -16,34 +17,35 @@ export class TgMsgSendService {
       return { success: false, error: configError }
     }
 
-    const apiId = parseInt(this.app.config.API_ID)
-    const apiHash = this.app.config.API_HASH
     let client: TelegramClient | null = null
 
     try {
-      client = await this.createAndConnectClient(sessionString, apiId, apiHash)
+      client = await this.tgClientService.connect(sessionString)
 
       const parsedTarget = this.parseTarget(target)
       if (!parsedTarget) {
         return { success: false, error: 'target 格式错误,请检查是否正确' }
       }
 
-      const targetPeer = await this.getTargetPeer(client, parsedTarget)
+      const targetPeer = await this.tgClientService.getTargetPeer(client, parsedTarget)
       if (!targetPeer) {
         return { success: false, error: 'target 无效,无法获取目标信息' }
       }
 
-      const result = await this.sendMessageToPeer(client, targetPeer, message)
+      const result = await this.tgClientService.sendMessageToPeer(client, targetPeer, message)
       this.app.log.info('消息发送成功', result.id)
 
-      await this.clearConversation(client, targetPeer)
+      await this.tgClientService.clearConversation(client, targetPeer)
       this.app.log.info('会话清除成功')
 
       if (target.startsWith('+')) {
-        await this.deleteTempContact(client, targetPeer.id)
+        await this.tgClientService.deleteTempContact(client, targetPeer.id)
         this.app.log.info('临时联系人删除成功')
       }
 
+      await this.tgClientService.disconnect()
+      this.app.log.info('=============发送消息任务结束=============')
+
       return {
         success: true,
         messageId: result.id
@@ -55,8 +57,6 @@ export class TgMsgSendService {
         success: false,
         error: errorMessage
       }
-    } finally {
-      await this.disconnectClient(client)
     }
   }
 
@@ -70,160 +70,6 @@ export class TgMsgSendService {
     return null
   }
 
-  private async createAndConnectClient(sessionString: string, apiId: number, apiHash: string): Promise<TelegramClient> {
-    const stringSession = new StringSession(sessionString)
-    const client = new TelegramClient(stringSession, apiId, apiHash, {
-      connectionRetries: 5
-    })
-
-    await client.connect()
-
-    if (!client.connected) {
-      throw new Error('TelegramClient 连接失败,请检查网络或 Session 是否有效')
-    }
-
-    this.app.log.info('TelegramClient 连接成功')
-
-    const me = await client.getMe()
-    if (me) {
-      this.app.log.info(
-        `当前登录账号: id: ${me.id} ,name: ${me.firstName || ''} ${me.lastName || ''} ${me.username || ''}`.trim()
-      )
-    }
-
-    return client
-  }
-
-  private async getTargetPeer(client: TelegramClient, parsedTarget: string | number): Promise<any> {
-    this.app.log.info('正在获取目标实体信息...')
-
-    try {
-      let targetPeer: any
-
-      if (typeof parsedTarget === 'string' && parsedTarget.startsWith('+')) {
-        this.app.log.info('手机号导入联系人...')
-        // 手机号
-        const result = await client.invoke(
-          new Api.contacts.ImportContacts({
-            contacts: [
-              new Api.InputPhoneContact({
-                clientId: bigInt(0),
-                phone: parsedTarget,
-                firstName: 'Temp',
-                lastName: ''
-              })
-            ]
-          })
-        )
-
-        const user = result.users?.[0]
-        if (!user) throw new Error('未找到对应的 Telegram 用户')
-
-        targetPeer = user
-      } else {
-        // 用户名 用户 id
-        targetPeer = await client.getEntity(parsedTarget)
-      }
-
-      if (targetPeer) {
-        this.logTargetInfo(targetPeer)
-      }
-
-      return targetPeer
-    } catch (error) {
-      const errorMessage = this.extractErrorMessage(error)
-
-      if (typeof parsedTarget === 'number') {
-        this.app.log.error({
-          msg: '无法获取用户实体',
-          error: errorMessage,
-          targetId: parsedTarget.toString()
-        })
-        throw new Error('target 无效,不在用户消息列表中')
-      }
-
-      this.app.log.error({
-        msg: '无法获取目标信息',
-        error: errorMessage,
-        target: parsedTarget
-      })
-      throw new Error('target 无效,请检查 target 是否正确')
-    }
-  }
-
-  private async sendMessageToPeer(client: TelegramClient, targetPeer: any, message: string): Promise<any> {
-    this.app.log.info('正在发送消息...')
-
-    try {
-      const result = await client.sendMessage(targetPeer, {
-        message: message
-      })
-      return result
-    } catch (error) {
-      const errorMessage = this.extractErrorMessage(error)
-      throw new Error(`发送消息失败: ${errorMessage}`)
-    }
-  }
-
-  private async clearConversation(client: TelegramClient, targetPeer: any): Promise<void> {
-    this.app.log.info('正在清除会话...')
-    try {
-      await client.invoke(
-        new Api.messages.DeleteHistory({
-          peer: targetPeer,
-          revoke: false
-        })
-      )
-    } catch (error) {
-      const errorMessage = this.extractErrorMessage(error)
-      throw new Error(`清除会话失败: ${errorMessage}`)
-    }
-  }
-
-  private async deleteTempContact(client: TelegramClient, userId: number) {
-    this.app.log.info('正在删除临时联系人...')
-    try {
-      await client.invoke(
-        new Api.contacts.DeleteContacts({
-          id: [userId]
-        })
-      )
-    } catch (error) {
-      const errorMessage = this.extractErrorMessage(error)
-      throw new Error(`删除临时联系人失败: ${errorMessage}`)
-    }
-  }
-
-  private async disconnectClient(client: TelegramClient | null): Promise<void> {
-    if (!client) {
-      return
-    }
-
-    try {
-      if (client.connected) {
-        await client.disconnect()
-        this.app.log.info('TelegramClient 已断开连接')
-        await client.destroy()
-        this.app.log.info('TelegramClient 已销毁')
-      }
-    } catch (error) {
-      const errorMessage = this.extractErrorMessage(error)
-      if (!errorMessage.includes('TIMEOUT')) {
-        this.app.log.error({ msg: '断开连接时发生错误', error: errorMessage })
-      }
-    }
-  }
-
-  private extractErrorMessage(error: unknown): string {
-    if (error instanceof Error) {
-      return error.message
-    }
-    if (typeof error === 'string') {
-      return error
-    }
-    return '未知错误'
-  }
-
   private parseTarget(targetId: string): string | number | null {
     const trimmed = targetId.trim()
 
@@ -241,29 +87,13 @@ export class TgMsgSendService {
     return null
   }
 
-  private logTargetInfo(targetPeer: any): void {
-    const entityInfo = targetPeer as any
-    const logData: any = {
-      className: entityInfo.className || '未知'
-    }
-
-    // 记录 ID
-    if (entityInfo.id !== undefined) {
-      logData.id = entityInfo.id.toString()
-    }
-
-    // 记录名称信息
-    if (entityInfo.title) {
-      logData.title = entityInfo.title
-    } else if (entityInfo.firstName) {
-      logData.name = `${entityInfo.firstName} ${entityInfo.lastName || ''}`.trim()
+  private extractErrorMessage(error: unknown): string {
+    if (error instanceof Error) {
+      return error.message
     }
-
-    // 记录用户名
-    if (entityInfo.username) {
-      logData.username = entityInfo.username
+    if (typeof error === 'string') {
+      return error
     }
-
-    this.app.log.info(logData)
+    return '未知错误'
   }
 }

+ 255 - 0
src/services/tgClient.service.ts

@@ -0,0 +1,255 @@
+import { Api, TelegramClient } from 'telegram'
+import { StringSession } from 'telegram/sessions'
+import { createApp } from '../app'
+import bigInt from 'big-integer'
+
+export class TgClientService {
+  private static _instance: TgClientService
+
+  public static getInstance(): TgClientService {
+    if (!this._instance) {
+      this._instance = new TgClientService()
+    }
+    return this._instance
+  }
+
+  private app: any
+  private client: TelegramClient | null = null
+  private currentSession: string | null = null
+  private apiId: number
+  private apiHash: string
+  private initPromise: Promise<void> | null = null
+
+  private constructor() {}
+
+  private async initializeApp(): Promise<void> {
+    if (this.initPromise) {
+      return this.initPromise
+    }
+
+    if (this.app && this.apiId && this.apiHash) {
+      return
+    }
+
+    // 初始化
+    this.initPromise = (async () => {
+      this.app = await createApp()
+      if (!this.app.config.API_ID) {
+        throw new Error('API_ID 未配置')
+      }
+      if (!this.app.config.API_HASH) {
+        throw new Error('API_HASH 未配置')
+      }
+      this.apiId = parseInt(this.app.config.API_ID)
+      this.apiHash = this.app.config.API_HASH
+    })()
+
+    return this.initPromise
+  }
+
+  async connect(sessionString: string): Promise<TelegramClient> {
+    await this.initializeApp()
+
+    if (this.client && this.client.connected && this.currentSession === sessionString) {
+      return this.client
+    }
+
+    if (this.client && this.client.connected) {
+      await this.disconnect()
+    }
+
+    const stringSession = new StringSession(sessionString)
+    this.client = new TelegramClient(stringSession, this.apiId, this.apiHash, {
+      connectionRetries: 5
+    })
+
+    await this.client.connect()
+
+    if (!this.client.connected) {
+      throw new Error('TelegramClient 连接失败,请检查网络或 Session 是否有效')
+    }
+
+    this.currentSession = sessionString
+    this.app.log.info('TelegramClient 连接成功')
+
+    const me = await this.client.getMe()
+    if (me) {
+      this.app.log.info(
+        `当前登录账号: id: ${me.id} ,name: ${me.firstName || ''} ${me.lastName || ''} ${me.username || ''}`.trim()
+      )
+    }
+
+    return this.client
+  }
+
+  async disconnect(): Promise<void> {
+    if (!this.client) {
+      return
+    }
+
+    try {
+      if (this.client.connected) {
+        await this.client.disconnect()
+        this.app.log.info('TelegramClient 已断开连接')
+        await this.client.destroy()
+        this.app.log.info('TelegramClient 已销毁')
+      }
+    } catch (error) {
+      const errorMessage = error instanceof Error ? error.message : String(error)
+      if (!errorMessage.includes('TIMEOUT')) {
+        this.app.log.error({ msg: '断开连接时发生错误', error: errorMessage })
+      }
+    } finally {
+      this.client = null
+      this.currentSession = null
+    }
+  }
+
+  async getTargetPeer(client: TelegramClient, parsedTarget: string | number): Promise<any> {
+    this.app.log.info('正在获取目标实体信息...')
+
+    try {
+      let targetPeer: any
+
+      if (typeof parsedTarget === 'string' && parsedTarget.startsWith('+')) {
+        this.app.log.info('手机号导入联系人...')
+        // 手机号
+        const result = await client.invoke(
+          new Api.contacts.ImportContacts({
+            contacts: [
+              new Api.InputPhoneContact({
+                clientId: bigInt(0),
+                phone: parsedTarget,
+                firstName: 'Temp',
+                lastName: ''
+              })
+            ]
+          })
+        )
+
+        const user = result.users?.[0]
+        if (!user) throw new Error('未找到对应的 Telegram 用户')
+
+        targetPeer = user
+      } else {
+        // 用户名 用户 id
+        targetPeer = await client.getEntity(parsedTarget)
+      }
+
+      if (targetPeer) {
+        this.logTargetInfo(targetPeer)
+      }
+
+      return targetPeer
+    } catch (error) {
+      const errorMessage = this.extractErrorMessage(error)
+
+      if (typeof parsedTarget === 'number') {
+        this.app.log.error({
+          msg: '无法获取用户实体',
+          error: errorMessage,
+          targetId: parsedTarget.toString()
+        })
+        throw new Error('target 无效,不在用户消息列表中')
+      }
+
+      this.app.log.error({
+        msg: '无法获取目标信息',
+        error: errorMessage,
+        target: parsedTarget
+      })
+      throw new Error('target 无效,请检查 target 是否正确')
+    }
+  }
+
+  async sendMessageToPeer(client: TelegramClient, targetPeer: any, message: string): Promise<any> {
+    this.app.log.info('正在发送消息...')
+
+    try {
+      const result = await client.sendMessage(targetPeer, {
+        message: message
+      })
+      return result
+    } catch (error) {
+      const errorMessage = this.extractErrorMessage(error)
+      throw new Error(`发送消息失败: ${errorMessage}`)
+    }
+  }
+
+  async clearConversation(client: TelegramClient, targetPeer: any): Promise<void> {
+    this.app.log.info('正在清除会话...')
+    try {
+      await client.invoke(
+        new Api.messages.DeleteHistory({
+          peer: targetPeer,
+          revoke: false
+        })
+      )
+    } catch (error) {
+      const errorMessage = this.extractErrorMessage(error)
+      throw new Error(`清除会话失败: ${errorMessage}`)
+    }
+  }
+
+  async deleteTempContact(client: TelegramClient, userId: number): Promise<void> {
+    this.app.log.info('正在删除临时联系人...')
+    try {
+      await client.invoke(
+        new Api.contacts.DeleteContacts({
+          id: [userId]
+        })
+      )
+    } catch (error) {
+      const errorMessage = this.extractErrorMessage(error)
+      throw new Error(`删除临时联系人失败: ${errorMessage}`)
+    }
+  }
+
+  private extractErrorMessage(error: unknown): string {
+    if (error instanceof Error) {
+      return error.message
+    }
+    if (typeof error === 'string') {
+      return error
+    }
+    return '未知错误'
+  }
+
+  private logTargetInfo(targetPeer: any): void {
+    const entityInfo = targetPeer as any
+    const logData: any = {
+      className: entityInfo.className || '未知'
+    }
+
+    // 记录 ID
+    if (entityInfo.id !== undefined) {
+      logData.id = entityInfo.id.toString()
+    }
+
+    // 记录名称信息
+    if (entityInfo.title) {
+      logData.title = entityInfo.title
+    } else if (entityInfo.firstName) {
+      logData.name = `${entityInfo.firstName} ${entityInfo.lastName || ''}`.trim()
+    }
+
+    // 记录用户名
+    if (entityInfo.username) {
+      logData.username = entityInfo.username
+    }
+
+    this.app.log.info(logData)
+  }
+
+  getClient(): TelegramClient | null {
+    return this.client
+  }
+
+  isConnected(): boolean {
+    return this.client !== null && (this.client.connected ?? false)
+  }
+
+  getCurrentSession(): string | null {
+    return this.currentSession
+  }
+}