infrastructure/modules/nixos/barcodebuddy-scanner.nix
2024-05-26 14:13:33 -07:00

161 lines
4.7 KiB
Nix

{
config,
lib,
utils,
pkgs,
...
}: let
inherit (utils) escapeSystemdPath;
inherit (lib.options) mkOption mkEnableOption mkPackageOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault mkDefault;
inherit (lib.attrsets) mapAttrs' nameValuePair;
inherit (lib.lists) optional isList imap0;
inherit (lib.strings) optionalString concatStringsSep;
inherit (lib.meta) getExe;
cfg = config.services.barcodebuddy-scanner;
toEnvName = key: "BBUDDY_" + key;
toEnvValue = value:
if value == true
then "true"
else if value == false
then "false"
else if isList value
then concatStringsSep ";" (imap0 (i: v: "${toString i}=${toEnvValue v}") value)
else toString value;
toEnvPair = key: value: nameValuePair (toEnvName key) (toEnvValue value);
in {
options.services.barcodebuddy-scanner = with lib.types; {
enable = mkEnableOption "Barcode Buddy scanner";
package = mkPackageOption pkgs "barcodebuddy-scanner" {
example = "pkgs.barcodebuddy-scanner-python";
};
inputDevice = mkOption {
type = nullOr path;
default = null;
example = "/dev/input/event6";
};
serverAddress = mkOption {
type = nullOr str;
example = "https://your.bbuddy.url/api/";
};
apiKeyPath = mkOption {
type = nullOr path;
};
user = mkOption {
type = str;
};
scanCommand = mkOption {
type = nullOr path;
default = null;
};
udevMatchRules = mkOption {
type = nullOr (listOf str);
default = null;
example = [
''ATTRS{idVendor}=="1abc"''
];
};
};
config = let
scannerConfig.services.barcodebuddy-scanner = {
inputDevice = mkIf (cfg.udevMatchRules != null) (
mkDefault "/dev/barcodebuddy-scanner"
);
apiKeyPath = mkIf (cfg.serverAddress == null) (
mkOptionDefault null
);
};
localBbuddyConfig = {
services.barcodebuddy-scanner = {
serverAddress = mkOptionDefault null;
user = mkOptionDefault "barcodebuddy";
};
systemd.services.barcodebuddy-scanner = let
inherit (config.services) barcodebuddy;
services =
["phpfpm-barcodebuddy.service"]
++ optional barcodebuddy.screen.enable "barcodebuddy-websocket.service";
in
mkIf cfg.enable {
wantedBy = services;
bindsTo = services;
after = services;
environment = mapAttrs' toEnvPair barcodebuddy.settings;
};
};
# https://github.com/Forceu/barcodebuddy/blob/master/example/bbuddy-grabInput.conf
conf.systemd.services.barcodebuddy-scanner = let
RuntimeDirectory = "barcodebuddy-scanner";
apiKeyFile = "apikey.env";
prepKeyEnvironment = pkgs.writeShellScript "barcodebuddy-scanner-apikey.sh" ''
set -eu
printf "" > $RUNTIME_DIRECTORY/${apiKeyFile}
chmod 0640 $RUNTIME_DIRECTORY/${apiKeyFile}
printf "API_KEY=$(cat $API_KEY_PATH)\\n" >> $RUNTIME_DIRECTORY/${apiKeyFile}
'';
in {
wantedBy = [
"multi-user.target"
];
environment = mkMerge [
(mkIf (cfg.serverAddress != null) {
SERVER_ADDRESS = cfg.serverAddress;
})
(mkIf (cfg.scanCommand != null) {
BARCODE_COMMAND = cfg.scanCommand;
})
(mkIf (cfg.apiKeyPath != null) {
API_KEY_PATH = cfg.apiKeyPath;
})
];
unitConfig = {
Description = "Grab barcode scans for barcode buddy";
ConditionPathExists = mkIf (cfg.inputDevice != null) [
cfg.inputDevice
];
};
serviceConfig = {
inherit RuntimeDirectory;
Type = "exec";
ExecStart = [
(getExe cfg.package + optionalString (cfg.inputDevice != null) " ${cfg.inputDevice}")
];
ExecStartPre = mkIf (cfg.apiKeyPath != null) [
"${prepKeyEnvironment}"
];
EnvironmentFile = mkIf (cfg.apiKeyPath != null) [
"-/run/${RuntimeDirectory}/${apiKeyFile}"
];
Restart = "on-failure";
User = cfg.user;
};
};
conf.services.udev.extraRules = let
rules =
[
''SUBSYSTEM=="input"''
''ACTION=="add"''
''KERNEL=="event*"''
]
++ cfg.udevMatchRules
++ [
''SYMLINK+="barcodebuddy-scanner"''
''OWNER="${cfg.user}"''
''MODE="0600"''
''TAG+="systemd"''
''ENV{SYSTEMD_WANTS}="barcodebuddy-scanner.service"''
];
rulesLine = concatStringsSep ", " rules;
in
mkIf (cfg.udevMatchRules != null) rulesLine;
in
mkMerge [
scannerConfig
(mkIf config.services.barcodebuddy.enable or false localBbuddyConfig)
(mkIf cfg.enable conf)
];
}