mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-03-08 06:08:21 +01:00
Add Manyfold add-on integration
This commit is contained in:
55
manyfold/CHANGELOG.md
Normal file
55
manyfold/CHANGELOG.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.3
|
||||
|
||||
- Added the add-on to this repository under the official add-on folder/slug name `manyfold`.
|
||||
- Updated image namespace and repository metadata for this repository:
|
||||
- `image: ghcr.io/alexbelgium/manyfold-{arch}`
|
||||
- `url: https://github.com/alexbelgium/hassio-addons/tree/master/manyfold`
|
||||
- Updated AppArmor profile name to `hassio-addons/manyfold`.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
- Added build metadata for Home Assistant CI compatibility:
|
||||
- `manyfold/build.yaml` with multi-arch `build_from` entries
|
||||
- image template wiring in `config.yaml`
|
||||
- Switched Docker base wiring to Home Assistant add-on build conventions:
|
||||
- `Dockerfile` now uses `ARG BUILD_FROM` and `FROM ${BUILD_FROM}`
|
||||
- Updated add-on `url` metadata to this repository path.
|
||||
- Updated repository README to remove obsolete `import_path` references.
|
||||
- Added ShellCheck compatibility headers (`# shellcheck shell=bash`) to s6/entry scripts using `with-contenv`.
|
||||
- Removed default-valued metadata keys (`apparmor`, `boot`, `ingress`, `stage`) to satisfy add-on linter rules.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- New resource tuning options for smaller HAOS hosts:
|
||||
- `web_concurrency`
|
||||
- `rails_max_threads`
|
||||
- `default_worker_concurrency`
|
||||
- `performance_worker_concurrency`
|
||||
- `max_file_upload_size`
|
||||
- `max_file_extract_size`
|
||||
- Baseline AppArmor support:
|
||||
- `apparmor: true` in add-on metadata
|
||||
- `manyfold/apparmor.txt` profile
|
||||
- Removed `import_path` option and runtime wiring to reduce confusion (it was not a web import endpoint).
|
||||
- Kept ingress disabled and documented direct access on port `3214`.
|
||||
- Host media mappings (`/share`, `/media`) are writable to support writable library paths like `/media/manyfold/models`.
|
||||
- Home Assistant ingress/panel 404 issue by moving to direct web UI access model.
|
||||
- Startup/runtime setup improvements:
|
||||
- Better path validation for configured library and thumbnails paths
|
||||
- Clearer startup logs and configuration summary
|
||||
- More robust secret/bootstrap handling and ownership setup
|
||||
- Recommended small-server baseline (see README):
|
||||
- `web_concurrency: 1`
|
||||
- `rails_max_threads: 5`
|
||||
- `default_worker_concurrency: 2`
|
||||
- `performance_worker_concurrency: 1`
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- First Home Assistant add-on packaging for Manyfold (`manyfold`).
|
||||
- Runs `ghcr.io/manyfold3d/manyfold-solo` with persistent data under `/config`.
|
||||
- Sidebar/web UI integration on port `3214`.
|
||||
- Configurable storage paths and startup path safety checks.
|
||||
- Non-root runtime defaults (`puid`/`pgid`) and startup ownership handling.
|
||||
27
manyfold/Dockerfile
Normal file
27
manyfold/Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
||||
ARG BUILD_FROM=ghcr.io/manyfold3d/manyfold-solo:latest
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# hadolint ignore=DL3041
|
||||
RUN set -eux; \
|
||||
if command -v apk >/dev/null 2>&1; then \
|
||||
apk add --no-cache bash coreutils jq openssl; \
|
||||
elif command -v apt-get >/dev/null 2>&1; then \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends bash coreutils jq openssl ca-certificates; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
elif command -v dnf >/dev/null 2>&1; then \
|
||||
dnf install -y bash coreutils jq openssl; \
|
||||
dnf clean all; \
|
||||
else \
|
||||
echo "Unsupported base image: missing apk/apt-get/dnf"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
COPY run.sh /run.sh
|
||||
COPY rootfs /
|
||||
|
||||
RUN chmod +x /run.sh \
|
||||
&& chmod +x /etc/s6-overlay/s6-rc.d/manyfold/run \
|
||||
&& chmod +x /etc/s6-overlay/s6-rc.d/manyfold/finish
|
||||
|
||||
ENTRYPOINT ["/init"]
|
||||
132
manyfold/README.md
Normal file
132
manyfold/README.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Manyfold Home Assistant Add-on
|
||||
|
||||
This add-on wraps `ghcr.io/manyfold3d/manyfold-solo` for Home Assistant OS with persistent storage and configurable host-backed media paths.
|
||||
|
||||
Documentation: [manyfold.app/get-started](https://manyfold.app/get-started/)
|
||||
|
||||
## Features
|
||||
|
||||
- Runs Manyfold on port `3214`.
|
||||
- Persists app data, database, cache, and settings under `/config` (`addon_config`).
|
||||
- Uses a configurable library path on Home Assistant host storage.
|
||||
- Refuses startup if configured paths resolve outside `/share`, `/media`, or `/config`.
|
||||
- No external PostgreSQL or Redis required.
|
||||
- Supports `amd64` and `aarch64`.
|
||||
- Includes a baseline AppArmor profile.
|
||||
|
||||
## Default paths
|
||||
|
||||
- Library path: `/share/manyfold/models`
|
||||
- Thumbnails path: `/config/thumbnails`
|
||||
|
||||
## Installation
|
||||
|
||||
1. In Home Assistant OS Add-on Store, open menu (`...`) -> `Repositories`.
|
||||
2. Add the Git repository URL for this add-on repository root (the repo includes `repository.yaml` and `manyfold/`).
|
||||
3. Refresh Add-on Store and install **Manyfold**.
|
||||
4. Configure options (defaults are safe for first run):
|
||||
- `library_path`: `/share/manyfold/models`
|
||||
- `secret_key_base`: leave blank to auto-generate
|
||||
- `puid` / `pgid`: set to a non-root UID/GID (see "Fix root warning (PUID/PGID)" below)
|
||||
- optionally tune worker/thread and upload limits in "Small server tuning" below
|
||||
5. Start the add-on.
|
||||
6. Open `http://<HA_IP>:3214`.
|
||||
|
||||
Before first start, ensure your library folder exists on the host:
|
||||
|
||||
```bash
|
||||
mkdir -p /share/manyfold/models
|
||||
```
|
||||
|
||||
Local development alternative on the HA host:
|
||||
|
||||
1. Copy `manyfold/` to `/addons/manyfold`.
|
||||
2. In Add-on Store menu (`...`), click `Check for updates`.
|
||||
3. Install and run **Manyfold** from local add-ons.
|
||||
|
||||
## Library/index workflow
|
||||
|
||||
1. Drop STL/3MF/etc into `/share/manyfold/models` on the host.
|
||||
2. In Manyfold UI, configure a library that points to the same container path.
|
||||
3. Thumbnails and indexing artifacts persist in `/config/thumbnails`.
|
||||
|
||||
## Options
|
||||
|
||||
- `secret_key_base`: App secret. Auto-generated and persisted at `/config/secret_key_base` when empty.
|
||||
- `puid` / `pgid`: Ownership applied to writable mapped directories (`/config` paths).
|
||||
- `multiuser`: Toggle Manyfold multiuser mode.
|
||||
- `library_path`: Scanned/indexed path.
|
||||
- `thumbnails_path`: Persistent thumbnails/index artifacts (must be under `/config`).
|
||||
- `log_level`: `info`, `debug`, `warn`, `error`.
|
||||
- `web_concurrency`: Puma worker process count.
|
||||
- `rails_max_threads`: Max threads per Puma worker.
|
||||
- `default_worker_concurrency`: Sidekiq default queue concurrency.
|
||||
- `performance_worker_concurrency`: Sidekiq performance queue concurrency.
|
||||
- `max_file_upload_size`: Max uploaded archive size in bytes.
|
||||
- `max_file_extract_size`: Max extracted archive size in bytes.
|
||||
|
||||
## Small server tuning
|
||||
|
||||
For low-memory HAOS hosts, start with:
|
||||
|
||||
```yaml
|
||||
web_concurrency: 1
|
||||
rails_max_threads: 5
|
||||
default_worker_concurrency: 2
|
||||
performance_worker_concurrency: 1
|
||||
max_file_upload_size: 268435456
|
||||
max_file_extract_size: 536870912
|
||||
```
|
||||
|
||||
Then restart the add-on and increase gradually only if needed.
|
||||
|
||||
## Fix root warning (PUID/PGID)
|
||||
|
||||
If Manyfold shows:
|
||||
|
||||
`Manyfold is running as root, which is a security risk.`
|
||||
|
||||
set `puid` and `pgid` in the add-on Configuration tab to a non-root UID/GID.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
puid: 1000
|
||||
pgid: 1000
|
||||
```
|
||||
|
||||
How to find the correct values in Home Assistant:
|
||||
|
||||
1. Open the **Terminal & SSH** add-on (or SSH into the HA host).
|
||||
2. If you know the target Linux user name, run:
|
||||
|
||||
```bash
|
||||
id <username>
|
||||
```
|
||||
|
||||
Use the `uid=` value for `puid` and `gid=` value for `pgid`.
|
||||
|
||||
If you do not have a specific username, use the owner of the Manyfold folders:
|
||||
|
||||
```bash
|
||||
stat -c '%u %g' /share/manyfold/models
|
||||
```
|
||||
|
||||
Set `puid`/`pgid` to those numbers.
|
||||
|
||||
After changing values:
|
||||
|
||||
1. Save add-on Configuration.
|
||||
2. Restart the Manyfold add-on.
|
||||
3. Check logs for `puid:pgid=<uid>:<gid>` and confirm the warning is gone.
|
||||
|
||||
## Validation behavior
|
||||
|
||||
- Startup fails if `library_path` or `thumbnails_path` resolve outside mapped storage roots.
|
||||
- `thumbnails_path` must resolve under `/config` to guarantee persistence.
|
||||
- Startup fails if `library_path` is not readable.
|
||||
|
||||
## Notes
|
||||
|
||||
- This baseline avoids Home Assistant ingress and keeps direct port access.
|
||||
- If `puid`/`pgid` change, restart the add-on to re-apply ownership to mapped directories.
|
||||
18
manyfold/apparmor.txt
Normal file
18
manyfold/apparmor.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <tunables/global>
|
||||
|
||||
profile hassio-addons/manyfold flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/bash>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/openssl>
|
||||
|
||||
# Baseline profile for Manyfold in HAOS. Keep broad compatibility while
|
||||
# denying known high-risk kernel interfaces.
|
||||
file,
|
||||
network,
|
||||
capability,
|
||||
|
||||
deny /proc/kcore rwklx,
|
||||
deny /proc/sysrq-trigger rwklx,
|
||||
deny /sys/firmware/** rwklx,
|
||||
}
|
||||
4
manyfold/build.yaml
Normal file
4
manyfold/build.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
build_from:
|
||||
aarch64: ghcr.io/manyfold3d/manyfold-solo:latest
|
||||
amd64: ghcr.io/manyfold3d/manyfold-solo:latest
|
||||
53
manyfold/config.yaml
Normal file
53
manyfold/config.yaml
Normal file
@@ -0,0 +1,53 @@
|
||||
name: "Manyfold"
|
||||
slug: manyfold
|
||||
description: "Manyfold 3D model manager as a Home Assistant add-on, using the upstream image with configurable library/index paths."
|
||||
version: "1.0.3"
|
||||
url: "https://github.com/alexbelgium/hassio-addons/tree/master/manyfold"
|
||||
image: ghcr.io/alexbelgium/manyfold-{arch}
|
||||
arch:
|
||||
- amd64
|
||||
- aarch64
|
||||
startup: services
|
||||
init: false
|
||||
|
||||
ports:
|
||||
3214/tcp: 3214
|
||||
ports_description:
|
||||
3214/tcp: "Manyfold Web UI"
|
||||
|
||||
webui: "http://[HOST]:[PORT:3214]"
|
||||
|
||||
map:
|
||||
- addon_config:rw
|
||||
- share:rw
|
||||
- media:rw
|
||||
|
||||
options:
|
||||
secret_key_base: ""
|
||||
puid: 1000
|
||||
pgid: 1000
|
||||
multiuser: true
|
||||
library_path: "/share/manyfold/models"
|
||||
thumbnails_path: "/config/thumbnails"
|
||||
log_level: "info"
|
||||
web_concurrency: 4
|
||||
rails_max_threads: 16
|
||||
default_worker_concurrency: 4
|
||||
performance_worker_concurrency: 1
|
||||
max_file_upload_size: 1073741824
|
||||
max_file_extract_size: 1073741824
|
||||
|
||||
schema:
|
||||
secret_key_base: str
|
||||
puid: int
|
||||
pgid: int
|
||||
multiuser: bool
|
||||
library_path: str
|
||||
thumbnails_path: str
|
||||
log_level: list(info|debug|warn|error)
|
||||
web_concurrency: int
|
||||
rails_max_threads: int
|
||||
default_worker_concurrency: int
|
||||
performance_worker_concurrency: int
|
||||
max_file_upload_size: int
|
||||
max_file_extract_size: int
|
||||
BIN
manyfold/icon.png
Normal file
BIN
manyfold/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
manyfold/logo.png
Normal file
BIN
manyfold/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
3
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish
Executable file
3
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
exit 0
|
||||
3
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/run
Executable file
3
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/run
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
exec /run.sh
|
||||
1
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/type
Normal file
1
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/type
Normal file
@@ -0,0 +1 @@
|
||||
longrun
|
||||
253
manyfold/run.sh
Executable file
253
manyfold/run.sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
CONFIG_DIR="/config"
|
||||
OPTIONS_JSON="/data/options.json"
|
||||
SECRET_FILE="${CONFIG_DIR}/secret_key_base"
|
||||
DEFAULT_LIBRARY_PATH="/share/manyfold/models"
|
||||
DEFAULT_THUMBNAILS_PATH="/config/thumbnails"
|
||||
DEFAULT_LOG_LEVEL="info"
|
||||
DEFAULT_WEB_CONCURRENCY="4"
|
||||
DEFAULT_RAILS_MAX_THREADS="16"
|
||||
DEFAULT_DEFAULT_WORKER_CONCURRENCY="4"
|
||||
DEFAULT_PERFORMANCE_WORKER_CONCURRENCY="1"
|
||||
DEFAULT_MAX_FILE_UPLOAD_SIZE="1073741824"
|
||||
DEFAULT_MAX_FILE_EXTRACT_SIZE="1073741824"
|
||||
|
||||
log() {
|
||||
echo "[manyfold-addon] $*"
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "[manyfold-addon] ERROR: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
read_opt() {
|
||||
local key="$1"
|
||||
jq -er --arg k "$key" '.[$k]' "$OPTIONS_JSON" 2>/dev/null || true
|
||||
}
|
||||
|
||||
normalize_path() {
|
||||
local raw="$1"
|
||||
if command -v realpath >/dev/null 2>&1; then
|
||||
realpath -m "$raw"
|
||||
return
|
||||
fi
|
||||
|
||||
case "$raw" in
|
||||
/*) printf '%s\n' "$raw" ;;
|
||||
*) printf '/%s\n' "$raw" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
is_allowed_path() {
|
||||
local resolved="$1"
|
||||
case "$resolved" in
|
||||
/share|/share/*|/media|/media/*|/config|/config/*)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
require_mapped_path() {
|
||||
local label="$1"
|
||||
local raw="$2"
|
||||
local resolved
|
||||
|
||||
resolved="$(normalize_path "$raw")"
|
||||
if ! is_allowed_path "$resolved"; then
|
||||
die "${label} '${raw}' resolves to '${resolved}', which is outside /share, /media, and /config"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$resolved"
|
||||
}
|
||||
|
||||
ensure_dir() {
|
||||
local dir="$1"
|
||||
mkdir -p "$dir"
|
||||
}
|
||||
|
||||
ensure_existing_or_create() {
|
||||
local label="$1"
|
||||
local dir="$2"
|
||||
|
||||
if [[ -d "$dir" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if mkdir -p "$dir" 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
die "${label} '${dir}' does not exist and could not be created. Create it on the host or choose a writable path under /config."
|
||||
}
|
||||
|
||||
chown_recursive_if_writable() {
|
||||
local owner="$1"
|
||||
local path="$2"
|
||||
|
||||
if [[ ! -e "$path" ]]; then
|
||||
log "Skipping ownership update for ${path} (missing path)"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -w "$path" ]]; then
|
||||
chown -R "$owner" "$path"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Skipping ownership update for ${path} (read-only mapping)"
|
||||
}
|
||||
|
||||
generate_secret() {
|
||||
if command -v openssl >/dev/null 2>&1; then
|
||||
openssl rand -hex 64
|
||||
return
|
||||
fi
|
||||
|
||||
head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n'
|
||||
}
|
||||
|
||||
start_manyfold() {
|
||||
if [[ -x /usr/src/app/bin/docker-entrypoint.sh ]]; then
|
||||
log "Starting Manyfold via /usr/src/app/bin/docker-entrypoint.sh foreman start"
|
||||
cd /usr/src/app
|
||||
exec ./bin/docker-entrypoint.sh foreman start
|
||||
fi
|
||||
|
||||
if [[ -x /app/bin/docker-entrypoint.sh ]]; then
|
||||
log "Starting Manyfold via /app/bin/docker-entrypoint.sh foreman start"
|
||||
cd /app
|
||||
exec ./bin/docker-entrypoint.sh foreman start
|
||||
fi
|
||||
|
||||
local candidate
|
||||
for candidate in \
|
||||
/usr/local/bin/docker-entrypoint.sh \
|
||||
/usr/local/bin/docker-entrypoint \
|
||||
/docker-entrypoint.sh \
|
||||
/entrypoint.sh
|
||||
do
|
||||
if [[ -x "$candidate" ]]; then
|
||||
log "Starting Manyfold via ${candidate}"
|
||||
if [[ "$candidate" == *docker-entrypoint* ]]; then
|
||||
exec "$candidate" foreman start
|
||||
fi
|
||||
exec "$candidate"
|
||||
fi
|
||||
done
|
||||
|
||||
if command -v docker-entrypoint >/dev/null 2>&1; then
|
||||
log "Starting Manyfold via docker-entrypoint"
|
||||
exec docker-entrypoint foreman start
|
||||
fi
|
||||
|
||||
if [[ -d /usr/src/app ]]; then
|
||||
cd /usr/src/app
|
||||
elif [[ -d /app ]]; then
|
||||
cd /app
|
||||
fi
|
||||
|
||||
if command -v bundle >/dev/null 2>&1; then
|
||||
log "Starting Manyfold via rails server fallback"
|
||||
exec bundle exec rails server -b 0.0.0.0 -p 3214
|
||||
fi
|
||||
|
||||
die "Could not find a known Manyfold entrypoint"
|
||||
}
|
||||
|
||||
[[ -f "$OPTIONS_JSON" ]] || die "Missing options file at ${OPTIONS_JSON}"
|
||||
|
||||
PUID="$(read_opt puid)"; PUID="${PUID:-1000}"
|
||||
PGID="$(read_opt pgid)"; PGID="${PGID:-1000}"
|
||||
MULTIUSER="$(read_opt multiuser)"; MULTIUSER="${MULTIUSER:-true}"
|
||||
LIBRARY_PATH_RAW="$(read_opt library_path)"; LIBRARY_PATH_RAW="${LIBRARY_PATH_RAW:-$DEFAULT_LIBRARY_PATH}"
|
||||
THUMBNAILS_PATH_RAW="$(read_opt thumbnails_path)"; THUMBNAILS_PATH_RAW="${THUMBNAILS_PATH_RAW:-$DEFAULT_THUMBNAILS_PATH}"
|
||||
LOG_LEVEL="$(read_opt log_level)"; LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}"
|
||||
WEB_CONCURRENCY="$(read_opt web_concurrency)"; WEB_CONCURRENCY="${WEB_CONCURRENCY:-$DEFAULT_WEB_CONCURRENCY}"
|
||||
RAILS_MAX_THREADS="$(read_opt rails_max_threads)"; RAILS_MAX_THREADS="${RAILS_MAX_THREADS:-$DEFAULT_RAILS_MAX_THREADS}"
|
||||
DEFAULT_WORKER_CONCURRENCY="$(read_opt default_worker_concurrency)"; DEFAULT_WORKER_CONCURRENCY="${DEFAULT_WORKER_CONCURRENCY:-$DEFAULT_DEFAULT_WORKER_CONCURRENCY}"
|
||||
PERFORMANCE_WORKER_CONCURRENCY="$(read_opt performance_worker_concurrency)"; PERFORMANCE_WORKER_CONCURRENCY="${PERFORMANCE_WORKER_CONCURRENCY:-$DEFAULT_PERFORMANCE_WORKER_CONCURRENCY}"
|
||||
MAX_FILE_UPLOAD_SIZE="$(read_opt max_file_upload_size)"; MAX_FILE_UPLOAD_SIZE="${MAX_FILE_UPLOAD_SIZE:-$DEFAULT_MAX_FILE_UPLOAD_SIZE}"
|
||||
MAX_FILE_EXTRACT_SIZE="$(read_opt max_file_extract_size)"; MAX_FILE_EXTRACT_SIZE="${MAX_FILE_EXTRACT_SIZE:-$DEFAULT_MAX_FILE_EXTRACT_SIZE}"
|
||||
SECRET_KEY_BASE="$(read_opt secret_key_base)"; SECRET_KEY_BASE="${SECRET_KEY_BASE:-}"
|
||||
|
||||
[[ "$PUID" =~ ^[0-9]+$ ]] || die "puid must be a non-negative integer"
|
||||
[[ "$PGID" =~ ^[0-9]+$ ]] || die "pgid must be a non-negative integer"
|
||||
[[ "$WEB_CONCURRENCY" =~ ^[1-9][0-9]*$ ]] || die "web_concurrency must be a positive integer"
|
||||
[[ "$RAILS_MAX_THREADS" =~ ^[1-9][0-9]*$ ]] || die "rails_max_threads must be a positive integer"
|
||||
[[ "$DEFAULT_WORKER_CONCURRENCY" =~ ^[1-9][0-9]*$ ]] || die "default_worker_concurrency must be a positive integer"
|
||||
[[ "$PERFORMANCE_WORKER_CONCURRENCY" =~ ^[1-9][0-9]*$ ]] || die "performance_worker_concurrency must be a positive integer"
|
||||
[[ "$MAX_FILE_UPLOAD_SIZE" =~ ^[1-9][0-9]*$ ]] || die "max_file_upload_size must be a positive integer (bytes)"
|
||||
[[ "$MAX_FILE_EXTRACT_SIZE" =~ ^[1-9][0-9]*$ ]] || die "max_file_extract_size must be a positive integer (bytes)"
|
||||
|
||||
LIBRARY_PATH="$(require_mapped_path "library_path" "$LIBRARY_PATH_RAW")"
|
||||
THUMBNAILS_PATH="$(require_mapped_path "thumbnails_path" "$THUMBNAILS_PATH_RAW")"
|
||||
|
||||
case "$THUMBNAILS_PATH" in
|
||||
/config|/config/*) ;;
|
||||
*) die "thumbnails_path must resolve under /config for persistence" ;;
|
||||
esac
|
||||
|
||||
ensure_dir "$CONFIG_DIR"
|
||||
ensure_dir "$DEFAULT_THUMBNAILS_PATH"
|
||||
ensure_existing_or_create "library_path" "$LIBRARY_PATH"
|
||||
ensure_dir "$THUMBNAILS_PATH"
|
||||
[[ -r "$LIBRARY_PATH" ]] || die "library_path '${LIBRARY_PATH}' is not readable"
|
||||
|
||||
if [[ -z "$SECRET_KEY_BASE" ]]; then
|
||||
if [[ -s "$SECRET_FILE" ]]; then
|
||||
SECRET_KEY_BASE="$(cat "$SECRET_FILE")"
|
||||
log "Loaded SECRET_KEY_BASE from ${SECRET_FILE}"
|
||||
else
|
||||
SECRET_KEY_BASE="$(generate_secret)"
|
||||
printf '%s' "$SECRET_KEY_BASE" > "$SECRET_FILE"
|
||||
chmod 600 "$SECRET_FILE"
|
||||
log "Generated and stored SECRET_KEY_BASE at ${SECRET_FILE}"
|
||||
fi
|
||||
else
|
||||
printf '%s' "$SECRET_KEY_BASE" > "$SECRET_FILE"
|
||||
chmod 600 "$SECRET_FILE"
|
||||
log "Saved provided SECRET_KEY_BASE to ${SECRET_FILE}"
|
||||
fi
|
||||
|
||||
export SECRET_KEY_BASE
|
||||
export PUID
|
||||
export PGID
|
||||
export MULTIUSER
|
||||
export MANYFOLD_MULTIUSER="$MULTIUSER"
|
||||
export MANYFOLD_LIBRARY_PATH="$LIBRARY_PATH"
|
||||
export MANYFOLD_THUMBNAILS_PATH="$THUMBNAILS_PATH"
|
||||
export RAILS_LOG_LEVEL="$LOG_LEVEL"
|
||||
export MANYFOLD_LOG_LEVEL="$LOG_LEVEL"
|
||||
export WEB_CONCURRENCY
|
||||
export RAILS_MAX_THREADS
|
||||
export DEFAULT_WORKER_CONCURRENCY
|
||||
export PERFORMANCE_WORKER_CONCURRENCY
|
||||
export MAX_FILE_UPLOAD_SIZE
|
||||
export MAX_FILE_EXTRACT_SIZE
|
||||
export PORT="3214"
|
||||
|
||||
chown_recursive_if_writable "$PUID:$PGID" "$CONFIG_DIR"
|
||||
chown_recursive_if_writable "$PUID:$PGID" "$DEFAULT_THUMBNAILS_PATH"
|
||||
chown_recursive_if_writable "$PUID:$PGID" "$LIBRARY_PATH"
|
||||
chown_recursive_if_writable "$PUID:$PGID" "$THUMBNAILS_PATH"
|
||||
|
||||
log "Configuration summary:"
|
||||
log " library_path=${LIBRARY_PATH}"
|
||||
log " thumbnails_path=${THUMBNAILS_PATH}"
|
||||
log " multiuser=${MULTIUSER}"
|
||||
log " puid:pgid=${PUID}:${PGID}"
|
||||
log " web_concurrency=${WEB_CONCURRENCY}"
|
||||
log " rails_max_threads=${RAILS_MAX_THREADS}"
|
||||
log " default_worker_concurrency=${DEFAULT_WORKER_CONCURRENCY}"
|
||||
log " performance_worker_concurrency=${PERFORMANCE_WORKER_CONCURRENCY}"
|
||||
log " max_file_upload_size=${MAX_FILE_UPLOAD_SIZE}"
|
||||
log " max_file_extract_size=${MAX_FILE_EXTRACT_SIZE}"
|
||||
|
||||
start_manyfold
|
||||
40
manyfold/translations/en.yaml
Normal file
40
manyfold/translations/en.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
configuration:
|
||||
secret_key_base:
|
||||
name: Secret key base
|
||||
description: Leave blank to auto-generate and persist at /config/secret_key_base.
|
||||
puid:
|
||||
name: PUID
|
||||
description: User ID for file ownership on writable mapped volumes.
|
||||
pgid:
|
||||
name: PGID
|
||||
description: Group ID for file ownership on writable mapped volumes.
|
||||
multiuser:
|
||||
name: Multiuser mode
|
||||
description: Enable or disable Manyfold multiuser login.
|
||||
library_path:
|
||||
name: Library path
|
||||
description: Folder scanned/indexed by Manyfold. Must be under /share, /media, or /config.
|
||||
thumbnails_path:
|
||||
name: Thumbnails path
|
||||
description: Path for thumbnails/index artifacts. Must resolve under /config.
|
||||
log_level:
|
||||
name: Log level
|
||||
description: Rails log verbosity.
|
||||
web_concurrency:
|
||||
name: Web workers
|
||||
description: Puma worker process count (WEB_CONCURRENCY). Lower this on small servers.
|
||||
rails_max_threads:
|
||||
name: Web max threads
|
||||
description: Max threads per Puma worker (RAILS_MAX_THREADS). Lower values reduce memory use.
|
||||
default_worker_concurrency:
|
||||
name: Default worker concurrency
|
||||
description: Sidekiq concurrency for the default worker queue.
|
||||
performance_worker_concurrency:
|
||||
name: Performance worker concurrency
|
||||
description: Sidekiq concurrency for the performance queue.
|
||||
max_file_upload_size:
|
||||
name: Max upload size (bytes)
|
||||
description: Upper limit for uploaded archive size (MAX_FILE_UPLOAD_SIZE).
|
||||
max_file_extract_size:
|
||||
name: Max extract size (bytes)
|
||||
description: Upper limit for extracted archive size (MAX_FILE_EXTRACT_SIZE).
|
||||
Reference in New Issue
Block a user