{ self }: { config, lib, pkgs, ... }: let inherit (lib) mkEnableOption mkIf mkOption types; cfg = config.services.omnisearch; generatedConfig = pkgs.writeText "omnisearch-config.ini" '' ${lib.generators.toINI {} cfg.settings} ${cfg.extraConfig} ''; assetDir = "${cfg.package}/share/omnisearch"; in { options.services.omnisearch = { enable = mkEnableOption "OmniSearch metasearch server"; package = mkOption { type = types.package; default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; defaultText = lib.literalExpression "packages.${pkgs.stdenv.hostPlatform.system}.default"; description = "OmniSearch package to run."; }; user = mkOption { type = types.str; default = "omnisearch"; description = "User account under which OmniSearch runs."; }; group = mkOption { type = types.str; default = "omnisearch"; description = "Group under which OmniSearch runs."; }; settings = mkOption { type = types.attrsOf (types.attrsOf (types.oneOf [ types.str types.int types.bool ])); default = { server = { host = "0.0.0.0"; port = 8087; }; cache.dir = "/var/cache/omnisearch"; engines.engines = "*"; }; example = { server = { host = "127.0.0.1"; port = 8087; }; engines.engines = "ddg,startpage"; rate_limit = { search_requests = 10; search_interval = 60; }; }; description = '' INI settings grouped by section. Section and key names follow `example-config.ini`; values are written as strings, integers or booleans. The generated INI is stored in the world-readable Nix store, so do not put secrets here. ''; }; extraConfig = mkOption { type = types.lines; default = ""; example = '' [proxy] proxy = "socks5://127.0.0.1:9050" ''; description = '' Additional raw INI text appended after the generated `settings`. This text is also embedded in the world-readable Nix store; avoid including secrets. ''; }; openFirewall = mkOption { type = types.bool; default = false; description = "Whether to open the configured TCP port in the firewall."; }; }; config = mkIf cfg.enable { users.groups.${cfg.group} = {}; users.users.${cfg.user} = { isSystemUser = true; group = cfg.group; description = "OmniSearch service user"; }; networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ (cfg.settings.server.port or 8087) ]; systemd.services.omnisearch = { description = "OmniSearch metasearch server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; wants = [ "network-online.target" ]; serviceConfig = { Type = "simple"; User = cfg.user; Group = cfg.group; StateDirectory = "omnisearch"; CacheDirectory = "omnisearch"; WorkingDirectory = "/var/lib/omnisearch"; ExecStartPre = pkgs.writeShellScript "omnisearch-prepare" '' ln -sfn ${lib.escapeShellArg "${assetDir}/templates"} templates ln -sfn ${lib.escapeShellArg "${assetDir}/static"} static ln -sfn ${lib.escapeShellArg "${assetDir}/locales"} locales ln -sfn ${lib.escapeShellArg (toString generatedConfig)} config.ini ''; ExecStart = "${cfg.package}/bin/omnisearch"; Restart = "on-failure"; RestartSec = "5s"; PrivateTmp = true; NoNewPrivileges = true; ProtectSystem = "strict"; ProtectHome = true; ReadWritePaths = [ "/var/lib/omnisearch" "/var/cache/omnisearch" ]; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; }; }; }; }