diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc11164 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +Thumbs.db + +.vscode/ diff --git a/klipper-priority-fix.py b/klipper-priority-fix.py new file mode 100644 index 0000000..d3e00a7 --- /dev/null +++ b/klipper-priority-fix.py @@ -0,0 +1,39 @@ +import psutil +import os +import time +import sys + +KLIPPY_PROCESS_NAME = "klippy.py" + +def set_high_priority(pid, method="nice"): + if method == "chrt": + cmd = f"sudo chrt --verbose --all-tasks --pid 1 {pid}" + elif method == "nice": + cmd = f"sudo renice -n -20 -p {pid}" + else: + raise ValueError(f"Unsupported priority method: {method}") + + os.system(cmd) + +def main(method="nice"): + while True: + try: + # Check if Klippy is running + klippy_process = None + for process in psutil.process_iter(["pid", "name", "cmdline"]): + if KLIPPY_PROCESS_NAME in process.info["name"] or KLIPPY_PROCESS_NAME in ' '.join(process.info["cmdline"]): + klippy_process = process + break + + if klippy_process: + set_high_priority(klippy_process.info["pid"], method=method) + + except Exception as e: + print(f"Error: {e}") + + time.sleep(5) # check every 5 seconds + +if __name__ == "__main__": + allowed_methods = ["chrt", "nice"] + method = sys.argv[1] if len(sys.argv) > 1 and sys.argv[1] in allowed_methods else "nice" + main(method=method) diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..4d3927c --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash + +# +# Installation script for klipper-priority-fix for Klipper. +# +# Based loosely on the following files/projects: +# - https://github.com/gobackup/gobackup/blob/main/install +# - https://github.com/eliteSchwein/mooncord/blob/master/scripts/install.sh +# + +# Enable error handling. +set -eo pipefail + +# Enable script debugging. +# set -x + +# Get the script path. +SCRIPT_PATH="$(cd "$(dirname "$0")" >/dev/null 2>&1; pwd -P)" + +# Define global variables. +KLIPPER_PRIORITY_FIX_ROOT_PATH="$(cd "${SCRIPT_PATH}/.." >/dev/null 2>&1; pwd -P)" +KLIPPER_PRIORITY_FIX_INSTALL_PATH="/usr/local/bin" +KLIPPER_PRIORITY_FIX_SERVICE_NAME="klipper-priority-fix" +KLIPPER_PRIORITY_FIX_SERVICE_VERSION="1" + +source "${SCRIPT_PATH}/util.sh" + +# Ensure Python is available and meets the minimum version requirement (e.g., 3.6+) +if ! command -v python3 &> /dev/null; then + echo "Python3 is not installed. Please install Python3 and try again." + exit 1 +fi +python_version=$(python3 --version | awk '{print $2}') +if [[ "$python_version" < "3.6" ]]; then + echo "Python version 3.6 or higher is required. Current version: $python_version" + exit 1 +fi +PYTHON_PATH="$(which python3)" + +# Function for installing or updating the custom klipper-priority-fix binary. +function install_klipper-priority-fix_binary() { + local source_path="${KLIPPER_PRIORITY_FIX_ROOT_PATH}/klipper-priority-fix.py" + local target_path="${KLIPPER_PRIORITY_FIX_INSTALL_PATH}/klipper-priority-fix" + + # Check if this is a fresh install + if test -e "${target_path}"; then + echo "klipper-priority-fix binary already installed, checking for updates ..." + local source_hash="$(shasum -a 256 "${source_path}" | awk '{print $1}')" + local target_hash="$(shasum -a 256 "${target_path}" | awk '{print $1}')" + if test "${source_hash}" = "${target_hash}"; then + echo "klipper-priority-fix binary already up-to-date" + return + else + echo "klipper-priority-fix binary is out-of-date, updating ..." + fi + else + echo "klipper-priority-fix binary is not installed, installing ..." + fi + + # Check if running as root + if test $(id -u) -eq 0; then + cp -f "${source_path}" "${target_path}" + chmod +x "${target_path}" + else + # Check if sudo is available + if ! command -v sudo &> /dev/null; then + echo "This script must be run as root or with sudo." + exit 1 + fi + sudo cp -f "${source_path}" "${target_path}" + sudo chmod +x "${target_path}" + fi + + echo "klipper-priority-fix binary successfully installed" +} + +# Function for installing or updating the custom systemd service for klipper-priority-fix. +function install_klipper-priority-fix_service() { + local source_path="/tmp/${KLIPPER_PRIORITY_FIX_SERVICE_NAME}.service" + local target_path="/etc/systemd/system/${KLIPPER_PRIORITY_FIX_SERVICE_NAME}.service" + + local user="$(id -un)" + if test -z "${user}"; then + echo "ERROR: Could not determine current user name" >&2 + exit 1 + fi + + local group="$(id -gn)" + if test -z "${group}"; then + echo "ERROR: Could not determine current group name" >&2 + exit 1 + fi + + # Echo a systemd service file to the temporary directory. + rm -f "${source_path}" || true + cat <> "${source_path}" +# KLIPPER_PRIORITY_FIX_SERVICE_VERSION=${KLIPPER_PRIORITY_FIX_SERVICE_VERSION} +[Unit] +Description=Klipper Priority Manager +Requires=klipper.service +After=klipper.service + +[Service] +Type=simple +User=${user} +Group=${group} +ExecStart=${PYTHON_PATH} ${KLIPPER_PRIORITY_FIX_INSTALL_PATH}/klipper-priority-fix +WorkingDirectory=${HOME} +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOT + + # Check if this is a fresh install + if test -e "${target_path}"; then + echo "klipper-priority-fix systemd service already installed, checking for updates ..." + + # Check the KLIPPER_PRIORITY_FIX_SERVICE_VERSION of the service file to determine if we need to update it + local service_version="$(grep "^# KLIPPER_PRIORITY_FIX_SERVICE_VERSION=" "${target_path}" | awk -F= '{print $NF}')" + if test "${service_version}" = "${KLIPPER_PRIORITY_FIX_SERVICE_VERSION}"; then + echo "klipper-priority-fix systemd service already up-to-date" + return + else + echo "Updating klipper-priority-fix systemd service from version ${service_version} to ${KLIPPER_PRIORITY_FIX_SERVICE_VERSION} ..." + fi + else + echo "klipper-priority-fix systemd service is not installed, installing ..." + fi + + # Check if running as root + if test $(id -u) -eq 0; then + cp -f "${source_path}" "${target_path}" + else + # Check if sudo is available + if ! command -v sudo &> /dev/null; then + echo "This script must be run as root or with sudo." + exit 1 + fi + sudo cp -f "${source_path}" "${target_path}" + fi + + # Remove the temporary systemd service file. + rm -f "${source_path}" || true + + # Reload systemd and its services. + reload_systemd + + # Ensure that the klipper-priority-fix systemd service is always enabled. + enable_systemd_service "${KLIPPER_PRIORITY_FIX_SERVICE_NAME}" +} + +# Stop the klipper-priority-fix systemd service. +stop_systemd_service "${KLIPPER_PRIORITY_FIX_SERVICE_NAME}" + +# Check if klipper service is running +if ! systemctl is-active --quiet klipper.service; then + echo "Klipper service is not running. Please start the Klipper service and try again." + exit 1 +fi + +# Ensure that the klipper-priority-fix binary is installed and up-to-date. +install_klipper-priority-fix_binary + +# Ensure that the custom systemd service is installed and up-to-date. +install_klipper-priority-fix_service + +# Start the klipper-priority-fix systemd service. +start_systemd_service "${KLIPPER_PRIORITY_FIX_SERVICE_NAME}" + +# Verify that the klipper-priority-fix systemd service is running. +verify_systemd_service_running "${KLIPPER_PRIORITY_FIX_SERVICE_NAME}" + +echo "klipper-priority-fix installation complete" +exit 0 diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 0000000..200403e --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# +# Uninstallation script for klipper-priority-fix for Klipper. +# + +# Enable error handling +set -eo pipefail + +# Enable script debugging +# set -x + +# Get the script path. +SCRIPT_PATH="$(cd "$(dirname "$0")" >/dev/null 2>&1; pwd -P)" + +# Load the utility functions. +source "${SCRIPT_PATH}/util.sh" + +# Stop the klipper-priority-fix systemd service. +echo "Stopping klipper-priority-fix systemd service ..." +stop_systemd_service + +# Disable the klipper-priority-fix systemd service. +echo "Disabling klipper-priority-fix systemd service ..." +disable_systemd_service + +# Remove the klipper-priority-fix systemd service. +echo "Removing klipper-priority-fix systemd service ..." +if test $(id -u) -eq 0; then + rm -f /etc/systemd/system/klipper-priority-fix.service +else + sudo rm -f /etc/systemd/system/klipper-priority-fix.service +fi + +# Reload the systemd daemon. +reload_systemd + +# Remove the klipper-priority-fix binary. +if test $(id -u) -eq 0; then + rm -f /usr/local/bin/klipper-priority-fix +else + sudo rm -f /usr/local/bin/klipper-priority-fix +fi + +# Remove the klipper-priority-fix source code. +# echo "Removing klipper-priority-fix source code ..." +# rm -fr ~/klipper-priority-fix + +echo "Successfully uninstalled klipper-priority-fix" diff --git a/scripts/util.sh b/scripts/util.sh new file mode 100755 index 0000000..343b984 --- /dev/null +++ b/scripts/util.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env bash + +# Ensure that this script is never ran as root. +if test $(id -u) -eq 0; then + echo "ERROR: This script should not be run as root" >&2 + exit 1 +fi + +# Ensure that this script can only be sourced and not ran directly. +if test "${BASH_SOURCE[0]}" = "${0}"; then + echo "ERROR: This script should be sourced, not ran directly" >&2 + exit 1 +fi + +# Ensure that we always have a valid user home directory available. +if test -z "${HOME}"; then + HOME="$(getent passwd $(whoami) | cut -d: -f6)" +fi +if test -z "${HOME}"; then + echo "ERROR: Could not determine user home directory (is HOME environment variable set?)" >&2 + exit 1 +fi + +function is_version_lte() { + [ "${1}" = "`echo -e "${1}\n${2}" | sort -V | head -n1`" ] +} + +function version() { + echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; +} + +# Function for reloading the systemd daemon and its services. +function reload_systemd() { + echo "Reloading systemd daemon ..." + if test $(id -u) -eq 0; then + systemctl daemon-reload + else + sudo systemctl daemon-reload + fi +} + +# Function that checks if a systemd service file exists, +# based on the service name as the first argument. +function systemd_service_exists() { + ## TODO: We might want to use systemctl instead of checking the file system directly, in case paths change in the future? + if test -e "/etc/systemd/system/${1}.service"; then + return 0 + else + return 1 + fi +} + +# Function for enabling a systemd service, +# based on the service name as the first argument. +function enable_systemd_service() { + # Return early if the service does not exist. + if ! systemd_service_exists "${1}"; then + # return 1 + return + fi + + echo "Enabling systemd service ${1} ..." + if test $(id -u) -eq 0; then + systemctl enable "${1}" + else + sudo systemctl enable "${1}" + fi +} + +# Function for disabling a systemd service, +# based on the service name as the first argument. +function disable_systemd_service() { + # Return early if the service does not exist. + if ! systemd_service_exists "${1}"; then + # return 1 + return + fi + + echo "Disabling systemd service ${1} ..." + if test $(id -u) -eq 0; then + systemctl disable "${1}" + else + sudo systemctl disable "${1}" + fi +} + +# Function for starting a systemd service, +# based on the service name as the first argument. +function start_systemd_service() { + # Return early if the service does not exist. + if ! systemd_service_exists "${1}"; then + # return 1 + return + fi + + echo "Starting systemd service ${1} ..." + if test $(id -u) -eq 0; then + systemctl start "${1}" + else + sudo systemctl start "${1}" + fi +} + +# Function for stopping a systemd service, +# based on the service name as the first argument. +function stop_systemd_service() { + # Return early if the service does not exist. + if ! systemd_service_exists "${1}"; then + # return 1 + return + fi + + echo "Stopping systemd service ${1} ..." + if test $(id -u) -eq 0; then + systemctl stop "${1}" + else + sudo systemctl stop "${1}" + fi +} + +# Function for restarting a systemd service, +# based on the service name as the first argument. +function restart_systemd_service() { + # Return early if the service does not exist. + if ! systemd_service_exists "${1}"; then + # return 1 + return + fi + + echo "Restarting systemd service ${1} ..." + if test $(id -u) -eq 0; then + systemctl restart "${1}" + else + sudo systemctl restart "${1}" + fi +} + +# Function for checking if a systemd service is enabled +# and running, with a timeout based second retry check, +# based on the service name as the first argument. +verify_systemd_service_running() { + echo "Verifying that ${1} systemd service is running ..." + + # Return early if the service does not exist. + if ! systemd_service_exists "${1}"; then + # return 1 + return + fi + + # Check if the service is enabled. + if ! systemctl is-enabled "${1}" >/dev/null 2>&1; then + echo "ERROR: systemd service ${1} is not enabled" >&2 + return 1 + fi + + # Check if the service is running, and if not + # wait for 5 seconds and check again. + if ! systemctl is-active "${1}" >/dev/null 2>&1; then + echo "WARNING: systemd service ${1} is not running, waiting 5 seconds and checking again ..." >&2 + sleep 5 + if ! systemctl is-active "${1}" >/dev/null 2>&1; then + echo "ERROR: systemd service ${1} is not running" >&2 + return 1 + fi + fi +} \ No newline at end of file