{ lib, config, pkgs, ... }: let cfg = config.services.network-watchdog; watchdog = "${pkgs.custom.network-watchdog}/bin/network-watchdog"; units = map (name: "${name}.service") cfg.units; in { # User services that only make sense while online: GUI clients that hold a # socket to a server (jellyfin-mpv-shim, nextcloud-client). Their upstream # units have no network ordering (network-online.target is a system target, # out of reach for user units), so they happily start while offline — # silently dead — and nothing notices a connection dropped by a network # blip. Gate each start on the network being up, restart on failure, and let # a watchdog catch the "up but not connected" state that systemd can't see. # See pkgs.custom.network-watchdog. options.services.network-watchdog.units = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "jellyfin-mpv-shim" ]; description = "User services (no .service suffix) to gate on the network and keep connected."; }; config = lib.mkIf (cfg.units != [ ]) { systemd.user.services = lib.genAttrs cfg.units (name: { Service = { ExecStartPre = "${watchdog} wait-online ${name}.service"; TimeoutStartSec = "infinity"; # stay in start-pre until the network is back Restart = lib.mkDefault "on-failure"; RestartSec = lib.mkDefault 5; }; }) // { network-watchdog = { Unit = { Description = "Restart network services that are up but not connected"; After = units; }; Service = { Type = "oneshot"; ExecStart = "${watchdog} check ${lib.concatStringsSep " " units}"; }; }; }; systemd.user.timers.network-watchdog = { Unit.Description = "Periodic health check for network services"; Timer = { OnActiveSec = "60s"; OnUnitActiveSec = "60s"; }; Install.WantedBy = [ "timers.target" ]; }; }; }