Wiki-Serve-Skript war bisher in ~/.local/bin/, jetzt auch im Repo versioniert, damit Updates via git pull verfügbar sind. CHANGELOG korrigiert: server.py jetzt +12 Zeilen statt +7 (Bug-Fix für trailing '/' ist mit drin).
346 lines
13 KiB
Bash
Executable File
346 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# hermes-wiki-serve.sh — Hermes Wiki via obsidian-web-viewer + Tailscale
|
|
#
|
|
# Was dieses Skript tut:
|
|
# - Klont DanielCheer/obsidian-web-viewer einmalig nach ~/.local/share/hermes-wiki/owv/
|
|
# - Startet deren server.py (Python stdlib) auf 127.0.0.1:8765 (Loopback)
|
|
# - Aktiviert tailscale serve, der den Loopback-Port als https im Tailnet exponen lässt
|
|
# - Liefert File-Tree, 3D-Graph, Volltext-Suche, WikiLink-Navigation out-of-the-box
|
|
#
|
|
# Verwendung:
|
|
# hermes-wiki-serve.sh start # Server starten (klont obv beim ersten Mal)
|
|
# hermes-wiki-serve.sh stop # Server stoppen
|
|
# hermes-wiki-serve.sh restart # stop + start
|
|
# hermes-wiki-serve.sh status # Process-Status, Health-Check, Tailscale-URL
|
|
# hermes-wiki-serve.sh logs # tail -f der Log-Files
|
|
# hermes-wiki-serve.sh install # nur das Clonen/Update, kein Server-Start
|
|
# hermes-wiki-serve.sh --help
|
|
#
|
|
# Umgebungsvariablen:
|
|
# HERMES_WIKI_PORT=8765 Lokaler HTTP-Port (Loopback)
|
|
# HERMES_WIKI_DIR=/home/admin/my-karpathy-wiki
|
|
# HERMES_WIKI_LOG_DIR=$HOME/.local/share/hermes-wiki/log
|
|
# HERMES_WIKI_TS=auto auto|yes|no — Tailscale serve aktivieren
|
|
# HERMES_WIKI_TS_PATH= leer=Root-Prefix (default), /wiki=unter-Pfad
|
|
# HERMES_WIKI_OWV_DIR=$HOME/repos/hermes-wiki-viewer (Lukas-Fork default; upstream obv als Fallback)
|
|
|
|
set -euo pipefail
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Defaults
|
|
# ---------------------------------------------------------------------------
|
|
readonly HERMES_WIKI_PORT="${HERMES_WIKI_PORT:-8765}"
|
|
readonly HERMES_WIKI_DIR="${HERMES_WIKI_DIR:-/home/admin/my-karpathy-wiki}"
|
|
readonly HERMES_WIKI_LOG_DIR="${HERMES_WIKI_LOG_DIR:-$HOME/.local/share/hermes-wiki/log}"
|
|
readonly HERMES_WIKI_TS="${HERMES_WIKI_TS:-auto}"
|
|
readonly HERMES_WIKI_TS_PATH="${HERMES_WIKI_TS_PATH:-}" # leer = Root-Prefix (obv nutzt relative URLs!)
|
|
readonly HERMES_WIKI_OWV_DIR="${HERMES_WIKI_OWV_DIR:-$HOME/repos/hermes-wiki-viewer}"
|
|
readonly HERMES_WIKI_REPO="${HERMES_WIKI_REPO:-}" # leer = lokales Lukas-Repo nutzen
|
|
readonly OWV_REPO_UPSTREAM="https://github.com/DanielCheer/obsidian-web-viewer.git"
|
|
readonly PID_FILE="/tmp/hermes-wiki-serve.pid"
|
|
readonly HEALTH_URL="http://127.0.0.1:${HERMES_WIKI_PORT}/api/vault/tree"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
log() {
|
|
printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*" | tee -a "$HERMES_WIKI_LOG_DIR/server.log" >&2
|
|
}
|
|
|
|
die() {
|
|
log "ERROR: $*"
|
|
exit 1
|
|
}
|
|
|
|
ensure_dirs() {
|
|
mkdir -p "$HERMES_WIKI_LOG_DIR" || die "Kann Log-Dir nicht erstellen: $HERMES_WIKI_LOG_DIR"
|
|
}
|
|
|
|
require_tools() {
|
|
command -v python3 >/dev/null || die "python3 nicht gefunden"
|
|
command -v git >/dev/null || die "git nicht gefunden"
|
|
[ -d "$HERMES_WIKI_DIR" ] || die "Wiki-Verzeichnis nicht gefunden: $HERMES_WIKI_DIR"
|
|
}
|
|
|
|
detect_tailscale() {
|
|
[ "$HERMES_WIKI_TS" != "no" ] || return 1
|
|
command -v tailscale >/dev/null || return 1
|
|
tailscale status --json >/dev/null 2>&1 || return 1
|
|
return 0
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Installation: Repo klonen oder updaten
|
|
# ---------------------------------------------------------------------------
|
|
install_repo() {
|
|
# Mode 1: Lokales Lukas-Repo (~/repos/hermes-wiki-viewer/) — default nach Fork
|
|
if [ -d "$HERMES_WIKI_OWV_DIR/.git" ] && [ -z "$HERMES_WIKI_REPO" ]; then
|
|
log "Nutze lokales Lukas-Repo: $HERMES_WIKI_OWV_DIR"
|
|
(cd "$HERMES_WIKI_OWV_DIR" && git pull --ff-only 2>>"$HERMES_WIKI_LOG_DIR/install.log") || \
|
|
log "WARN: git pull fehlgeschlagen — nutze Working-Tree-Stand"
|
|
# Mode 2: Remote Lukas-Repo klonen (z.B. wenn HERMES_WIKI_REPO gesetzt)
|
|
elif [ -n "$HERMES_WIKI_REPO" ]; then
|
|
if [ -d "$HERMES_WIKI_OWV_DIR/.git" ]; then
|
|
log "Update Lukas-Fork in $HERMES_WIKI_OWV_DIR"
|
|
(cd "$HERMES_WIKI_OWV_DIR" && git pull --ff-only 2>>"$HERMES_WIKI_LOG_DIR/install.log") || \
|
|
log "WARN: git pull fehlgeschlagen"
|
|
else
|
|
log "Klone Lukas-Fork $HERMES_WIKI_REPO nach $HERMES_WIKI_OWV_DIR"
|
|
git clone "$HERMES_WIKI_REPO" "$HERMES_WIKI_OWV_DIR" 2>>"$HERMES_WIKI_LOG_DIR/install.log" || \
|
|
die "git clone fehlgeschlagen — Repo-URL korrekt?"
|
|
fi
|
|
# Mode 3: Fallback — upstream obv direkt (vor Lukas-Fork)
|
|
else
|
|
log "Kein Lukas-Repo gefunden, klone upstream obv nach $HERMES_WIKI_OWV_DIR"
|
|
log "(Für Lukas-Customizations: HERMES_WIKI_OWV_DIR=/path/to/hermes-wiki-viewer setzen)"
|
|
git clone "$OWV_REPO_UPSTREAM" "$HERMES_WIKI_OWV_DIR" 2>>"$HERMES_WIKI_LOG_DIR/install.log" || \
|
|
die "git clone fehlgeschlagen"
|
|
fi
|
|
|
|
# requirements.txt: nur PyYAML (optional). Stdlib reicht für unsere Zwecke.
|
|
if ! python3 -c "import yaml" 2>/dev/null; then
|
|
log "PyYAML nicht installiert (optional). Installiere..."
|
|
python3 -m pip install --user --quiet PyYAML 2>>"$HERMES_WIKI_LOG_DIR/install.log" || \
|
|
log "WARN: PyYAML-Installation fehlgeschlagen — Frontmatter wird rudimentär behandelt"
|
|
fi
|
|
log "Wiki-Viewer bereit in $HERMES_WIKI_OWV_DIR"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tailscale-Integration
|
|
# ---------------------------------------------------------------------------
|
|
start_tailscale() {
|
|
detect_tailscale || {
|
|
[ "$HERMES_WIKI_TS" = "no" ] || \
|
|
log "Tailscale übersprungen (nicht verfügbar oder HERMES_WIKI_TS=$HERMES_WIKI_TS)"
|
|
return 0
|
|
}
|
|
|
|
if tailscale serve status --bg 2>/dev/null | grep -q "$HERMES_WIKI_PORT"; then
|
|
log "Tailscale serve bereits aktiv für Port $HERMES_WIKI_PORT"
|
|
return 0
|
|
fi
|
|
|
|
log "Starte tailscale serve auf Root-Prefix -> 127.0.0.1:$HERMES_WIKI_PORT"
|
|
local ts_path_arg=()
|
|
if [ -n "$HERMES_WIKI_TS_PATH" ]; then
|
|
ts_path_arg=(--set-path="$HERMES_WIKI_TS_PATH")
|
|
log "(Tailscale wird unter /$HERMES_WIKI_TS_PATH/ exposen — Achtung: obv nutzt relative URLs!)"
|
|
fi
|
|
if tailscale serve --bg --https=443 "${ts_path_arg[@]}" \
|
|
"http://127.0.0.1:$HERMES_WIKI_PORT" 2>>"$HERMES_WIKI_LOG_DIR/tailscale.log"; then
|
|
local ts_url
|
|
ts_url=$(tailscale serve status --json 2>/dev/null | python3 -c "
|
|
import json, sys
|
|
try:
|
|
data = json.load(sys.stdin)
|
|
for entry in data.get('Web', {}).values():
|
|
print(f'https://{entry[\"HTTPS\"]}{entry[\"Path\"]}/')
|
|
break
|
|
except: pass
|
|
" 2>/dev/null)
|
|
log "Tailscale serve aktiv: ${ts_url:-URL konnte nicht ermittelt werden}"
|
|
return 0
|
|
else
|
|
log "WARN: tailscale serve fehlgeschlagen — siehe $HERMES_WIKI_LOG_DIR/tailscale.log"
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
stop_tailscale() {
|
|
detect_tailscale || return 0
|
|
if tailscale serve status --bg 2>/dev/null | grep -q "$HERMES_WIKI_PORT"; then
|
|
log "Stoppe tailscale serve"
|
|
tailscale serve --bg --https=443 --set-path="$HERMES_WIKI_TS_PATH" off \
|
|
"http://127.0.0.1:$HERMES_WIKI_PORT" 2>>"$HERMES_WIKI_LOG_DIR/tailscale.log" || true
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Server-Lifecycle
|
|
# ---------------------------------------------------------------------------
|
|
is_running() {
|
|
[ -f "$PID_FILE" ] || return 1
|
|
local pid
|
|
pid=$(cat "$PID_FILE" 2>/dev/null || echo "")
|
|
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null
|
|
}
|
|
|
|
start_server() {
|
|
ensure_dirs
|
|
require_tools
|
|
install_repo
|
|
|
|
if is_running; then
|
|
log "Server läuft bereits (PID $(cat "$PID_FILE"))"
|
|
return 0
|
|
fi
|
|
|
|
# Port-Konflikt-Check
|
|
if ss -tln 2>/dev/null | grep -q ":${HERMES_WIKI_PORT} "; then
|
|
die "Port ${HERMES_WIKI_PORT} ist bereits belegt. HERMES_WIKI_PORT ändern oder Prozess beenden."
|
|
fi
|
|
|
|
# Check, dass die Wiki-Page gerendert werden kann
|
|
local md_count
|
|
md_count=$(find "$HERMES_WIKI_DIR" -name "*.md" -not -path "*/raw/*" 2>/dev/null | wc -l)
|
|
log "Wiki-Dir: $HERMES_WIKI_DIR ($md_count .md-Dateien, ohne /raw/)"
|
|
|
|
# Server starten — Loopback only, NICHT 0.0.0.0
|
|
log "Starte obsidian-web-viewer server.py auf 127.0.0.1:$HERMES_WIKI_PORT"
|
|
nohup python3 "$HERMES_WIKI_OWV_DIR/server.py" \
|
|
--vault "$HERMES_WIKI_DIR" \
|
|
--host 127.0.0.1 \
|
|
--port "$HERMES_WIKI_PORT" \
|
|
> "$HERMES_WIKI_LOG_DIR/renderer.log" 2>&1 &
|
|
local pid=$!
|
|
echo "$pid" > "$PID_FILE"
|
|
|
|
# Health-Check (das Tool hat keine /__health, aber /api/vault/tree ist immer da)
|
|
local i
|
|
for i in 1 2 3 4 5; do
|
|
sleep 1
|
|
if curl -sf "$HEALTH_URL" >/dev/null 2>&1; then
|
|
log "Server gestartet (PID $pid), Health-Check OK"
|
|
start_tailscale
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
log "ERROR: Health-Check fehlgeschlagen nach 5s"
|
|
log "--- renderer.log ---"
|
|
tail -20 "$HERMES_WIKI_LOG_DIR/renderer.log" >&2
|
|
rm -f "$PID_FILE"
|
|
return 1
|
|
}
|
|
|
|
stop_server() {
|
|
if is_running; then
|
|
local pid
|
|
pid=$(cat "$PID_FILE")
|
|
log "Stoppe Server (PID $pid)"
|
|
kill "$pid" 2>/dev/null || true
|
|
local i
|
|
for i in 1 2 3 4 5; do
|
|
kill -0 "$pid" 2>/dev/null || break
|
|
sleep 0.5
|
|
done
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
fi
|
|
rm -f "$PID_FILE"
|
|
fi
|
|
# Tailscale NICHT stoppen — soll laufen bleiben für Re-Start ohne Tailscale-Re-Init
|
|
# stop_tailscale
|
|
log "(Tailscale serve bleibt aktiv für Re-Start)"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Status / Help
|
|
# ---------------------------------------------------------------------------
|
|
show_status() {
|
|
echo "=== Hermes Wiki Server Status (via obsidian-web-viewer) ==="
|
|
echo "Wiki-Dir: $HERMES_WIKI_DIR"
|
|
echo "Viewer-Repo: $HERMES_WIKI_OWV_DIR"
|
|
echo "Port: $HERMES_WIKI_PORT (Loopback only)"
|
|
echo "Log-Dir: $HERMES_WIKI_LOG_DIR"
|
|
|
|
if is_running; then
|
|
local pid
|
|
pid=$(cat "$PID_FILE")
|
|
echo "Status: RUNNING (PID $pid)"
|
|
ps -o pid,rss,etime,cmd -p "$pid" 2>/dev/null | tail -1 | \
|
|
awk '{printf " Memory: %.1f MB, Uptime: %s\n", $2/1024, $3}'
|
|
|
|
if curl -sf "$HEALTH_URL" >/dev/null 2>&1; then
|
|
local md_count
|
|
md_count=$(curl -sf "$HEALTH_URL" | python3 -c "
|
|
import json, sys
|
|
try:
|
|
data = json.load(sys.stdin)
|
|
count = sum(1 + len(c.get('children',[])) for c in [data])
|
|
# grobe zählung
|
|
print(len(json.dumps(data)))
|
|
except: print('?')
|
|
" 2>/dev/null || echo "?")
|
|
echo "Health: OK (Tree-API reachable, $md_count bytes)"
|
|
else
|
|
echo "Health: FAILED"
|
|
fi
|
|
|
|
if detect_tailscale; then
|
|
if tailscale serve status --bg 2>&1 | grep -q "$HERMES_WIKI_PORT"; then
|
|
local ts_url
|
|
ts_url=$(tailscale serve status --json 2>/dev/null | python3 -c "
|
|
import json, sys
|
|
try:
|
|
data = json.load(sys.stdin)
|
|
for entry in data.get('Web', {}).values():
|
|
print(f'https://{entry[\"HTTPS\"]}{entry[\"Path\"]}/')
|
|
break
|
|
except: pass
|
|
" 2>/dev/null)
|
|
echo "Tailscale: AKTIV — ${ts_url:-URL nicht extrahierbar}"
|
|
else
|
|
echo "Tailscale: nicht aktiv für Port $HERMES_WIKI_PORT (HERMES_WIKI_TS=$HERMES_WIKI_TS)"
|
|
fi
|
|
else
|
|
echo "Tailscale: nicht verfügbar oder deaktiviert"
|
|
fi
|
|
else
|
|
echo "Status: NOT RUNNING"
|
|
fi
|
|
}
|
|
|
|
show_help() {
|
|
cat <<EOF
|
|
hermes-wiki-serve.sh — Hermes Wiki via obsidian-web-viewer + Tailscale
|
|
|
|
Dieses Skript wrapper't DanielCheer/obsidian-web-viewer (3D-Graph, File-Tree,
|
|
WikiLink-Navigation, Volltext-Suche, Catppuccin-Theme) und integriert Tailscale
|
|
serve für Tailnet-Zugriff.
|
|
|
|
Verwendung:
|
|
$0 start # Server starten (klont obv beim ersten Mal)
|
|
$0 stop # Server stoppen
|
|
$0 restart # stop + start
|
|
$0 status # Process-Status, Health-Check, Tailscale-URL
|
|
$0 logs # tail -f der Log-Files
|
|
$0 install # nur das Clonen/Update, kein Server-Start
|
|
$0 --help
|
|
|
|
Umgebungsvariablen:
|
|
HERMES_WIKI_PORT=8765
|
|
HERMES_WIKI_DIR=/home/admin/my-karpathy-wiki
|
|
HERMES_WIKI_LOG_DIR=\$HOME/.local/share/hermes-wiki/log
|
|
HERMES_WIKI_TS=auto auto|yes|no
|
|
HERMES_WIKI_TS_PATH=/wiki URL-Pfad unter dem Tailscale
|
|
HERMES_WIKI_OWV_DIR=\$HOME/.local/share/hermes-wiki/owv
|
|
|
|
Dependencies (einmalig):
|
|
- python3 (stdlib)
|
|
- git
|
|
- pip install PyYAML (optional, für sauberes Frontmatter)
|
|
- tailscale (für Tailnet-Zugriff)
|
|
|
|
Zugriff:
|
|
- Lokal: http://127.0.0.1:8765/
|
|
- Tailnet: https://<hostname>.<tailnet>.ts.net/wiki/
|
|
- API: http://127.0.0.1:8765/api/vault/{tree,graph,search,file/<path>}
|
|
|
|
EOF
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main
|
|
# ---------------------------------------------------------------------------
|
|
case "${1:-}" in
|
|
start) start_server ;;
|
|
stop) stop_server ;;
|
|
restart) stop_server; start_server ;;
|
|
status) show_status ;;
|
|
logs) tail -f "$HERMES_WIKI_LOG_DIR"/*.log 2>/dev/null || die "Keine Logs gefunden" ;;
|
|
install) ensure_dirs; require_tools; install_repo ;;
|
|
--help|-h|help|"") show_help ;;
|
|
*) die "Unbekanntes Kommando: $1 (--help für Hilfe)" ;;
|
|
esac |