# ======================================================================= # # Copyright (C) 2020 - 2024 Dominik Willner # # # # This file is part of KIAUH - Klipper Installation And Update Helper # # https://github.com/dw-0/kiauh # # # # This file may be distributed under the terms of the GNU GPLv3 license # # ======================================================================= # import shutil from typing import Dict, List, Optional from components.moonraker import ( DEFAULT_MOONRAKER_PORT, MODULE_PATH, MOONRAKER_BACKUP_DIR, MOONRAKER_DB_BACKUP_DIR, MOONRAKER_DIR, MOONRAKER_ENV_DIR, ) from components.moonraker.moonraker import Moonraker from components.webui_client.base_data import BaseWebClient from components.webui_client.client_utils import enable_mainsail_remotemode from components.webui_client.mainsail_data import MainsailData from core.backup_manager.backup_manager import BackupManager from core.config_manager.config_manager import ConfigManager from core.instance_manager.instance_manager import InstanceManager from utils.common import get_install_status from utils.logger import Logger from utils.sys_utils import ( get_ipv4_addr, ) from utils.types import ComponentStatus def get_moonraker_status() -> ComponentStatus: return get_install_status(MOONRAKER_DIR, MOONRAKER_ENV_DIR, Moonraker) def create_example_moonraker_conf( instance: Moonraker, ports_map: Dict[str, int], clients: Optional[List[BaseWebClient]] = None, ) -> None: Logger.print_status(f"Creating example moonraker.conf in '{instance.cfg_dir}'") if instance.cfg_file.is_file(): Logger.print_info(f"'{instance.cfg_file}' already exists.") return source = MODULE_PATH.joinpath("assets/moonraker.conf") target = instance.cfg_file try: shutil.copy(source, target) except OSError as e: Logger.print_error(f"Unable to create example moonraker.conf:\n{e}") return ports = [ ports_map.get(instance) for instance in ports_map if ports_map.get(instance) is not None ] if ports_map.get(instance.suffix) is None: # this could be improved to not increment the max value of the ports list and assign it as the port # as it can lead to situation where the port for e.g. instance moonraker-2 becomes 7128 if the port # of moonraker-1 is 7125 and moonraker-3 is 7127 and there are moonraker.conf files for moonraker-1 # and moonraker-3 already. though, there does not seem to be a very reliable way of always assigning # the correct port to each instance and the user will likely be required to correct the value manually. port = max(ports) + 1 if ports else DEFAULT_MOONRAKER_PORT else: port = ports_map.get(instance.suffix) ports_map[instance.suffix] = port ip = get_ipv4_addr().split(".")[:2] ip.extend(["0", "0/16"]) uds = instance.comms_dir.joinpath("klippy.sock") cm = ConfigManager(target) trusted_clients = f"\n{'.'.join(ip)}" trusted_clients += cm.get_value("authorization", "trusted_clients") cm.set_value("server", "port", str(port)) cm.set_value("server", "klippy_uds_address", str(uds)) cm.set_value("authorization", "trusted_clients", trusted_clients) # add existing client and client configs in the update section if clients is not None and len(clients) > 0: for c in clients: # client part c_section = f"update_manager {c.name}" c_options = [ ("type", "web"), ("channel", "stable"), ("repo", c.repo_path), ("path", c.client_dir), ] cm.config.add_section(section=c_section) for option in c_options: cm.config.set(c_section, option[0], option[1]) # client config part c_config = c.client_config if c_config.config_dir.exists(): c_config_section = f"update_manager {c_config.name}" c_config_options = [ ("type", "git_repo"), ("primary_branch", "master"), ("path", c_config.config_dir), ("origin", c_config.repo_url), ("managed_services", "klipper"), ] cm.config.add_section(section=c_config_section) for option in c_config_options: cm.config.set(c_config_section, option[0], option[1]) cm.write_config() Logger.print_ok(f"Example moonraker.conf created in '{instance.cfg_dir}'") def moonraker_to_multi_conversion(new_name: str) -> None: """ Converts the first instance in the List of Moonraker instances to an instance with a new name. This method will be called when converting from a single Klipper instance install to a multi instance install when Moonraker is also already installed with a single instance. :param new_name: new name the previous single instance is renamed to :return: None """ im = InstanceManager(Moonraker) instances: List[Moonraker] = im.instances if not instances: return # in case there are multiple Moonraker instances, we don't want to do anything if len(instances) > 1: Logger.print_info("More than a single Moonraker instance found. Skipped ...") return Logger.print_status("Convert Moonraker single to multi instance ...") # remove the old single instance im.current_instance = im.instances[0] im.stop_instance() im.disable_instance() im.delete_instance() # create a new moonraker instance with the new name new_instance = Moonraker(suffix=new_name) im.current_instance = new_instance # patch the server sections klippy_uds_address value to match the new printer_data foldername cm = ConfigManager(new_instance.cfg_file) if cm.config.has_section("server"): cm.set_value( "server", "klippy_uds_address", str(new_instance.comms_dir.joinpath("klippy.sock")), ) cm.write_config() # create, enable and start the new moonraker instance im.create_instance() im.enable_instance() im.start_instance() # if mainsail is installed, we enable mainsails remote mode if MainsailData().client_dir.exists() and len(im.instances) > 1: enable_mainsail_remotemode() def backup_moonraker_dir(): bm = BackupManager() bm.backup_directory("moonraker", source=MOONRAKER_DIR, target=MOONRAKER_BACKUP_DIR) bm.backup_directory( "moonraker-env", source=MOONRAKER_ENV_DIR, target=MOONRAKER_BACKUP_DIR ) def backup_moonraker_db_dir() -> None: im = InstanceManager(Moonraker) instances: List[Moonraker] = im.instances bm = BackupManager() for instance in instances: name = f"database-{instance.data_dir_name}" bm.backup_directory( name, source=instance.db_dir, target=MOONRAKER_DB_BACKUP_DIR )