eg25-control: port to s6 (hopefully)

This commit is contained in:
Colin 2024-04-26 21:43:51 +00:00
parent 4c0ae75b00
commit 19115dfb65
8 changed files with 92 additions and 105 deletions

View File

@ -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;
}

View File

@ -29,6 +29,7 @@
./dino.nix
./dissent.nix
./dtrx.nix
./eg25-control.nix
./element-desktop.nix
./engrampa.nix
./epiphany.nix

View File

@ -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/<agps>
# - eg25-control-gps tests new/<agps>: it works
# - eg25-control-freshen-agps initiates DL of new/<agps>
# - eg25-control-gps: moves new/<agps> 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"; }
];
}

View File

@ -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";

View File

@ -3,7 +3,6 @@
imports = [
./clightning.nix
./dyn-dns.nix
./eg25-control.nix
./eg25-manager.nix
./kiwix-serve.nix
./mautrix-signal.nix

View File

@ -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/<agps>
# - eg25-control-gps tests new/<agps>: it works
# - eg25-control-freshen-agps initiates DL of new/<agps>
# - eg25-control-gps: moves new/<agps> 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
};
};
}

View File

@ -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;

View File

@ -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
;