{ config, lib, pkgs, ... }: with lib; let cfg = config.services.objectifier; pythonYolo = pkgs.python3.withPackages (pyPkgs: with pyPkgs; [ fastapi gunicorn opencv4 python-multipart uvicorn ]); in { options.services.objectifier = with types; { enable = mkEnableOption "Enable Objectifier object-detection web sevice."; port = mkOption { type = port; description = "Port on which to run the Objectifier web service."; default = 5121; }; workers = mkOption { type = int; description = "Number of worker threads to launch."; default = 3; }; pool-size = mkOption { type = int; description = "Number of nets to initialize."; default = 5; }; listen-addresses = mkOption { type = listOf str; description = "List of IP addresses on which to listen for incoming requests."; default = [ "127.0.0.1" ]; }; detection-timeout = mkOption { type = int; description = "Time in seconds to allow for detection to start."; default = 5; }; hostname = mkOption { type = nullOr str; description = "Hostname on which to listen for requests."; default = null; }; cleanup = { max_file_age = mkOption { type = int; description = "Maximum age of a file (in seconds), after which it will be removed."; default = (60 * 60 * 8); # 8 hours }; delay = mkOption { type = int; description = "Time between cleanup sweeps."; default = (60 * 10); # 10 minutes }; }; }; config = mkIf cfg.enable { services.nginx = mkIf (!isNull cfg.hostname) { enable = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedGzipSettings = true; virtualHosts."${cfg.hostname}" = { locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; }; }; systemd.services = { objectifier = { after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; environment = { OBJECTIFIER_YOLOV3_CONFIG = "${pkgs.yolov3-data}/yolov3.cfg"; OBJECTIFIER_YOLOV3_WEIGHTS = "${pkgs.yolov3-data}/yolov3.weights"; OBJECTIFIER_YOLOV3_LABELS = "${pkgs.yolov3-data}/labels"; OBJECTIFIER_BUFFER_SIZE = "524288"; OBJECTIFIER_CLEANUP_MAX_AGE = toString cfg.cleanup.max_file_age; OBJECTIFIER_CLEANUP_DELAY = toString cfg.cleanup.delay; OBJECTIFIER_TIMEOUT = toString cfg.detection-timeout; OBJECTIFIER_POOL_SIZE = toString cfg.pool-size; }; serviceConfig = { PrivateUsers = true; PrivateDevices = true; PrivateTmp = true; PrivateMounts = true; ProtectControlGroups = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectSystem = true; ProtectHostname = true; ProtectHome = true; ProtectClock = true; ProtectKernelLogs = true; # DynamicUser = true; MemoryDenyWriteExecute = true; RestrictRealtime = true; LockPersonality = true; PermissionsStartOnly = true; WorkingDirectory = "${pkgs.objectifier}"; StateDirectory = "objectifier"; CacheDirectory = "objectifier"; RuntimeDirectory = "objectifier"; LimitNOFILE = 4096; Restart = "on-failure"; RestartSec = "5s"; Type = "simple"; ExecStart = let bindClause = concatStringsSep " " (map (addr: "--bind ${addr}:${toString cfg.port}") cfg.listen-addresses); in (concatStringsSep " " [ "${pkgs.objectifier}/bin/objectifier" bindClause "--workers ${toString cfg.workers}" ]); }; }; }; }; }