mirror of
https://github.com/Terranom674/Piwigo_Bratonien_Tools.git
synced 2026-09-19 21:04:33 +00:00
Compare commits
11 Commits
78f34fceb9
...
ceea3b5483
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ceea3b5483 | ||
|
|
11c136439d | ||
|
|
953bc92f1b | ||
|
|
7106765be6 | ||
|
|
e0efb72a98 | ||
|
|
1ae9f2acc4 | ||
|
|
c819861c91 | ||
|
|
7fdb022126 | ||
|
|
73de6a7a82 | ||
|
|
00ae99e2a0 | ||
|
|
85fa5aeeb5 |
@@ -185,7 +185,7 @@ function bratonien_tools_start_webdav_warmup_mode($mode, $message)
|
||||
'queued',
|
||||
$mode === 'rebuild'
|
||||
? 'Cache-Rebuild wurde angefordert. Der Worker wartet auf den Start und gleicht danach Shadow-Tree und eigenen Index ab.'
|
||||
: 'Quellenprüfung wurde angefordert. Der Worker wartet auf den Start und gleicht danach Shadow-Tree und eigenen Index ab.',
|
||||
: 'Cache-Abgleich wurde angefordert. Bereits erfolgreich abgeschlossene Stufen bleiben erhalten; geladen werden nur Quellen mit fehlender Stufe 1 oder Stufe 2.',
|
||||
array('mode'=>$mode, 'run_id'=>$run_id)
|
||||
);
|
||||
}
|
||||
@@ -212,7 +212,7 @@ function bratonien_tools_start_webdav_warmup_manual()
|
||||
{
|
||||
return bratonien_tools_start_webdav_warmup_mode(
|
||||
'manual',
|
||||
'WebDAV-Worker: Shadow-Tree wird mit dem eigenen Index auf neue oder geänderte Quellen abgeglichen.'
|
||||
'WebDAV-Worker: Shadow-Tree und Worker-Index werden abgeglichen; vollständig erledigte Quellen werden nicht aus Nextcloud geladen.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -240,10 +240,13 @@ function bratonien_tools_has_local_cache_sources()
|
||||
|
||||
function bratonien_tools_start_combined_image_cache_build()
|
||||
{
|
||||
// Der WebDAV-Status muss vor jedem asynchronen Start auf queued wechseln.
|
||||
// Sonst kann die Admin-Seite den complete-Status des vorigen Laufs sofort
|
||||
// als Ergebnis des neuen Klicks interpretieren und die Abfrage beenden.
|
||||
$webdav = bratonien_tools_start_webdav_cache_rebuild();
|
||||
// Der normale "Piwigo-Bildcache aufbauen"-Lauf ist immer inkrementell.
|
||||
// Der Worker liest zuerst ausschließlich Shadow-Tree/Mapping und seinen
|
||||
// eigenen Index. Nur Quellen, denen laut Index Stufe 1 oder Stufe 2 fehlt,
|
||||
// dürfen anschließend aus Nextcloud geladen werden. Ein kompletter
|
||||
// Neuaufbau entsteht nur nach einer echten Cache-Invalidierung (z.B. Cache
|
||||
// leeren), denn genau dort werden die Stage-Signaturen bewusst entfernt.
|
||||
$webdav = bratonien_tools_start_webdav_warmup_manual();
|
||||
$main = array('started'=>false, 'message'=>'');
|
||||
|
||||
if (bratonien_tools_has_local_cache_sources())
|
||||
|
||||
@@ -98,6 +98,9 @@ $webdav_pending = false;
|
||||
$webdav_latest = 0;
|
||||
$webdav_lines = array();
|
||||
$webdav_all_complete = !empty($webdav);
|
||||
$webdav_progress_total = 0;
|
||||
$webdav_progress_completed = 0;
|
||||
$webdav_source_total = 0;
|
||||
foreach ($webdav as &$status)
|
||||
{
|
||||
$state = (string)($status['state'] ?? 'idle');
|
||||
@@ -111,6 +114,36 @@ foreach ($webdav as &$status)
|
||||
$status['message'] = 'Worker wurde angefordert, hat aber innerhalb von 45 Sekunden keinen Scan gestartet.';
|
||||
}
|
||||
|
||||
if ($state === 'scan')
|
||||
{
|
||||
$selected = max(0, (int)($status['selected'] ?? 0));
|
||||
$webdav_source_total += $selected;
|
||||
$webdav_progress_total += $selected * 2;
|
||||
}
|
||||
elseif ($state === 'running')
|
||||
{
|
||||
$selected = max(0, (int)($status['selected_total'] ?? 0));
|
||||
$stage = max(1, (int)($status['stage'] ?? 1));
|
||||
$stage_completed = max(0, min($selected, (int)($status['stage_completed'] ?? 0)));
|
||||
$webdav_source_total += $selected;
|
||||
$webdav_progress_total += $selected * 2;
|
||||
$webdav_progress_completed += $stage >= 2 ? $selected + $stage_completed : $stage_completed;
|
||||
}
|
||||
elseif ($state === 'complete' || $state === 'error' || $state === 'fatal' || $state === 'preempted')
|
||||
{
|
||||
$selected = max(0, (int)($status['selected'] ?? 0));
|
||||
if ($selected > 0)
|
||||
{
|
||||
$stage1_completed = max(0, (int)($status['stage1_completed'] ?? 0));
|
||||
$stage2_completed = max(0, (int)($status['stage2_completed'] ?? 0));
|
||||
$stage1_failed = max(0, (int)($status['stage1_failed'] ?? 0));
|
||||
$stage2_failed = max(0, (int)($status['stage2_failed'] ?? 0));
|
||||
$webdav_source_total += $selected;
|
||||
$webdav_progress_total += $selected * 2;
|
||||
$webdav_progress_completed += min($selected * 2, $stage1_completed + $stage2_completed + $stage1_failed + $stage2_failed);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($state, array('queued','scan','running'), true)) $webdav_active = true;
|
||||
if ($state === 'preempted') $webdav_pending = true;
|
||||
if (in_array($state, array('error','fatal'), true)) $webdav_error = true;
|
||||
@@ -140,37 +173,53 @@ $overall = $local;
|
||||
$overall['local'] = $local;
|
||||
$overall['webdav'] = $webdav;
|
||||
$overall['updated_at'] = max($local_updated, $webdav_latest);
|
||||
$overall['source_total'] = $webdav_source_total;
|
||||
|
||||
$local_total = max(0, (int)($local['total'] ?? 0));
|
||||
$local_completed = max(0, min($local_total, (int)($local['completed'] ?? 0)));
|
||||
$combined_total = $local_total + $webdav_progress_total;
|
||||
$combined_completed = $local_completed + min($webdav_progress_total, $webdav_progress_completed);
|
||||
|
||||
if ($webdav_active)
|
||||
{
|
||||
$overall['state'] = 'running';
|
||||
$overall['total'] = 0;
|
||||
$overall['completed'] = 0;
|
||||
$overall['generated'] = 0;
|
||||
$overall['cached'] = 0;
|
||||
$overall['skipped'] = 0;
|
||||
$overall['message'] = 'Gesamtaufbau läuft. '.$local_label;
|
||||
$overall['total'] = $combined_total;
|
||||
$overall['completed'] = $combined_completed;
|
||||
$overall['generated'] = (int)($local['generated'] ?? 0);
|
||||
$overall['cached'] = (int)($local['cached'] ?? 0);
|
||||
$overall['skipped'] = (int)($local['skipped'] ?? 0);
|
||||
$overall['message'] = 'Gesamtaufbau läuft'.($webdav_source_total > 0 ? ' · '.$webdav_source_total.' WebDAV-Quellen' : '').'. '.$local_label;
|
||||
$overall['current'] = implode(' ', $webdav_lines);
|
||||
}
|
||||
elseif ($webdav_error || $local_state === 'error')
|
||||
{
|
||||
$overall['state'] = 'error';
|
||||
$overall['message'] = 'Cache-Aufbau mit Fehlern. '.$local_label;
|
||||
if ($combined_total > 0)
|
||||
{
|
||||
$overall['total'] = $combined_total;
|
||||
$overall['completed'] = $combined_completed;
|
||||
}
|
||||
$overall['message'] = 'Cache-Aufbau mit Fehlern'.($webdav_source_total > 0 ? ' · '.$webdav_source_total.' WebDAV-Quellen' : '').'. '.$local_label;
|
||||
$overall['current'] = implode(' ', $webdav_lines);
|
||||
$overall['errors'] = max(1, (int)($overall['errors'] ?? 0));
|
||||
}
|
||||
elseif ($webdav_pending)
|
||||
{
|
||||
$overall['state'] = 'queued';
|
||||
$overall['total'] = 0;
|
||||
$overall['completed'] = 0;
|
||||
$overall['message'] = 'Cache-Aufbau wartet auf priorisierte Connector-Inhalte. '.$local_label;
|
||||
$overall['total'] = $combined_total;
|
||||
$overall['completed'] = $combined_completed;
|
||||
$overall['message'] = 'Cache-Aufbau wartet auf priorisierte Connector-Inhalte'.($webdav_source_total > 0 ? ' · '.$webdav_source_total.' WebDAV-Quellen' : '').'. '.$local_label;
|
||||
$overall['current'] = implode(' ', $webdav_lines);
|
||||
}
|
||||
elseif ($webdav_all_complete && $local_state === 'complete')
|
||||
{
|
||||
$overall['state'] = 'complete';
|
||||
$overall['message'] = 'Cache-Aufbau abgeschlossen. '.$local_label;
|
||||
if ($combined_total > 0)
|
||||
{
|
||||
$overall['total'] = $combined_total;
|
||||
$overall['completed'] = $combined_total;
|
||||
}
|
||||
$overall['message'] = 'Cache-Aufbau abgeschlossen'.($webdav_source_total > 0 ? ' · '.$webdav_source_total.' WebDAV-Quellen' : '').'. '.$local_label;
|
||||
$overall['current'] = implode(' ', $webdav_lines);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/*
|
||||
Plugin Name: Bratonien Tools
|
||||
Version: 0.9.7.1.22
|
||||
Version: 0.9.7.1.27
|
||||
Description: Erweiterbare Administrationswerkzeuge fuer die Bratonien-Piwigo-Installation.
|
||||
Plugin URI: https://github.com/Terranom674/Piwigo_Bratonien_Tools
|
||||
Author: Bratonien
|
||||
|
||||
@@ -31,23 +31,28 @@ result=0
|
||||
for config in "${webdav_configs[@]}"; do
|
||||
name="$(basename "$config")"
|
||||
echo "NC Connector WebDAV: $name"
|
||||
state_dir="$(PIWIGO_CONFIG="$config" bash -c 'source "$PIWIGO_CONFIG"; printf "%s" "${STATE_DIR:-}"')"
|
||||
change_file="${state_dir%/}/webdav-sync-content-changed"
|
||||
|
||||
if env PIWIGO_CONFIG="$config" bash "$SCRIPT_DIR/sync-webdav.sh"; then
|
||||
# Ein neues Album soll nicht bis zur periodischen Einzelbildprüfung
|
||||
# warten. Direkt nach dem vollständig erfolgreichen Sync dieser
|
||||
# Verbindung darf der Warmup gezielt nur diese Verbindung prüfen.
|
||||
if [[ -f "$SCRIPT_DIR/webdav-warmup-dispatch.php" && "$name" =~ ^webdav-connection-([0-9]+)\.conf$ ]]; then
|
||||
# Nur ein tatsaechlich geaenderter Connector-Bestand darf einen
|
||||
# laufenden Cache-Rebuild priorisiert unterbrechen. Ein erfolgreicher
|
||||
# Sync ohne Aenderung ist kein neuer Inhalt.
|
||||
if [[ -f "$change_file" && -f "$SCRIPT_DIR/webdav-warmup-dispatch.php" && "$name" =~ ^webdav-connection-([0-9]+)\.conf$ ]]; then
|
||||
connection_id="${BASH_REMATCH[1]}"
|
||||
php "$SCRIPT_DIR/webdav-warmup-dispatch.php" --mode=sync --connection-id="$connection_id" || result=1
|
||||
rm -f -- "$change_file"
|
||||
else
|
||||
echo "NC Connector WebDAV: keine Inhaltsaenderung, kein priorisierter Warmup erforderlich."
|
||||
fi
|
||||
else
|
||||
result=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Einzelne neue/geänderte Bilder in bereits bekannten Alben werden nur über
|
||||
# die periodische Eingangsprüfung behandelt. Der Dispatcher liest zunächst nur
|
||||
# den Warmup-State und startet die eigentliche Prüfung erst, wenn das im Plugin
|
||||
# konfigurierte Intervall (Standard: 12 Stunden) wirklich fällig ist.
|
||||
# Einzelne neue/geänderte Bilder in bereits bekannten Alben werden weiterhin
|
||||
# über die periodische Eingangsprüfung behandelt. Der Dispatcher startet die
|
||||
# eigentliche Prüfung erst, wenn das konfigurierte Intervall fällig ist.
|
||||
if [[ "$result" -eq 0 && -f "$SCRIPT_DIR/webdav-warmup-dispatch.php" ]]; then
|
||||
php "$SCRIPT_DIR/webdav-warmup-dispatch.php" --mode=periodic || result=1
|
||||
fi
|
||||
|
||||
@@ -28,6 +28,8 @@ source "$CONFIG_FILE"
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCK_FILE="$STATE_DIR/webdav-sync.lock"
|
||||
WORKER_LOCK_FILE="$STATE_DIR/webdav-cache-warmup.lock"
|
||||
CHANGE_FILE="$STATE_DIR/webdav-sync-content-changed"
|
||||
PRIORITY_FILE="$STATE_DIR/webdav-cache-warmup-priority-sync"
|
||||
mkdir -p -- "$STATE_DIR"
|
||||
chgrp www-data -- "$STATE_DIR"
|
||||
chmod 0750 -- "$STATE_DIR"
|
||||
@@ -35,8 +37,6 @@ chmod 0750 -- "$STATE_DIR"
|
||||
# Das Connector-State-Verzeichnis bleibt fuer www-data bewusst nicht
|
||||
# beschreibbar. Die beiden gemeinsam verwendeten Lock-Dateien werden deshalb
|
||||
# vom privilegierten Connector explizit angelegt und gruppenschreibbar gemacht.
|
||||
# So kann der Piwigo-CLI-Worker vorhandene Locks oeffnen, ohne Schreibrechte
|
||||
# auf das gesamte Connector-State-Verzeichnis zu erhalten.
|
||||
touch -- "$LOCK_FILE" "$WORKER_LOCK_FILE"
|
||||
chgrp www-data -- "$LOCK_FILE" "$WORKER_LOCK_FILE"
|
||||
chmod 0660 -- "$LOCK_FILE" "$WORKER_LOCK_FILE"
|
||||
@@ -96,6 +96,11 @@ done < "$WEBDAV_ROOTS_FILE"
|
||||
|
||||
[[ ${#ROOT_ARGS[@]} -gt 0 ]] || { write_status error "Keine WebDAV-Wurzeln konfiguriert"; exit 1; }
|
||||
|
||||
OLD_MAPPING_HASH=""
|
||||
if [[ -r "$WEBDAV_MAPPING_FILE" ]]; then
|
||||
OLD_MAPPING_HASH="$(sha256sum -- "$WEBDAV_MAPPING_FILE" | awk '{print $1}')"
|
||||
fi
|
||||
|
||||
python3 "$SCRIPT_DIR/lib/build_webdav_placeholder_source.py" \
|
||||
--base-url "$WEBDAV_BASE_URL" \
|
||||
--user "$WEBDAV_USER" \
|
||||
@@ -113,6 +118,18 @@ find "$WEBDAV_SOURCE_DIR" -type f -exec chmod 0664 -- {} +
|
||||
chgrp www-data -- "$WEBDAV_MAPPING_FILE"
|
||||
chmod 0640 -- "$WEBDAV_MAPPING_FILE"
|
||||
|
||||
NEW_MAPPING_HASH="$(sha256sum -- "$WEBDAV_MAPPING_FILE" | awk '{print $1}')"
|
||||
if [[ -z "$OLD_MAPPING_HASH" || "$OLD_MAPPING_HASH" != "$NEW_MAPPING_HASH" ]]; then
|
||||
printf '%s\n' "$NEW_MAPPING_HASH" > "$CHANGE_FILE"
|
||||
chmod 0640 -- "$CHANGE_FILE"
|
||||
else
|
||||
rm -f -- "$CHANGE_FILE"
|
||||
# Eine alte Prioritaetsmarke darf einen laufenden Rebuild nicht abbrechen,
|
||||
# wenn der gerade abgeschlossene Connector-Sync keinerlei Aenderung
|
||||
# festgestellt hat.
|
||||
rm -f -- "$PRIORITY_FILE"
|
||||
fi
|
||||
|
||||
python3 "$SCRIPT_DIR/lib/shadow_tree.py" \
|
||||
--manifest "$MANIFEST" \
|
||||
--destination "$GALLERY_ROOT" \
|
||||
|
||||
@@ -23,7 +23,7 @@ $_SERVER['REQUEST_URI'] = '/';
|
||||
$_SERVER['SCRIPT_NAME'] = '/plugins/bratonien_tools/runtime/webdav-warmup-dispatch.php';
|
||||
$_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'];
|
||||
$_SERVER['QUERY_STRING'] = '';
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'Bratonien-WebDAV-Worker-Dispatcher/0.9.7.1.19';
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'Bratonien-WebDAV-Worker-Dispatcher/0.9.7.1.23';
|
||||
$_SERVER['HTTPS'] = 'off';
|
||||
|
||||
require_once(PHPWG_ROOT_PATH.'include/common.inc.php');
|
||||
@@ -35,6 +35,37 @@ if (!defined('BRATONIEN_TOOLS_PATH'))
|
||||
require_once(BRATONIEN_TOOLS_PATH.'include/nc_connector.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH.'include/webdav_warmup_settings.inc.php');
|
||||
|
||||
function bratonien_tools_webdav_dispatch_existing_status($connection_id)
|
||||
{
|
||||
if (!function_exists('bratonien_tools_webdav_warmup_status_file_for_connection')) return null;
|
||||
$file = bratonien_tools_webdav_warmup_status_file_for_connection($connection_id);
|
||||
if (!is_file($file) || !is_readable($file)) return null;
|
||||
$raw = @file_get_contents($file);
|
||||
$data = $raw !== false ? json_decode($raw, true) : null;
|
||||
return is_array($data) ? $data : null;
|
||||
}
|
||||
|
||||
function bratonien_tools_webdav_dispatch_failure_lines(array $output)
|
||||
{
|
||||
$failures = array();
|
||||
foreach ($output as $line)
|
||||
{
|
||||
$line = trim((string)$line);
|
||||
if ($line === '') continue;
|
||||
if (
|
||||
strpos($line, 'download_failed') !== false
|
||||
|| strpos($line, ' ok=0 ') !== false
|
||||
|| strpos($line, '[BRAT-WORKER] fatal ') !== false
|
||||
|| stripos($line, 'RESTORE FEHLGESCHLAGEN') !== false
|
||||
)
|
||||
{
|
||||
$failures[] = $line;
|
||||
if (count($failures) >= 8) break;
|
||||
}
|
||||
}
|
||||
return $failures;
|
||||
}
|
||||
|
||||
$mode = 'periodic';
|
||||
$wait = false;
|
||||
$connection_filter = 0;
|
||||
@@ -75,11 +106,6 @@ $result = 0;
|
||||
$started = 0;
|
||||
$matched = 0;
|
||||
|
||||
// Ein manueller Lauf wird bereits vom Admin-Handler als eigener nohup-
|
||||
// Dispatcher gestartet. Innerhalb dieses Hintergrundprozesses darf nicht noch
|
||||
// einmal ein zweiter, abgekoppelter nohup-Prozess erzeugt werden: sonst kann
|
||||
// der Dispatcher erfolgreich enden, obwohl der eigentliche Worker nie bis zum
|
||||
// Scan kommt. Manual/Rebuild laufen deshalb im Dispatcher-Prozess selbst.
|
||||
$run_inline = $wait || in_array($mode, array('manual','rebuild'), true);
|
||||
|
||||
foreach (bratonien_tools_nc_connector_connections() as $connection)
|
||||
@@ -144,15 +170,43 @@ foreach (bratonien_tools_nc_connector_connections() as $connection)
|
||||
$result = $exit;
|
||||
if (function_exists('bratonien_tools_webdav_warmup_write_status'))
|
||||
{
|
||||
$detail = $output ? implode(' ', array_slice($output, -4)) : 'Worker Exit '.$exit;
|
||||
$existing = bratonien_tools_webdav_dispatch_existing_status($connection_id);
|
||||
$failures = bratonien_tools_webdav_dispatch_failure_lines($output);
|
||||
$terminal = is_array($existing) && in_array((string)($existing['state'] ?? ''), array('error','fatal','preempted'), true);
|
||||
|
||||
if ($terminal)
|
||||
{
|
||||
$message = trim((string)($existing['message'] ?? 'WebDAV-Worker wurde mit Fehlern beendet.'));
|
||||
if ($failures)
|
||||
{
|
||||
$message .= ' Fehlerbeispiele: '.implode(' | ', $failures);
|
||||
}
|
||||
$extra = $existing;
|
||||
unset($extra['state'], $extra['message'], $extra['connection_id'], $extra['updated_at']);
|
||||
$extra['worker_exit_code'] = (int)$exit;
|
||||
$extra['dispatcher_preserved_worker_status'] = true;
|
||||
if ($failures) $extra['failure_examples'] = $failures;
|
||||
bratonien_tools_webdav_warmup_write_status(
|
||||
$connection_id,
|
||||
(string)$existing['state'],
|
||||
$message,
|
||||
$extra
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$detail = $failures
|
||||
? implode(' | ', $failures)
|
||||
: ($output ? implode(' ', array_slice($output, -8)) : 'keine Worker-Ausgabe');
|
||||
bratonien_tools_webdav_warmup_write_status(
|
||||
$connection_id,
|
||||
'error',
|
||||
'WebDAV-Worker wurde gestartet, ist aber vor erfolgreichem Abschluss beendet worden: '.$detail,
|
||||
array('mode'=>$mode)
|
||||
'WebDAV-Worker Exit '.(int)$exit.'. Ursache: '.$detail,
|
||||
array('mode'=>$mode, 'worker_exit_code'=>(int)$exit, 'failure_examples'=>$failures)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$started++;
|
||||
|
||||
Reference in New Issue
Block a user