diff --git a/nc-connector-normalize.php b/nc-connector-normalize.php new file mode 100644 index 0000000..1391d9a --- /dev/null +++ b/nc-connector-normalize.php @@ -0,0 +1,149 @@ +#!/usr/bin/env php +\n"); + exit(1); +} + +$id = (int)$argv[1]; +$pluginRoot = __DIR__; +$piwigoRoot = dirname(__DIR__, 2); +$dbConfig = $piwigoRoot.'/local/config/database.inc.php'; +$configPath = '/etc/bratonien-tools/nc-connector/connection-'.$id.'.conf'; +$newState = '/var/lib/bratonien-tools/nc-connector/connection-'.$id; +$servicePath = '/etc/systemd/system/bratonien-nc-connector.service'; +$timer = 'bratonien-nc-connector.timer'; +$service = 'bratonien-nc-connector.service'; + +function normalize_run(array $command, $allowFailure = false) +{ + $spec = array(0=>array('file','/dev/null','r'), 1=>array('pipe','w'), 2=>array('pipe','w')); + $process = proc_open($command, $spec, $pipes); + if (!is_resource($process)) throw new RuntimeException('Prozess konnte nicht gestartet werden.'); + $stdout = stream_get_contents($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[1]); fclose($pipes[2]); + $exit = proc_close($process); + if ($exit !== 0 && !$allowFailure) + { + $detail = trim($stderr) !== '' ? trim($stderr) : trim($stdout); + throw new RuntimeException('Befehl fehlgeschlagen ('.$exit.'): '.implode(' ', $command).($detail !== '' ? "\n".$detail : '')); + } + return array('exit'=>$exit, 'stdout'=>$stdout, 'stderr'=>$stderr); +} + +function remove_tree($path) +{ + if (!is_dir($path)) return; + $items = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($items as $item) + { + if ($item->isDir()) @rmdir($item->getPathname()); else @unlink($item->getPathname()); + } + @rmdir($path); +} + +try +{ + $conf = array(); + $prefixeTable = 'piwigo_'; + if (!is_readable($dbConfig)) throw new RuntimeException('Piwigo-Datenbankkonfiguration nicht lesbar.'); + require $dbConfig; + $db = new mysqli($conf['db_host'], $conf['db_user'], $conf['db_password'], $conf['db_base']); + if ($db->connect_errno) throw new RuntimeException('Piwigo-Datenbank nicht erreichbar: '.$db->connect_error); + $db->set_charset('utf8mb4'); + $table = $prefixeTable.'bratonien_tools_nc_connections'; + $result = $db->query("SELECT id, enabled, takeover_state, config_json FROM `".$table."` WHERE id=".$id." LIMIT 1"); + if (!$result || !$result->num_rows) throw new RuntimeException('Connector-Verbindung #'.$id.' wurde nicht gefunden.'); + $row = $result->fetch_assoc(); + if ((int)$row['enabled'] !== 1 || (string)$row['takeover_state'] !== 'active') throw new RuntimeException('Die Verbindung muss aktiv sein.'); + $config = json_decode((string)$row['config_json'], true); + if (!is_array($config)) throw new RuntimeException('Connector-Konfiguration ist ungueltig.'); + $oldState = rtrim((string)($config['state_dir'] ?? ''), '/'); + if ($oldState === '') throw new RuntimeException('Bisheriger State-Pfad fehlt.'); + if ($oldState === $newState) + { + echo "Verbindung #".$id." verwendet bereits den nativen State-Pfad.\n"; + exit(0); + } + if (!is_readable($configPath)) throw new RuntimeException('Aktive Runtime-Konfiguration fehlt: '.$configPath); + + echo "Stoppe Connector-Timer...\n"; + normalize_run(array('systemctl','stop',$timer)); + $deadline = time() + 120; + while (normalize_run(array('systemctl','is-active','--quiet',$service), true)['exit'] === 0) + { + if (time() >= $deadline) throw new RuntimeException('Laufender Connector-Lauf wurde nach 120 Sekunden nicht beendet.'); + sleep(2); + } + + if (!is_dir(dirname($newState)) && !mkdir(dirname($newState), 0750, true)) throw new RuntimeException('Neues State-Wurzelverzeichnis konnte nicht angelegt werden.'); + if (!is_dir($newState) && !mkdir($newState, 0750, true)) throw new RuntimeException('Neues State-Verzeichnis konnte nicht angelegt werden.'); + if (is_dir($oldState)) normalize_run(array('cp','-a',$oldState.'/.',$newState.'/')); + chmod($newState, 0750); + + $originalConfig = file_get_contents($configPath); + if (!is_string($originalConfig)) throw new RuntimeException('Runtime-Konfiguration konnte nicht gelesen werden.'); + $newStatus = $newState.'/connector-status.json'; + $updatedConfig = preg_replace('/^STATE_DIR=.*$/m', 'STATE_DIR='.$newState, $originalConfig, 1); + $updatedConfig = preg_replace('/^STATUS_FILE=.*$/m', 'STATUS_FILE='.$newStatus, $updatedConfig, 1); + if (!is_string($updatedConfig) || $updatedConfig === $originalConfig) throw new RuntimeException('Runtime-Konfiguration konnte nicht auf nativen State umgestellt werden.'); + file_put_contents($configPath, $updatedConfig, LOCK_EX); + chmod($configPath, 0600); + + echo "Teste Plugin-Runtime mit neuem State...\n"; + $test = normalize_run(array('env','PIWIGO_CONFIG='.$configPath,'bash',$pluginRoot.'/runtime/sync.sh'), true); + if ($test['exit'] !== 0) + { + file_put_contents($configPath, $originalConfig, LOCK_EX); + remove_tree($newState); + normalize_run(array('systemctl','start',$timer), true); + $detail = trim($test['stderr']) !== '' ? trim($test['stderr']) : trim($test['stdout']); + throw new RuntimeException('Normalisierung abgebrochen; alter Zustand wiederhergestellt'.($detail !== '' ? ': '.$detail : '.')); + } + + $serviceContent = "[Unit]\nDescription=Bratonien NC Connector Sync\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/env bash ".$pluginRoot."/runtime/run-all.sh\n\n"; + file_put_contents($servicePath, $serviceContent, LOCK_EX); + chmod($servicePath, 0644); + + $config['state_dir'] = $newState; + $config['status_file'] = $newStatus; + $config['origin'] = 'native'; + $config['runtime'] = array('mode'=>'plugin-runtime', 'config'=>$configPath); + if (isset($config['takeover']) && is_array($config['takeover'])) $config['takeover']['runtime'] = 'plugin-runtime'; + $json = json_encode($config, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $jsonEsc = $db->real_escape_string((string)$json); + $nowEsc = $db->real_escape_string(date('Y-m-d H:i:s')); + if (!$db->query("UPDATE `".$table."` SET config_json='".$jsonEsc."', updated='".$nowEsc."' WHERE id=".$id)) throw new RuntimeException('Connector-Datenbankstatus konnte nicht aktualisiert werden: '.$db->error); + + normalize_run(array('systemctl','daemon-reload')); + normalize_run(array('systemctl','enable','--now',$timer)); + + if ($oldState !== '/var/lib' && $oldState !== '/' && strpos($oldState, '/var/lib/') === 0) + { + remove_tree($oldState); + } + + echo "Normalisierung erfolgreich.\n"; + echo "State: ".$newState."\n"; + echo "Service: gemeinsamer Multi-Connection-Runner aus Bratonien Tools.\n"; +} +catch (Throwable $e) +{ + fwrite(STDERR, $e->getMessage()."\n"); + exit(1); +}