{ config, lib, pkgs, ... }: with lib; let cfg = config.services.hyprmonitors; hyprmonitors = pkgs.rustPlatform.buildRustPackage { pname = "hyprmonitors"; version = "0.1.0"; src = ./.; cargoLock = { lockFile = ./Cargo.lock; }; nativeBuildInputs = with pkgs; [ pkg-config ]; buildInputs = with pkgs; [ openssl ]; meta = with lib; { description = "Hyprland monitor control server"; homepage = "https://github.com/your-username/hyprmonitors"; license = licenses.mit; maintainers = []; platforms = platforms.linux; }; }; in { options.services.hyprmonitors = { enable = mkEnableOption "Hyprland monitor control server"; package = mkOption { type = types.package; default = hyprmonitors; defaultText = literalExpression "pkgs.hyprmonitors"; description = "The hyprmonitors package to use."; }; host = mkOption { type = types.str; default = "127.0.0.1"; description = "Host address to bind the server to."; }; port = mkOption { type = types.port; default = 3000; description = "Port to bind the server to."; }; logLevel = mkOption { type = types.enum ["error" "warn" "info" "debug" "trace"]; default = "info"; description = "Log level for the server."; }; environmentVariables = mkOption { type = types.attrsOf types.str; default = {}; example = { HYPRLAND_INSTANCE_SIGNATURE = "your-signature"; }; description = "Additional environment variables to set for the service."; }; settings = mkOption { type = types.attrs; default = {}; example = { cors_origins = ["http://localhost:8080"]; timeout_seconds = 30; }; description = "Additional configuration settings (if supported by future versions)."; }; }; config = mkIf cfg.enable { assertions = [ { assertion = config.wayland.windowManager.hyprland.enable or false; message = "hyprmonitors requires Hyprland to be enabled. Set wayland.windowManager.hyprland.enable = true;"; } ]; home.packages = [cfg.package]; systemd.user.services.hyprmonitors = { Unit = { Description = "Hyprland Monitor Control Server"; Documentation = "https://github.com/your-username/hyprmonitors"; After = ["graphical-session.target" "hyprland-session.target"]; Wants = ["graphical-session.target"]; PartOf = ["hyprland-session.target"]; }; Service = { Type = "simple"; ExecStart = "${cfg.package}/bin/hyprmonitors"; Restart = "always"; RestartSec = 5; # Environment variables Environment = [ "RUST_LOG=${cfg.logLevel}" "HYPRMONITORS_HOST=${cfg.host}" "HYPRMONITORS_PORT=${toString cfg.port}" "HYPRMONITORS_LOG_LEVEL=${cfg.logLevel}" ] ++ (mapAttrsToList (name: value: "${name}=${value}") cfg.environmentVariables); # Security settings NoNewPrivileges = true; PrivateTmp = true; ProtectHome = "read-only"; ProtectSystem = "strict"; ReadWritePaths = ["/tmp"]; # Resource limits LimitNOFILE = 1024; MemoryMax = "128M"; }; Install = { WantedBy = ["hyprland-session.target"]; }; }; # Create a target for Hyprland session if it doesn't exist systemd.user.targets.hyprland-session = mkIf (!config.systemd.user.targets ? hyprland-session) { Unit = { Description = "Hyprland session"; BindsTo = ["graphical-session.target"]; Wants = ["graphical-session.target"]; After = ["graphical-session.target"]; }; }; # Optional: Add a desktop entry for manual control xdg.desktopEntries.hyprmonitors-control = mkIf (cfg.enable && cfg.host == "127.0.0.1") { name = "Hyprmonitors Control"; comment = "Control Hyprland monitors via web interface"; exec = "${pkgs.xdg-utils}/bin/xdg-open http://${cfg.host}:${toString cfg.port}/health"; icon = "preferences-desktop-display"; categories = ["Settings" "System"]; terminal = false; type = "Application"; }; # Add some useful aliases for controlling the service home.shellAliases = mkIf cfg.enable { hyprmonitors-start = "systemctl --user start hyprmonitors.service"; hyprmonitors-stop = "systemctl --user stop hyprmonitors.service"; hyprmonitors-restart = "systemctl --user restart hyprmonitors.service"; hyprmonitors-status = "systemctl --user status hyprmonitors.service"; hyprmonitors-logs = "journalctl --user -u hyprmonitors.service -f"; hyprmonitors-test = "curl http://${cfg.host}:${toString cfg.port}/health"; }; # Add some helper scripts home.packages = mkIf cfg.enable [ (pkgs.writeShellScriptBin "hyprmonitors-curl" '' #!/usr/bin/env bash # Helper script for testing hyprmonitors API BASE_URL="http://${cfg.host}:${toString cfg.port}" case "$1" in health) curl -s "$BASE_URL/health" | ${pkgs.jq}/bin/jq ;; status) curl -s "$BASE_URL/monitors/status" | ${pkgs.jq}/bin/jq ;; on) if [ -n "$2" ]; then curl -s -X POST "$BASE_URL/monitors/$2/on" | ${pkgs.jq}/bin/jq else curl -s -X POST "$BASE_URL/monitors/on" | ${pkgs.jq}/bin/jq fi ;; off) if [ -n "$2" ]; then curl -s -X POST "$BASE_URL/monitors/$2/off" | ${pkgs.jq}/bin/jq else curl -s -X POST "$BASE_URL/monitors/off" | ${pkgs.jq}/bin/jq fi ;; *) echo "Usage: hyprmonitors-curl {health|status|on [monitor]|off [monitor]}" echo "" echo "Examples:" echo " hyprmonitors-curl health" echo " hyprmonitors-curl status" echo " hyprmonitors-curl on" echo " hyprmonitors-curl off" echo " hyprmonitors-curl on DP-1" echo " hyprmonitors-curl off HDMI-A-1" exit 1 ;; esac '') ]; }; }