import threading import telegram import strings import configloader import sys import queue as queuem class StopSignal: """A data class that should be sent to the worker when the conversation has to be stopped abnormally.""" def __init__(self, reason: str=""): self.reason = reason class ChatWorker(threading.Thread): """A worker for a single conversation. A new one is created every time the /start command is sent.""" def __init__(self, bot: telegram.Bot, chat: telegram.Chat, *args, **kwargs): # Initialize the thread super().__init__(name=f"ChatThread {chat.first_name}", *args, **kwargs) # Store the bot and chat info inside the class self.bot = bot self.chat = chat # The sending pipe is stored in the ChatWorker class, allowing the forwarding of messages to the chat process self.queue = queuem.Queue() def run(self): """The conversation code.""" # TODO: catch all the possible exceptions # Welcome the user to the bot self.bot.send_message(self.chat.id, strings.conversation_after_start) # TODO: Send a command list or something while True: # For now, echo the sent message update = self._receive_next_update() self.bot.send_message(self.chat.id, f"{threading.current_thread().name} {update.message.text}") def stop(self, reason: str=""): """Gracefully stop the worker process""" # Send a stop message to the thread self.queue.put(StopSignal(reason)) # Wait for the thread to stop self.join() def _receive_next_update(self) -> telegram.Update: """Get the next update from the queue. If no update is found, block the process until one is received. If a stop signal is sent, try to gracefully stop the thread.""" # Pop data from the queue try: data = self.queue.get(timeout=int(configloader.config["Telegram"]["conversation_timeout"])) except queuem.Empty: # If the conversation times out, gracefully stop the thread self._graceful_stop() # Check if the data is a stop signal instance if isinstance(data, StopSignal): # Gracefully stop the process self._graceful_stop() # Return the received update return data def _graceful_stop(self): """Handle the graceful stop of the thread.""" # Notify the user that the session has expired self.bot.send_message(self.chat.id, strings.conversation_expired) # End the process sys.exit(0)