|
|
@@ -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 '未知错误'
|
|
|
}
|
|
|
}
|