def __init__(self, bot: 'Bot', update_queue: Queue, workers: int = 4, exception_event: Event = None, job_queue: 'JobQueue' = None): """ Initialize the dispatcher and its modules. """ super().__init__(bot, update_queue, workers=workers, exception_event=exception_event, job_queue=job_queue) self.add_error_handler(error_handler, True) self.modules = [] LOGI("Parsing modules") for module in modules: try: module_instance = module() except Exception as e: LOGE(f"Error initializing module {module.name}, will be skipped\n" f"Error: {e}") else: self.modules.append(module_instance) LOGI("Modules parsed") LOGI("Loading modules") for module in self.modules: self.load_module(module) LOGI("Modules loaded")
def disable_module(self: Dispatcher, module_name: str): """ Unload a provided module and remove its command handler from the bot's dispatcher. """ LOGI(f"Loading module {module_name}") module = get_module(module_name) if module is None: raise ModuleNotFoundError(f"Module {module_name} not found") with self.modules_status_lock: if not module_name in self.modules_status: self.modules_status[module_name] = MODULE_STATUS_DISABLED if self.modules_status[module_name] == MODULE_STATUS_DISABLED: raise AttributeError("Module is already disabled") self.modules_status[module_name] = MODULE_STATUS_DISABLING try: for command in module.commands: self.add_handler(command.handler) except: LOGE(f"Failed to add handler for module {module_name}") self.modules_status[module_name] = MODULE_STATUS_ERROR self.modules_status[module_name] = MODULE_STATUS_DISABLED LOGI(f"Module {module_name} disabled")
def main(): global modules modules += import_bot_modules() updater = HomeBotUpdater(get_config("BOT_API_TOKEN")) LOGI(f"HomeBot started, version {__version__}") LOGI(f"Bot username: @{updater.bot.get_me().username}") updater.start_polling()
def upload(self, file: Path, destination: Path): """Upload an artifact using settings from config.env.""" if not file.is_file(): raise FileNotFoundError("File doesn't exists") if self.destination_path_base is None: destination_path = destination else: destination_path = self.destination_path_base / destination LOGI(f"Started uploading of {file.name}") if self.method == "localcopy": os.makedirs(destination_path, exist_ok=True) shutil.copy(file, destination_path) elif self.method == "ftp": ftp = FTP(self.server) ftp.login(self.username, self.password) ftp_chdir(ftp, destination_path) with open(file, 'rb') as f: ftp.storbinary('STOR %s' % file.name, f) f.close() ftp.close() elif self.method == "sftp": transport = paramiko.Transport(self.server) transport.connect(username=self.username, password=self.password) sftp = paramiko.SFTPClient.from_transport(transport) sftp_chdir(sftp, destination_path) sftp.put(file, file.name) sftp.close() transport.close() LOGI(f"Finished uploading of {file.name}") return True
def user_is_admin(user_id): """ Check if the given user ID is in the list of the approved user IDs. """ if user_id not in get_config("libadmin.approved_user_ids", []): LOGI(f"Access denied to user {user_id}") return False LOGI(f"Access granted to user {user_id}") return True
def user_is_admin(user_id): """ Check if the given user ID is in the list of the approved user IDs. """ if str(user_id) not in get_config("CI_APPROVED_USER_IDS").split(): LOGI(f"Access denied to user {user_id}") return False LOGI(f"Access granted to user {user_id}") return True
def unload_module(self, module): """ Unload a provided module and remove its command handler from the bot's dispatcher. """ LOGI(f"Unloading module {module.name}") module.set_status("Stopping") for command in module.commands: self.remove_handler(command.handler) module.set_status("Disabled") LOGI(f"Module {module.name} unloaded")
def load_module(self, module): """ Load a provided module and add its command handler to the bot's dispatcher. """ LOGI(f"Loading module {module.name}") module.set_status("Starting up") for command in module.commands: self.add_handler(command.handler) module.set_status("Running") LOGI(f"Module {module.name} loaded")
def speedtest(update: Update, context: CallbackContext): message_id = update.message.reply_text("Running speedtest...").message_id LOGI("Started") speedtest = Speedtest() speedtest.get_best_server() speedtest.download() speedtest.upload() speedtest.results.share() results_dict = speedtest.results.dict() download = str(results_dict["download"] // 10 ** 6) upload = str(results_dict["upload"] // 10 ** 6) context.bot.edit_message_text(chat_id=update.message.chat_id, message_id=message_id, text=f"Download: {download} mbps\n" f"Upload: {upload} mbps") LOGI(f"Finished, download: {download} mbps, upload: {upload} mbps")
def run(self): while True: self.current_workflow = self.queue.get() self.running = True workflow_name = self.current_workflow.project_name LOGI(f"CI workflow started, project: {workflow_name}") try: self.current_workflow.run() except Exception as e: message = f"Unhandled exception from CI workflow: {type(e)}: {e}" LOGE(message) self.current_workflow.update.message.reply_text( f"Error: {message}") self.running = False LOGI(f"CI workflow finished, project: {workflow_name}") self.current_workflow = None
def unload_module(self, module: str): """ Unload a provided module and remove its command handler from the bot's dispatcher. """ LOGI(f"Unloading module {module}") module_class = self.modules[module] if module_class.status == "Disabled": raise AttributeError("Module is already unloaded") module_class.set_status("Stopping") for command in module_class.commands: self.remove_handler(command.handler) module_class.set_status("Disabled") LOGI(f"Module {module} unloaded")
def load_module(self, module: str): """ Load a provided module and add its command handler to the bot's dispatcher. """ LOGI(f"Loading module {module}") module_class = self.modules[module] if module_class.status == "Running": raise AttributeError("Module is already loaded") module_class.set_status("Starting up") for command in module_class.commands: self.add_handler(command.handler) module_class.set_status("Running") LOGI(f"Module {module} loaded")
def run(self): while True: try: self.current_workflow = self.queue.get() workflow_name = self.current_workflow.project_name LOGI(f"CI workflow started, project: {workflow_name}") try: self.current_workflow.run() except Exception as e: message = "Unhandled exception from CI workflow:\n" message += format_exception(e) LOGE(message) self.current_workflow.update.message.reply_text( f"Error: {message}") except Exception as e: message = "Unhandled exception from QueueManager:\n" message += format_exception(e) LOGE(message) finally: LOGI(f"CI workflow finished, project: {workflow_name}") self.current_workflow = None
def register_module(mdlintf: ModuleInterface): with _mdlbinder_lock: name = mdlintf.name if name in _mdlbinder: LOGW( f'Replacing already registered module "{mdlintf.name}" with a new instance, ' f'old ID: {id(_mdlbinder[name])}, new ID: {id(mdlintf)}') del _mdlbinder[name] _mdlbinder[name] = mdlintf LOGI(f'Registered module "{name}" with ID {id(_mdlbinder[name])}')
def ci(update: Update, context: CallbackContext): if not user_is_admin(update.message.from_user.id): update.message.reply_text("Error: You are not authorized to use CI function of this bot.\n" "Ask to who host this bot to add you to the authorized people list") return if get_config("CI_CHANNEL_ID") == "": update.message.reply_text("Error: CI channel or user ID not defined") LOGE("CI channel or user ID not defined") return parser = CIParser(prog="/ci") parser.set_output(update.message.reply_text) parser.add_argument('project', help='CI project', nargs='?', default=None,) parser.add_argument('-s', '--status', action='store_true', help='show queue status') args, project_args = parser.parse_known_args(context.args) if args.status: update.message.reply_text(queue_manager.get_formatted_queue_list()) return if args.project is None: parser.error("Please specify a project") try: project_class = import_module(f"homebot.modules.ci.projects.{args.project}", package="Project").Project except ModuleNotFoundError: update.message.reply_text(f"Error: Project script not found") return except Exception as e: text = "Error: Error while importing project:" text += format_exception(e) update.message.reply_text(text) LOGE(text) return try: project = project_class(update, context, project_args) except Exception as e: text = "Error: Project class initialization failed:\n" text += format_exception(e) update.message.reply_text(text) LOGE(text) return workflow = Workflow(project) queue_manager.put(workflow) update.message.reply_text("Workflow added to the queue") LOGI("Workflow added to the queue")
def main(): updater = HomeBot(get_config("bot.api_token")) LOGI(f"HomeBot started, version {__version__}") LOGI(f"Bot username: @{updater.bot.get_me().username}") updater.start_polling()