skailan-conversations
Version:
Servicio de conversaciones y mensajería para Skailan
259 lines • 10.2 kB
JavaScript
import { StartConversation } from "../../app/use-cases/StartConversation";
import { CreateMessage } from "../../app/use-cases/CreateMessage";
import { Message } from "../entities/Message";
import { v4 as uuidv4 } from "uuid";
export class TelegramChannelService {
telegramService;
messageRepository;
conversationRepository;
channelRepository;
constructor(telegramService, messageRepository, conversationRepository, channelRepository) {
this.telegramService = telegramService;
this.messageRepository = messageRepository;
this.conversationRepository = conversationRepository;
this.channelRepository = channelRepository;
}
async processIncomingMessage(organizationId, channelId, message) {
try {
console.log(`📥 Procesando mensaje de Telegram: ${message.id}`);
// 1. Iniciar o encontrar conversación
const startConversationUseCase = new StartConversation(this.conversationRepository, this.channelRepository);
const conversation = await startConversationUseCase.execute({
organizationId,
channelId,
contactExternalId: message.from,
contactName: message.metadata?.contactName,
contactPhone: message.from, // En Telegram, el from es el chat_id
});
// 2. Crear mensaje en la base de datos
const createMessageUseCase = new CreateMessage(this.messageRepository, this.conversationRepository);
const savedMessage = await createMessageUseCase.execute({
organizationId,
conversationId: conversation.id,
senderType: "contact",
senderId: message.from,
type: message.type,
content: message.content,
mediaUrl: message.mediaUrl,
externalMessageId: message.id,
timestamp: message.timestamp,
});
console.log(`✅ Mensaje de Telegram procesado: ${savedMessage.id}`);
return { conversation, message: savedMessage };
}
catch (error) {
console.error("❌ Error procesando mensaje de Telegram:", error);
throw error;
}
}
async sendMessage(request) {
try {
console.log(`📤 Enviando mensaje de Telegram a: ${request.to}`);
// Obtener configuración del canal
const channel = await this.channelRepository.findById(request.channelId);
if (!channel) {
throw new Error("Canal no encontrado");
}
const config = channel.config;
if (!config.botToken) {
throw new Error("Bot token no configurado");
}
// Enviar mensaje a Telegram
const telegramResponse = await this.telegramService.sendMessage(parseInt(request.to), request.content, request.options);
// Crear mensaje en la base de datos
const message = new Message(uuidv4(), request.organizationId, request.conversationId, "system", "telegram_system", request.type || "text", request.content, request.mediaUrl || null, telegramResponse.message_id?.toString() || null, "sent", new Date(), new Date());
const savedMessage = await this.messageRepository.save(message);
console.log(`✅ Mensaje de Telegram enviado: ${savedMessage.id}`);
return savedMessage;
}
catch (error) {
console.error("❌ Error enviando mensaje de Telegram:", error);
throw error;
}
}
async validateConfig(config) {
try {
const telegramConfig = config;
if (!telegramConfig.botToken) {
throw new Error("Bot token de Telegram requerido");
}
if (telegramConfig.botToken.length < 10) {
throw new Error("Bot token de Telegram inválido");
}
if (!telegramConfig.botToken.includes(":")) {
throw new Error("Formato de bot token de Telegram inválido");
}
console.log(`✅ Configuración de Telegram válida`);
return true;
}
catch (error) {
console.error("❌ Error validando configuración de Telegram:", error);
return false;
}
}
async getContactInfo(organizationId, channelId, contactId) {
try {
console.log(`👤 Obteniendo información de contacto: ${contactId}`);
// Obtener información del bot desde Telegram
const channel = await this.channelRepository.findById(channelId);
if (!channel) {
throw new Error("Canal no encontrado");
}
const config = channel.config;
// Aquí podrías hacer una llamada a la API de Telegram para obtener información del usuario
// Por ahora, retornamos información básica
return {
id: contactId,
externalId: contactId,
name: `Usuario ${contactId}`,
phone: contactId,
metadata: {
platform: "telegram",
chatId: contactId,
},
};
}
catch (error) {
console.error("❌ Error obteniendo información de contacto:", error);
throw error;
}
}
async verifyWebhook(payload, signature, config) {
try {
console.log(`🔐 Verificando webhook de Telegram`);
// Telegram no usa firmas como WhatsApp, pero podemos verificar el bot token
const telegramConfig = config;
if (!telegramConfig.botToken) {
console.error("❌ Bot token no encontrado en configuración");
return false;
}
// Verificar que el payload contiene un update válido
if (!payload || !payload.update_id) {
console.error("❌ Payload de Telegram inválido");
return false;
}
console.log(`✅ Webhook de Telegram verificado`);
return true;
}
catch (error) {
console.error("❌ Error verificando webhook de Telegram:", error);
return false;
}
}
getChannelType() {
return "telegram";
}
/**
* Procesa un update de Telegram
*/
async processTelegramUpdate(organizationId, channelId, update) {
try {
console.log(`📥 Procesando update de Telegram: ${update.update_id}`);
// Extraer mensaje del update
const message = this.extractMessageFromUpdate(update);
if (!message) {
console.log(`⚠️ Update de Telegram sin mensaje válido: ${update.update_id}`);
return null;
}
return await this.processIncomingMessage(organizationId, channelId, message);
}
catch (error) {
console.error("❌ Error procesando update de Telegram:", error);
throw error;
}
}
/**
* Extrae un mensaje del update de Telegram
*/
extractMessageFromUpdate(update) {
// Manejar diferentes tipos de updates
if (update.message) {
return this.extractMessageFromMessage(update.message);
}
else if (update.edited_message) {
return this.extractMessageFromMessage(update.edited_message);
}
else if (update.callback_query) {
return this.extractMessageFromCallbackQuery(update.callback_query);
}
return null;
}
/**
* Extrae mensaje de un objeto message de Telegram
*/
extractMessageFromMessage(message) {
if (!message.text &&
!message.photo &&
!message.video &&
!message.audio &&
!message.document) {
return null;
}
let content = "";
let type = "text";
let mediaUrl;
if (message.text) {
content = message.text;
type = "text";
}
else if (message.photo) {
content = message.caption || "(Imagen)";
type = "image";
mediaUrl = message.photo[0]?.file_id;
}
else if (message.video) {
content = message.caption || "(Video)";
type = "video";
mediaUrl = message.video.file_id;
}
else if (message.audio) {
content = "(Audio)";
type = "audio";
mediaUrl = message.audio.file_id;
}
else if (message.document) {
content = message.document.file_name || "(Documento)";
type = "document";
mediaUrl = message.document.file_id;
}
return {
id: message.message_id.toString(),
from: message.from.id.toString(),
to: message.chat.id.toString(),
type,
content,
mediaUrl,
timestamp: new Date(message.date * 1000),
metadata: {
contactName: message.from.first_name,
lastName: message.from.last_name,
username: message.from.username,
isBot: message.from.is_bot,
chatType: message.chat.type,
},
};
}
/**
* Extrae mensaje de un callback query de Telegram
*/
extractMessageFromCallbackQuery(callbackQuery) {
if (!callbackQuery.data) {
return null;
}
return {
id: callbackQuery.id,
from: callbackQuery.from.id.toString(),
to: callbackQuery.message?.chat.id.toString() || "",
type: "text",
content: callbackQuery.data,
timestamp: new Date(),
metadata: {
callbackQuery: true,
messageId: callbackQuery.message?.message_id,
contactName: callbackQuery.from.first_name,
username: callbackQuery.from.username,
},
};
}
}
//# sourceMappingURL=TelegramChannelService.js.map