feat: implement port reconfiguration for webclients (#586)

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
dw-0
2024-10-24 12:25:44 +02:00
committed by GitHub
parent 2df364512b
commit 81b7b156b9
7 changed files with 205 additions and 45 deletions

View File

@@ -34,7 +34,7 @@ from utils.input_utils import get_confirm
from utils.instance_utils import get_instances from utils.instance_utils import get_instances
def install_client_config(client_data: BaseWebClient) -> None: def install_client_config(client_data: BaseWebClient, cfg_backup=True) -> None:
client_config: BaseWebClientConfig = client_data.client_config client_config: BaseWebClientConfig = client_data.client_config
display_name = client_config.display_name display_name = client_config.display_name
@@ -56,6 +56,7 @@ def install_client_config(client_data: BaseWebClient) -> None:
download_client_config(client_config) download_client_config(client_config)
create_client_config_symlink(client_config, kl_instances) create_client_config_symlink(client_config, kl_instances)
if cfg_backup:
backup_printer_config_dir() backup_printer_config_dir()
add_config_section( add_config_section(

View File

@@ -53,8 +53,8 @@ def print_client_port_select_dialog(
dialog_content.extend( dialog_content.extend(
[ [
"\n\n", "\n\n",
"The following ports were found to be in use already:", "The following ports were found to be already in use:",
*[f"{port}" for port in ports_in_use], *[f"{p}" for p in ports_in_use if p != port],
] ]
) )

View File

@@ -36,8 +36,9 @@ from components.webui_client.client_utils import (
symlink_webui_nginx_log, symlink_webui_nginx_log,
) )
from core.instance_manager.instance_manager import InstanceManager from core.instance_manager.instance_manager import InstanceManager
from core.logger import Logger from core.logger import DialogCustomColor, DialogType, Logger
from utils.common import check_install_dependencies from core.settings.kiauh_settings import KiauhSettings
from utils.common import backup_printer_config_dir, check_install_dependencies
from utils.config_utils import add_config_section from utils.config_utils import add_config_section
from utils.fs_utils import unzip from utils.fs_utils import unzip
from utils.input_utils import get_confirm from utils.input_utils import get_confirm
@@ -49,16 +50,11 @@ from utils.sys_utils import (
) )
def install_client(client: BaseWebClient) -> None: def install_client(
if client is None: client: BaseWebClient,
raise ValueError("Missing parameter client_data!") settings: KiauhSettings,
reinstall: bool = False,
if client.client_dir.exists(): ) -> None:
Logger.print_info(
f"{client.display_name} seems to be already installed! Skipped ..."
)
return
mr_instances: List[Moonraker] = get_instances(Moonraker) mr_instances: List[Moonraker] = get_instances(Moonraker)
enable_remotemode = False enable_remotemode = False
@@ -88,7 +84,10 @@ def install_client(client: BaseWebClient) -> None:
question = f"Download the recommended {client_config.display_name}?" question = f"Download the recommended {client_config.display_name}?"
install_client_cfg = get_confirm(question, allow_go_back=False) install_client_cfg = get_confirm(question, allow_go_back=False)
port: int = get_client_port_selection(client) default_port: int = int(settings.get(client.name, "port"))
port: int = (
default_port if reinstall else get_client_port_selection(client, settings)
)
check_install_dependencies({"nginx"}) check_install_dependencies({"nginx"})
@@ -96,7 +95,8 @@ def install_client(client: BaseWebClient) -> None:
download_client(client) download_client(client)
if enable_remotemode and client.client == WebClientType.MAINSAIL: if enable_remotemode and client.client == WebClientType.MAINSAIL:
enable_mainsail_remotemode() enable_mainsail_remotemode()
if mr_instances:
backup_printer_config_dir()
add_config_section( add_config_section(
section=f"update_manager {client.name}", section=f"update_manager {client.name}",
instances=mr_instances, instances=mr_instances,
@@ -108,8 +108,9 @@ def install_client(client: BaseWebClient) -> None:
], ],
) )
InstanceManager.restart_all(mr_instances) InstanceManager.restart_all(mr_instances)
if install_client_cfg and kl_instances: if install_client_cfg and kl_instances:
install_client_config(client) install_client_config(client, False)
copy_upstream_nginx_cfg() copy_upstream_nginx_cfg()
copy_common_vars_nginx_cfg() copy_common_vars_nginx_cfg()
@@ -127,12 +128,24 @@ def install_client(client: BaseWebClient) -> None:
cmd_sysctl_service("nginx", "restart") cmd_sysctl_service("nginx", "restart")
except Exception as e: except Exception as e:
Logger.print_error(f"{client.display_name} installation failed!\n{e}") Logger.print_error(e)
Logger.print_dialog(
DialogType.ERROR,
center_content=True,
content=[f"{client.display_name} installation failed!"],
)
return return
log = f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{port}" # noinspection HttpUrlsUsage
Logger.print_ok(f"{client.display_name} installation complete!", start="\n") Logger.print_dialog(
Logger.print_ok(log, prefix=False, end="\n\n") DialogType.CUSTOM,
custom_title=f"{client.display_name} installation complete!",
custom_color=DialogCustomColor.GREEN,
center_content=True,
content=[
f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{port}",
],
)
def download_client(client: BaseWebClient) -> None: def download_client(client: BaseWebClient) -> None:

View File

@@ -370,19 +370,26 @@ def read_ports_from_nginx_configs() -> List[int]:
return sorted(ports_to_ints_list, key=lambda x: int(x)) return sorted(ports_to_ints_list, key=lambda x: int(x))
def get_client_port_selection(client: BaseWebClient) -> int: def get_client_port_selection(
settings = KiauhSettings() client: BaseWebClient,
settings: KiauhSettings,
reconfigure=False,
) -> int:
default_port: int = int(settings.get(client.name, "port")) default_port: int = int(settings.get(client.name, "port"))
ports_in_use: List[int] = read_ports_from_nginx_configs() ports_in_use: List[int] = read_ports_from_nginx_configs()
next_free_port: int = get_next_free_port(ports_in_use) next_free_port: int = get_next_free_port(ports_in_use)
port: int = next_free_port if default_port in ports_in_use else default_port port: int = (
next_free_port
if not reconfigure and default_port in ports_in_use
else default_port
)
print_client_port_select_dialog(client.display_name, port, ports_in_use) print_client_port_select_dialog(client.display_name, port, ports_in_use)
while True: while True:
question = f"Configure {client.display_name} for port" _type = "Reconfigure" if reconfigure else "Configure"
question = f"{_type} {client.display_name} for port"
port_input = get_number_input(question, min_count=80, default=port) port_input = get_number_input(question, min_count=80, default=port)
if port_input not in ports_in_use: if port_input not in ports_in_use:
@@ -400,3 +407,23 @@ def get_next_free_port(ports_in_use: List[int]) -> int:
used_ports = set(map(int, ports_in_use)) used_ports = set(map(int, ports_in_use))
return min(valid_ports - used_ports) return min(valid_ports - used_ports)
def set_listen_port(client: BaseWebClient, curr_port: int, new_port: int) -> None:
"""
Set the port the client should listen on in the NGINX config
:param curr_port: The current port the client listens on
:param new_port: The new port to set
:param client: The client to set the port for
:return: None
"""
config = NGINX_SITES_AVAILABLE.joinpath(client.name)
with open(config, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if "listen" in line:
lines[i] = line.replace(str(curr_port), str(new_port))
with open(config, "w") as f:
f.writelines(lines)

View File

@@ -0,0 +1,104 @@
# ======================================================================= #
# Copyright (C) 2020 - 2024 Dominik Willner <th33xitus@gmail.com> #
# #
# 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 #
# ======================================================================= #
from __future__ import annotations
import textwrap
from typing import Type
from components.webui_client.base_data import BaseWebClient
from components.webui_client.client_setup import install_client
from components.webui_client.client_utils import (
get_client_port_selection,
set_listen_port,
)
from core.constants import COLOR_CYAN, COLOR_GREEN, RESET_FORMAT
from core.logger import DialogCustomColor, DialogType, Logger
from core.menus import Option
from core.menus.base_menu import BaseMenu
from core.settings.kiauh_settings import KiauhSettings, WebUiSettings
from utils.sys_utils import cmd_sysctl_service, get_ipv4_addr
# noinspection PyUnusedLocal
class ClientInstallMenu(BaseMenu):
def __init__(
self, client: BaseWebClient, previous_menu: Type[BaseMenu] | None = None
):
super().__init__()
self.previous_menu: Type[BaseMenu] | None = previous_menu
self.client: BaseWebClient = client
self.settings = KiauhSettings()
self.client_settings: WebUiSettings = self.settings[client.name]
def set_previous_menu(self, previous_menu: Type[BaseMenu] | None) -> None:
from core.menus.install_menu import InstallMenu
self.previous_menu = previous_menu if previous_menu is not None else InstallMenu
def set_options(self) -> None:
self.options = {
"1": Option(method=self.reinstall_client),
"2": Option(method=self.change_listen_port),
}
def print_menu(self) -> None:
client_name = self.client.display_name
header = f" [ Installation Menu > {client_name} ] "
color = COLOR_GREEN
count = 62 - len(color) - len(RESET_FORMAT)
port = f"(Current: {COLOR_CYAN}{int(self.client_settings.port)}{RESET_FORMAT})"
menu = textwrap.dedent(
f"""
╔═══════════════════════════════════════════════════════╗
{color}{header:~^{count}}{RESET_FORMAT}
╟───────────────────────────────────────────────────────╢
║ 1) Reinstall {client_name:16}
║ 2) Reconfigure Listen Port {port:<34}
╟───────────────────────────────────────────────────────╢
"""
)[1:]
print(menu, end="")
def reinstall_client(self, **kwargs) -> None:
install_client(self.client, settings=self.settings, reinstall=True)
def change_listen_port(self, **kwargs) -> None:
curr_port = int(self.client_settings.port)
new_port = get_client_port_selection(
self.client,
self.settings,
reconfigure=True,
)
cmd_sysctl_service("nginx", "stop")
set_listen_port(self.client, curr_port, new_port)
Logger.print_status("Saving new port configuration ...")
self.client_settings.port = new_port
self.settings.save()
Logger.print_ok("Port configuration saved!")
cmd_sysctl_service("nginx", "start")
# noinspection HttpUrlsUsage
Logger.print_dialog(
DialogType.CUSTOM,
custom_title="Port reconfiguration complete!",
custom_color=DialogCustomColor.GREEN,
center_content=True,
content=[
f"Open {self.client.display_name} now on: "
f"http://{get_ipv4_addr()}:{new_port}",
],
)
def _go_back(self, **kwargs) -> None:
if self.previous_menu is not None:
self.previous_menu().run()

View File

@@ -15,13 +15,17 @@ from components.crowsnest.crowsnest import install_crowsnest
from components.klipper import klipper_setup from components.klipper import klipper_setup
from components.klipperscreen.klipperscreen import install_klipperscreen from components.klipperscreen.klipperscreen import install_klipperscreen
from components.moonraker import moonraker_setup from components.moonraker import moonraker_setup
from components.webui_client import client_setup from components.webui_client.client_config.client_config_setup import (
from components.webui_client.client_config import client_config_setup install_client_config,
)
from components.webui_client.client_setup import install_client
from components.webui_client.fluidd_data import FluiddData from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData from components.webui_client.mainsail_data import MainsailData
from components.webui_client.menus.client_install_menu import ClientInstallMenu
from core.constants import COLOR_GREEN, RESET_FORMAT from core.constants import COLOR_GREEN, RESET_FORMAT
from core.menus import Option from core.menus import Option
from core.menus.base_menu import BaseMenu from core.menus.base_menu import BaseMenu
from core.settings.kiauh_settings import KiauhSettings
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
@@ -80,16 +84,24 @@ class InstallMenu(BaseMenu):
moonraker_setup.install_moonraker() moonraker_setup.install_moonraker()
def install_mainsail(self, **kwargs) -> None: def install_mainsail(self, **kwargs) -> None:
client_setup.install_client(MainsailData()) client: MainsailData = MainsailData()
if client.client_dir.exists():
ClientInstallMenu(client, self.__class__).run()
else:
install_client(client, settings=KiauhSettings())
def install_mainsail_config(self, **kwargs) -> None: def install_mainsail_config(self, **kwargs) -> None:
client_config_setup.install_client_config(MainsailData()) install_client_config(MainsailData())
def install_fluidd(self, **kwargs) -> None: def install_fluidd(self, **kwargs) -> None:
client_setup.install_client(FluiddData()) client: FluiddData = FluiddData()
if client.client_dir.exists():
ClientInstallMenu(client, self.__class__).run()
else:
install_client(client, settings=KiauhSettings())
def install_fluidd_config(self, **kwargs) -> None: def install_fluidd_config(self, **kwargs) -> None:
client_config_setup.install_client_config(FluiddData()) install_client_config(FluiddData())
def install_klipperscreen(self, **kwargs) -> None: def install_klipperscreen(self, **kwargs) -> None:
install_klipperscreen() install_klipperscreen()

View File

@@ -27,6 +27,9 @@ def add_config_section(
instances: List[InstanceType], instances: List[InstanceType],
options: List[ConfigOption] | None = None, options: List[ConfigOption] | None = None,
) -> None: ) -> None:
if not instances:
return
for instance in instances: for instance in instances:
cfg_file = instance.cfg_file cfg_file = instance.cfg_file
Logger.print_status(f"Add section '[{section}]' to '{cfg_file}' ...") Logger.print_status(f"Add section '[{section}]' to '{cfg_file}' ...")