es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

El controlador de eventos de Telethon no funciona con Hypercorn.

Estoy intentando usar Quart con Hypercorn y Telethon. Tengo un oyente de mensajes, pero desde que integré Quart y Telethon, el oyente ya no se activa (por favor, consulte el ejemplo reproducible mínimo a continuación). ¿Alguien tiene alguna idea de por qué este código no funciona?

Utilicé este código como plantilla, pero no es exactamente el mismo caso de uso, ya que no hay un oyente de actualizaciones.

Cuando inicio el código con python3 main.py, todo funciona correctamente, pero cuando inicio con python3 -m hypercorn main:api (Windows 10), el oyente no funciona.

import os
from dotenv import load_dotenv
from telethon import TelegramClient, events, sync
import hypercorn.asyncio
from quart import Quart, request, json

Cargar variables de entorno

load_dotenv()

Variables globales

allMessages = []

Habilitar conexión

api_id = os.getenv("API_ID")
api_hash = os.getenv("API_HASH")
phone_number = os.getenv("PHONE_NUMBER")
channel_username = os.getenv("CHANNEL")
client = TelegramClient('abc', api_id, api_hash)
client.start(phone_number)

Obtener entidad de chat

chat = client.get_entity(channel_username)

Escuchar nuevos mensajes

@client.on(events.NewMessage(incoming=True, chats=chat))
async def handler(event):
  message = event.message
  allMessages.insert(0, message)
  print(message.stringify())

Servidor web

api = Quart(__name__)
@api.route('/messages/json', methods=['GET'])
def route_get_messages_json():
  return "test"
async def main():
  await hypercorn.asyncio.serve(api, hypercorn.Config())
if __name__ == '__main__':
  client.loop.run_until_complete(main())

Además, he intentado reemplazar las últimas líneas con el fragmento de código de esta pregunta, pero desafortunadamente, eso tampoco funcionó.

async def main():
  await serve(api, hypercorn.config.Config())
if __name__ == '__main__':
  loop = client.loop
  asyncio.set_event_loop(loop)
  client.loop.run_until_complete(main())
Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Parece que el problema está relacionado con el bucle de eventos que no maneja correctamente los oyentes de Quart y Telethon al mismo tiempo. Una posible solución es utilizar el soporte WebSocket de Quart para crear un canal de comunicación bidireccional con el servidor de Telegram utilizando Telethon.

    Aquí hay una posible modificación al código:

    import os
    from dotenv import load_dotenv
    from telethon import TelegramClient, events
    from quart import Quart, websocket, jsonify
    
    
    # Cargar variables de entorno
    load_dotenv()
    
    # Variables globales
    allMessages = []
    
    # Habilitar conexión
    api_id = os.getenv("API_ID")
    api_hash = os.getenv("API_HASH")
    phone_number = os.getenv("PHONE_NUMBER")
    channel_username=os.getenv("CHANNEL")
    client = TelegramClient('abc', api_id, api_hash)
    client.start(phone_number)
    
    
    # Obtener entidad de chat
    chat = client.get_entity(channel_username)
    
    
    # Escuchar nuevos mensajes
    @client.on(events.NewMessage(incoming=True, chats=chat))
    async def handler(event):
        message = event.message
        allMessages.insert(0, message)
        print(message.stringify())
    
        # Enviar el mensaje a través del websocket al cliente
        await websocket.send(message.stringify())
    
    
    # Servidor web
    app = Quart(__name__)
    
    @app.route('/')
    async def index():
        return await app.send_static_file('index.html')
    
    
    @app.websocket('/messages/ws')
    async def route_messages_ws():
        # Registrar el websocket como oyente para nuevos mensajes
        await websocket.accept()
        await client.run_until_disconnected()
    
    
    @app.route('/messages/json')
    async def route_messages_json():
        # Devolver la lista de mensajes como datos JSON
        return jsonify([m.to_dict() for m in allMessages])
    
    
    if __name__ == '__main__':
        # Iniciar el servidor web
        app.run()
    

    En esta versión modificada, el código crea un endpoint WebSocket /messages/ws que acepta conexiones de clientes y se registra como oyente para nuevos mensajes utilizando Telethon. Cuando llega un nuevo mensaje, lo envía a todos los clientes conectados a través del WebSocket. El endpoint /messages/json devuelve la lista de mensajes recibidos en formato JSON.

    Esta aproximación también debería funcionar con Hypercorn, iniciando el servidor de esta manera:

    hypercorn main:app --websocket-capable
    

    Ten en cuenta la bandera --websocket-capable, que es necesaria para habilitar el soporte de WebSocket en Hypercorn.

Comments are closed.