diff --git a/hosts/by-name/moby/gps.nix b/hosts/by-name/moby/gps.nix index 2476f7aa..c2ee42f7 100644 --- a/hosts/by-name/moby/gps.nix +++ b/hosts/by-name/moby/gps.nix @@ -64,6 +64,5 @@ "dialout" # TODO: figure out if dialout is required. that's for /dev/ttyUSB1, but geoclue probably doesn't read that? ]; - sane.services.eg25-control.enable = true; sane.programs.where-am-i.enableFor.user.colin = true; } diff --git a/hosts/common/programs/default.nix b/hosts/common/programs/default.nix index 5858be5e..c5c597cf 100644 --- a/hosts/common/programs/default.nix +++ b/hosts/common/programs/default.nix @@ -29,6 +29,7 @@ ./dino.nix ./dissent.nix ./dtrx.nix + ./eg25-control.nix ./element-desktop.nix ./engrampa.nix ./epiphany.nix diff --git a/hosts/common/programs/eg25-control.nix b/hosts/common/programs/eg25-control.nix new file mode 100644 index 00000000..e13d7ca5 --- /dev/null +++ b/hosts/common/programs/eg25-control.nix @@ -0,0 +1,64 @@ +{ config, lib, ... }: +let + cfg = config.sane.programs.eg25-control; +in +{ + sane.programs.eg25-control = { + services.eg25-control-powered = { + description = "eg25-control-powered: power to the Qualcomm eg25 modem used by PinePhone"; + startCommand = "eg25-control --power-on --verbose"; + cleanupCommand = "eg25-control --power-off --verbose"; + # depends = [ "ModemManager" ] + }; + + services.eg25-control-gps = { + # TODO: separate almanac upload from GPS enablement + # - don't want to re-upload the almanac everytime the GPS is toggled + # - want to upload almanac even when GPS *isn't* enabled, if we have internet connection. + description = "eg25-control-gps: background GPS tracking"; + startCommand = "eg25-control --enable-gps --dump-debug-info --verbose"; + cleanupCommand = "eg25-control --disable-gps --dump-debug-info --verbose"; + depends = [ "eg25-control-powered" ]; + }; + }; + + # TODO: port to s6 + systemd.services.eg25-control-freshen-agps = lib.mkIf cfg.enabled { + description = "keep assisted-GPS data fresh"; + serviceConfig = { + # XXX: this can have a race condition with eg25-control-gps + # - eg25-control-gps initiates DL of new/ + # - eg25-control-gps tests new/: it works + # - eg25-control-freshen-agps initiates DL of new/ + # - eg25-control-gps: moves new/ into cache/ + # - but it moved the result (possibly incomplete) of eg25-control-freshen-agps, incorrectly + # in practice, i don't expect much issue from this. + ExecStart = "${cfg.package}/bin/eg25-control --ensure-agps-cache --verbose"; + Restart = "no"; + + User = "eg25-control"; + WorkingDirectory = "/var/lib/eg25-control"; + StateDirectory = "eg25-control"; + }; + startAt = "hourly"; # this is a bit more than necessary, but idk systemd calendar syntax + after = [ "network-online.target" "nss-lookup.target" ]; + requires = [ "network-online.target" ]; + # wantedBy = [ "network-online.target" ]; # auto-start immediately after boot + }; + users = lib.mkIf cfg.enabled { + groups.eg25-control = {}; + users.eg25-control = { + group = "eg25-control"; + isSystemUser = true; + home = "/var/lib/eg25-control"; + extraGroups = [ + "dialout" # required to read /dev/ttyUSB1 + "networkmanager" # required to authenticate with mmcli + ]; + }; + }; + sane.persist.sys.byStore.plaintext = lib.mkIf cfg.enabled [ + # to persist agps data, i think. + { user = "eg25-control"; group = "eg25-control"; path = "/var/lib/eg25-control"; } + ]; +} diff --git a/hosts/common/programs/swaynotificationcenter/buttons.nix b/hosts/common/programs/swaynotificationcenter/buttons.nix index d27a22b9..b5d5c16f 100644 --- a/hosts/common/programs/swaynotificationcenter/buttons.nix +++ b/hosts/common/programs/swaynotificationcenter/buttons.nix @@ -9,8 +9,8 @@ let }; in { - gps = serviceButton "systemd" "eg25-control-gps" ""; # GPS services; other icons: gps, ⌖, 🛰, 🌎,  - cell-modem = serviceButton "systemd" "eg25-control-powered" "󰺐"; # icons: 5g, 📡, 📱, ᯤ, ⚡, , 🌐, 📶, 🗼, 󰀂, , 󰺐, 󰩯 + gps = serviceButton "s6" "eg25-control-gps" ""; # GPS services; other icons: gps, ⌖, 🛰, 🌎,  + cell-modem = serviceButton "s6" "eg25-control-powered" "󰺐"; # icons: 5g, 📡, 📱, ᯤ, ⚡, , 🌐, 📶, 🗼, 󰀂, , 󰺐, 󰩯 vpn = serviceButton "systemd" "wg-quick-vpn-servo" "vpn::hn"; gnome-calls = serviceButton "s6" "gnome-calls" "SIP"; diff --git a/modules/services/default.nix b/modules/services/default.nix index 74a6e89a..6bad3d61 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -3,7 +3,6 @@ imports = [ ./clightning.nix ./dyn-dns.nix - ./eg25-control.nix ./eg25-manager.nix ./kiwix-serve.nix ./mautrix-signal.nix diff --git a/modules/services/eg25-control.nix b/modules/services/eg25-control.nix deleted file mode 100644 index 45b9e8ce..00000000 --- a/modules/services/eg25-control.nix +++ /dev/null @@ -1,94 +0,0 @@ -{ config, lib, pkgs, ... }: -let - cfg = config.sane.services.eg25-control; -in -{ - options.sane.services.eg25-control = with lib; { - enable = mkEnableOption "Quectel EG25 modem configuration scripts. alternative to eg25-manager"; - package = mkOption { - type = types.package; - default = pkgs.eg25-control; - }; - }; - - config = lib.mkIf cfg.enable { - users.groups.eg25-control = {}; - users.users.eg25-control = { - group = "eg25-control"; - isSystemUser = true; - home = "/var/lib/eg25-control"; - extraGroups = [ - "dialout" # required to read /dev/ttyUSB1 - "networkmanager" # required to authenticate with mmcli - ]; - }; - sane.persist.sys.byStore.plaintext = [ - { user = "eg25-control"; group = "eg25-control"; path = "/var/lib/eg25-control"; } - ]; - - systemd.services.eg25-control-powered = { - description = "power to the Qualcomm eg25 modem used by PinePhone"; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${cfg.package}/bin/eg25-control --power-on --verbose"; - ExecStop = "${cfg.package}/bin/eg25-control --power-off --verbose"; - Restart = "on-failure"; - RestartSec = "60s"; - TimeoutSec = "60s"; - - # XXX /sys/class/modem-power/modem-power/device/powered is writable only by root - # User = "eg25-control"; - # WorkingDirectory = "/var/lib/eg25-control"; - # StateDirectory = "eg25-control"; - }; - after = [ "ModemManager.service" ]; - wants = [ "ModemManager.service" ]; - # wantedBy = [ "multi-user.target" ]; - }; - systemd.services.eg25-control-gps = { - # TODO: separate almanac upload from GPS enablement - # - don't want to re-upload the almanac everytime the GPS is toggled - # - want to upload almanac even when GPS *isn't* enabled, if we have internet connection. - description = "background GPS tracking"; - serviceConfig = { - Type = "simple"; - RemainAfterExit = true; - ExecStart = "${cfg.package}/bin/eg25-control --enable-gps --dump-debug-info --verbose"; - ExecStop = "${cfg.package}/bin/eg25-control --disable-gps --dump-debug-info --verbose"; - Restart = "on-failure"; - RestartSec = "60s"; - - User = "eg25-control"; - WorkingDirectory = "/var/lib/eg25-control"; - StateDirectory = "eg25-control"; - }; - after = [ "eg25-control-powered.service" ]; - requires = [ "eg25-control-powered.service" ]; - # wantedBy = [ "multi-user.target" ]; - }; - - systemd.services.eg25-control-freshen-agps = { - description = "keep assisted-GPS data fresh"; - serviceConfig = { - # XXX: this can have a race condition with eg25-control-gps - # - eg25-control-gps initiates DL of new/ - # - eg25-control-gps tests new/: it works - # - eg25-control-freshen-agps initiates DL of new/ - # - eg25-control-gps: moves new/ into cache/ - # - but it moved the result (possibly incomplete) of eg25-control-freshen-agps, incorrectly - # in practice, i don't expect much issue from this. - ExecStart = "${cfg.package}/bin/eg25-control --ensure-agps-cache --verbose"; - Restart = "no"; - - User = "eg25-control"; - WorkingDirectory = "/var/lib/eg25-control"; - StateDirectory = "eg25-control"; - }; - startAt = "hourly"; # this is a bit more than necessary, but idk systemd calendar syntax - after = [ "network-online.target" "nss-lookup.target" ]; - requires = [ "network-online.target" ]; - # wantedBy = [ "network-online.target" ]; # auto-start immediately after boot - }; - }; -} diff --git a/modules/users/default.nix b/modules/users/default.nix index aae1d3aa..074031c8 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -49,6 +49,15 @@ let restart of the service (if applicable) is blocked on this command. ''; }; + startCommand = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + command which is run to start the service. + this command is expected to exit once the service is up, contrary to the normal `command` argument. + mutually exclusive to `command`. + ''; + }; readiness.waitCommand = mkOption { type = types.nullOr (types.coercedTo types.package toString types.str); default = null; diff --git a/modules/users/s6-rc.nix b/modules/users/s6-rc.nix index aa22af64..bbff29de 100644 --- a/modules/users/s6-rc.nix +++ b/modules/users/s6-rc.nix @@ -62,10 +62,13 @@ let # } fsToDerivation = fs: fsItemToDerivation "/" { dir = fs; }; - # infers the service type from the arguments and creates an attrset usable by `fsToDerivation`. + # infers some service settings from the arguments and creates an attrset usable by `fsToDerivation`. # also configures the service for logging, if applicable. - serviceToFs = { name, check, contents, depends, finish, run }: let - type = if run != null then "longrun" else "bundle"; + # type can be: + # - "longrun" + # - "bundle" + # - "oneshot"? + serviceToFs = { name, check, contents, depends, finish, run, type }: let logger = serviceToFs' { name = "logger:${name}"; consumerFor = name; @@ -75,8 +78,8 @@ let in (serviceToFs' { inherit name check depends finish run type; contents = maybe (type == "bundle") contents; - producerFor = maybe (type == "longrun") "logger:${name}"; - }) // (lib.optionalAttrs (type == "longrun") logger); + producerFor = maybe (type != "bundle") "logger:${name}"; + }) // (lib.optionalAttrs (type != "bundle") logger); serviceToFs'= { name, @@ -221,7 +224,7 @@ let # transform the `user.services` attrset into a s6 services list. s6SvcsFromConfigServices = services: lib.mapAttrsToList - (name: service: { + (name: service: rec { inherit name; check = service.readiness.waitCommand; contents = builtins.attrNames ( @@ -231,7 +234,13 @@ let lib.filterAttrs (_: cfg: lib.elem name cfg.dependencyOf) services ); finish = service.cleanupCommand; - run = service.command; + inherit (if service.startCommand != null then + { type="oneshot"; run = service.startCommand; } + else if service.command != null then + { type="longshot"; run = service.command; } + else + { type="bundle"; run = null; } + ) type run; }) services ;