commit 84d6b3d58fd06bd048b2e79bb0e4759755006bf8 Author: dymik739 Date: Sun Oct 23 17:20:32 2022 +0300 Initial commit diff --git a/main.py b/main.py new file mode 100644 index 0000000..36896d8 --- /dev/null +++ b/main.py @@ -0,0 +1,200 @@ +from telegram.ext import Updater, MessageHandler, Filters +import codecs +import time +import json +import sys +import os +import threading + +# global variables +STOP_REQUESTED = False + +# some functions that increase readability of the code +def readfile(filename): + try: + return codecs.open(filename, encoding = "utf-8").read() + except FileNotFoundError: + return False + except Exception as e: + print( "[ERROR] Unexpected error occured in readfile() ({0})".format(e) ) + return False + +# module object classes +class ModuleV1: + def __init__(self, path, code, enabled, alias): + self.version = 1 + self.enabled = enabled + self.code = code + self.alias = alias + self.path = path + + # set environmental variables + def set_env(self): + self.RESPONCE = "" + + # running the module + def process(self, msg): + self.set_env() + + self.MESSAGE = msg + try: + exec(self.code) + return self.RESPONCE + except Exception as e: + print("[ERROR] module: module \"{}\" ({}) raised exception \"{}\"".format(self.path, self.alias, e)) + + +# module control unit +class ModuleControlUnit: + def __init__(self): + self.modules = [] + self.reload_modules() + + print("[INFO] ModuleControlUnit: initialized successfully") + + def reload_modules(self): + for folder in os.listdir("modules/"): + try: + meta_raw = readfile("modules/{}/meta.json".format(folder)) + if not meta_raw: + print("[WARN] module_loader: no meta.json found in module folder \"{}\"".format(folder)) + continue + + meta = json.loads( meta_raw ) + if "version" in meta: + if meta["version"] == 1: + if "index_file" in meta: + index_file = meta["index_file"] + else: + index_file = "index.py" + + code = readfile( "modules/{}/{}".format(folder, index_file) ) + if not code: # False both when readfile() returns False and when the code string is empty + print("[WARN] reload_modules: module {} does not have any code, skipping...".format(folder)) + continue + + if "start_on_boot" in meta: + enabled = meta["start_on_boot"] + else: + enabled = False + + if "alias" in meta: + alias = meta["alias"] + else: + alias = None + + self.modules.append( ModuleV1( "modules/{}/".format(folder), code, enabled, alias ) ) + + print("[INFO] reload_modules: successfully loaded {} as {}".format(folder, alias)) + else: + print("[WARN] reload_modules: module {} requires unsupported version ({} > 1), skipping...".format(folder, meta["version"])) + except Exception as e: + print("[ERROR] module_loader: error while loading module \"{}\" ({})".format(folder, e)) + + def reload_module(self, folder_name): + try: + meta_raw = readfile("modules/{}/meta.json".format(folder)) + if not meta_raw: + print("[WARN] module_loader: no meta.json found in module folder \"{}\"".format(folder_name)) + return 1 + + meta = json.loads( readfile("modules/{}/meta.json".format(folder_name)) ) + if "version" in meta: + if meta["version"] == 1: + if "index_file" in meta: + index_file = meta["index_file"] + else: + index_file = "index.py" + + code = readfile( "modules/{}/{}".format(folder_name, index_file) ) + if not code: # False both when readfile() returns False and when the code string is empty + print("[WARN] reload_modules: module {} does not have any code, skipping...".format(folder_name)) + + if "start_on_boot" in meta: + enabled = meta["start_on_boot"] + else: + enabled = False + + if "alias" in meta: + alias = meta["alias"] + else: + alias = None + + self.modules.append( ModuleV1( code, enabled, alias ) ) + + print("[INFO] reload_modules: successfully loaded {} as {}".format(folder_name, alias)) + else: + print("[WARN] reload_modules: module {} requires unsupported version ({} > 1), skipping...".format(folder_name, meta["version"])) + except Exception as e: + print("[ERROR] module_loader: error while loading module \"{}\" ({})".format(folder_name, e)) + +# message queue object to go back to synchronous message processing +#class MessageQueue: +# def __init__(self): +# print("[INFO] Initializing the message queue...") +# self.queue = [] + + +# synchronous message processor +def queue_processor(): + while True: + if len(message_queue) > 0: + msg = message_queue[0] + print("[DEBUG] queue_processor: {}".format(msg)) # debug + + # modules will be used in here + for mod in mcu.modules: + if mod.enabled: + if mod.version == 1: + responce = mod.process(msg) + if len(responce) > 0: + updater.bot.send_message(chat_id = msg.chat.id, text = responce) + print("Responded using module {} ({}) with text: {}".format(mod.path, mod.alias, responce)) + break + + del message_queue[0] + else: + if STOP_REQUESTED: + break + else: + time.sleep(1) + + print("[INFO] queue_processor thread stops successfully") + + +# telegram bot processor +def message_handler(update, context): + print("[DEBUG] Received new message") # just for testing + message_queue.append(update.message) + + +# --- Final stage --- + + +# initializing services and queues + +message_queue = [] + +mcu = ModuleControlUnit() + +processor_thread = threading.Thread( target = queue_processor, args = [] ) +processor_thread.start() + + +# connecting to Telegram servers and listening for messages + +TOKEN = readfile("config/token") +if not TOKEN: + print("[CRIT] Token has not been defined, quitting") + sys.exit(1) + +# connect to Telegram servers +updater = Updater(TOKEN, use_context = True) +dispatcher = updater.dispatcher + +# assign the handler for messages +dispatcher.add_handler(MessageHandler(Filters.text, message_handler)) + +# run the bot +updater.start_polling() +updater.idle() diff --git a/modules/echo-v1.0/index.py b/modules/echo-v1.0/index.py new file mode 100644 index 0000000..ca789de --- /dev/null +++ b/modules/echo-v1.0/index.py @@ -0,0 +1 @@ +self.RESPONCE = self.MESSAGE["text"] diff --git a/modules/echo-v1.0/meta.json b/modules/echo-v1.0/meta.json new file mode 100644 index 0000000..cd22017 --- /dev/null +++ b/modules/echo-v1.0/meta.json @@ -0,0 +1,5 @@ +{ + "version": 1, + "index_file": "index.py", + "start_on_boot": true +}