Unverified Commit 0a324bb3 authored by Arne Keller's avatar Arne Keller Committed by GitHub
Browse files

scanservjs: init at 2.27.1; nixos/scanservjs: init (#249806)

parents fe4fe1f7 ce37a0a3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

- [Bazecor](https://github.com/Dygmalab/Bazecor), the graphical configurator for Dygma Products.

- [scanservjs](https://github.com/sbs20/scanservjs/), a web UI for SANE scanners. Available at [services.scanservjs](#opt-services.scanservjs.enable).

- [Kimai](https://www.kimai.org/), a web-based multi-user time-tracking application. Available as [services.kimai](options.html#opt-services.kimai).

- [Omnom](https://github.com/asciimoo/omnom), a webpage bookmarking and snapshotting service. Available as [services.omnom](options.html#opt-services.omnom.enable).
+1 −0
Original line number Diff line number Diff line
@@ -624,6 +624,7 @@
  ./services/hardware/sane_extra_backends/brscan4.nix
  ./services/hardware/sane_extra_backends/brscan5.nix
  ./services/hardware/sane_extra_backends/dsseries.nix
  ./services/hardware/scanservjs.nix
  ./services/hardware/spacenavd.nix
  ./services/hardware/supergfxd.nix
  ./services/hardware/tcsd.nix
+155 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  cfg = config.services.scanservjs;
  settings = {
    scanimage = lib.getExe' config.hardware.sane.backends-package "scanimage";
    convert = lib.getExe' pkgs.imagemagick "convert";
    tesseract = lib.getExe pkgs.tesseract;
    # it defaults to config/devices.json, but "config" dir doesn't exist by default and scanservjs doesn't create it
    devicesPath = "devices.json";
  } // cfg.settings;
  settingsFormat = pkgs.formats.json { };

  leafs =
    attrs:
    builtins.concatLists (
      lib.mapAttrsToList (k: v: if builtins.isAttrs v then leafs v else [ v ]) attrs
    );

  package = pkgs.scanservjs;

  configFile = pkgs.writeText "config.local.js" ''
    /* eslint-disable no-unused-vars */
    module.exports = {
      afterConfig(config) {
        ${
          builtins.concatStringsSep "" (
            leafs (
              lib.mapAttrsRecursive (path: val: ''
                ${builtins.concatStringsSep "." path} = ${builtins.toJSON val};
              '') { config = settings; }
            )
          )
        }
        ${cfg.extraConfig}
      },

      afterDevices(devices) {
        ${cfg.extraDevicesConfig}
      },

      async afterScan(fileInfo) {
        ${cfg.runAfterScan}
      },

      actions: [
        ${builtins.concatStringsSep ",\n" cfg.extraActions}
      ],
    };
  '';

in
{
  options.services.scanservjs = {
    enable = lib.mkEnableOption "scanservjs";
    stateDir = lib.mkOption {
      type = lib.types.str;
      default = "/var/lib/scanservjs";
      description = ''
        State directory for scanservjs.
      '';
    };
    settings = lib.mkOption {
      default = { };
      description = ''
        Config to set in config.local.js's `afterConfig`.
      '';
      type = lib.types.submodule {
        freeformType = settingsFormat.type;
        options.host = lib.mkOption {
          type = lib.types.str;
          description = "The IP to listen on.";
          default = "127.0.0.1";
        };
        options.port = lib.mkOption {
          type = lib.types.port;
          description = "The port to listen on.";
          default = 8080;
        };
      };
    };
    extraConfig = lib.mkOption {
      default = "";
      type = lib.types.lines;
      description = ''
        Extra code to add to config.local.js's `afterConfig`.
      '';
    };
    extraDevicesConfig = lib.mkOption {
      default = "";
      type = lib.types.lines;
      description = ''
        Extra code to add to config.local.js's `afterDevices`.
      '';
    };
    runAfterScan = lib.mkOption {
      default = "";
      type = lib.types.lines;
      description = ''
        Extra code to add to config.local.js's `afterScan`.
      '';
    };
    extraActions = lib.mkOption {
      default = [ ];
      type = lib.types.listOf lib.types.lines;
      description = "Actions to add to config.local.js's `actions`.";
    };
  };

  config = lib.mkIf cfg.enable {
    hardware.sane.enable = true;
    users.users.scanservjs = {
      group = "scanservjs";
      extraGroups = [
        "scanner"
        "lp"
      ];
      home = cfg.stateDir;
      isSystemUser = true;
      createHome = true;
    };
    users.groups.scanservjs = { };

    systemd.services.scanservjs = {
      description = "scanservjs";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];
      # yes, those paths are configurable, but the config option isn't always used...
      # a lot of the time scanservjs just takes those from PATH
      path = with pkgs; [
        coreutils
        config.hardware.sane.backends-package
        imagemagick
        tesseract
      ];
      environment = {
        NIX_SCANSERVJS_CONFIG_PATH = configFile;
        SANE_CONFIG_DIR = "/etc/sane-config";
        LD_LIBRARY_PATH = "/etc/sane-libs";
      };
      serviceConfig = {
        ExecStart = lib.getExe package;
        Restart = "always";
        User = "scanservjs";
        Group = "scanservjs";
        WorkingDirectory = cfg.stateDir;
      };
    };
  };
}
+64 −0
Original line number Diff line number Diff line
diff --git a/packages/server/src/api.js b/packages/server/src/api.js
index bd43842..71ce7c9 100644
--- a/packages/server/src/api.js
+++ b/packages/server/src/api.js
@@ -105,7 +105,7 @@ module.exports = new class Api {
     }
 
     // If not then it's possible the default image is not quite the correct aspect ratio
-    const buffer = FileInfo.create(`${config.previewDirectory}/default.jpg`).toBuffer();
+    const buffer = FileInfo.create('NIX_OUT_PLACEHOLDER/lib/node_modules/scanservjs-api/data/preview/default.jpg').toBuffer();
 
     try {
       // We need to know the correct aspect ratio from the device
diff --git a/packages/server/src/application.js b/packages/server/src/application.js
index 2771036..0c2a4c0 100644
--- a/packages/server/src/application.js
+++ b/packages/server/src/application.js
@@ -26,7 +26,7 @@ module.exports = new class Application {
 
   userOptions() {
     if (this._userOptions === null) {
-      this._userOptions = new UserOptions('../../config/config.local.js');
+      this._userOptions = new UserOptions(process.env.NIX_SCANSERVJS_CONFIG_PATH);
     }
     return this._userOptions;
   }
diff --git a/packages/server/src/classes/user-options.js b/packages/server/src/classes/user-options.js
index f129e3c..c71e754 100644
--- a/packages/server/src/classes/user-options.js
+++ b/packages/server/src/classes/user-options.js
@@ -4,7 +4,7 @@ const path = require('path');
 module.exports = class UserOptions {
   constructor(localConfigPath) {
     if (localConfigPath) {
-      const localPath = path.join(__dirname, localConfigPath);
+      const localPath = localConfigPath;
       if (fs.existsSync(localPath)) {
         this.local = require(localPath);
       }
diff --git a/packages/server/src/configure.js b/packages/server/src/configure.js
index c9e5ed8..484949c 100644
--- a/packages/server/src/configure.js
+++ b/packages/server/src/configure.js
@@ -71,6 +71,7 @@ function initialize(rootPath) {
 
   try {
     fs.mkdirSync(config.outputDirectory, { recursive: true });
+    fs.mkdirSync(config.previewDirectory, { recursive: true });
     fs.mkdirSync(config.tempDirectory, { recursive: true });
   } catch (exception) {
     log.warn(`Error ensuring output and temp directories exist: ${exception}`);
diff --git a/packages/server/src/server.js b/packages/server/src/server.js
index e1a9fb0..3d58d37 100644
--- a/packages/server/src/server.js
+++ b/packages/server/src/server.js
@@ -5,7 +5,7 @@ const configure = require('./configure');
 const config = application.config();
 const app = express();
 
-app.use(express.static('client'));
+app.use(express.static('@client@'));
 
 configure(app);
 
+93 −0
Original line number Diff line number Diff line
{
  lib,
  fetchFromGitHub,
  buildNpmPackage,
  fetchNpmDeps,
  nodejs,
  substituteAll,
}:

let
  version = "2.27.1";
  src = fetchFromGitHub {
    owner = "sbs20";
    repo = "scanservjs";
    # rev = "v${version}";
    # 2.27.1 doesn't have a tag
    rev = "b15adc6f97fb152fd9819371bb1a9b8118baf55b";
    hash = "sha256-ne9fEF/eurWPXzmJQzBn5jiy+JgxMWiCXsOdmu2fj6E=";
  };

  depsHashes = {
    server = "sha256-M8t+TrE+ntZaI9X7hEel94bz34DPtW32n0KKMSoCfIs=";
    client = "sha256-C31WBYE8ba0t4mfKFAuYWrCZtSdN7tQIYmCflDRKuBM=";
  };

  serverDepsForClient = fetchNpmDeps {
    inherit src nodejs;
    sourceRoot = "${src.name}/packages/server";
    name = "scanservjs";
    hash = depsHashes.server or lib.fakeHash;
  };

  # static client files
  client = buildNpmPackage {
    pname = "scanservjs-client";
    inherit version src nodejs;

    sourceRoot = "${src.name}/packages/client";
    npmDepsHash = depsHashes.client or lib.fakeHash;

    preBuild = ''
      cd ../server
      chmod +w package-lock.json . /build/source/
      npmDeps=${serverDepsForClient} npmConfigHook
      cd ../client
    '';

    env.NODE_OPTIONS = "--openssl-legacy-provider";

    dontNpmInstall = true;
    installPhase = ''
      mv /build/source/dist/client $out
    '';
  };

in
buildNpmPackage {
  pname = "scanservjs";
  inherit version src nodejs;

  sourceRoot = "${src.name}/packages/server";
  npmDepsHash = depsHashes.server or lib.fakeHash;

  # can't use "patches" since they change the server deps' hash for building the client
  # (I don't want to maintain one more hash)
  preBuild = ''
    chmod +w /build/source
    patch -p3 <${
      substituteAll {
        src = ./decouple-from-source-tree.patch;
        inherit client;
      }
    }
    substituteInPlace src/api.js --replace 'NIX_OUT_PLACEHOLDER' "$out"
  '';

  postInstall = ''
    mkdir -p $out/bin
    makeWrapper ${lib.getExe nodejs} $out/bin/scanservjs \
      --set NODE_ENV production \
      --add-flags "'$out/lib/node_modules/scanservjs-api/src/server.js'"
  '';

  meta = {
    description = "SANE scanner nodejs web ui";
    longDescription = "scanservjs is a simple web-based UI for SANE which allows you to share a scanner on a network without the need for drivers or complicated installation.";
    homepage = "https://github.com/sbs20/scanservjs";
    license = lib.licenses.gpl2Only;
    mainProgram = "scanservjs";
    maintainers = with lib.maintainers; [ chayleaf ];
    platforms = lib.platforms.linux;
  };
}