sync_one : hash uniquement l'entrée cliquée, pas toutes celles du même numéro
Bug : sur un manifest avec deux entrées partageant le même numéro de version (channels multiples — ex proserve-firefighter-1.5.4.32.zip ET proserve-full- 1.5.4.32.zip, deux builds distincts pour firefighter vs full), cliquer le bouton « 🔁 Hash » d'une ligne déclenchait le hash des DEUX ZIPs dans la même requête HTTP. Résultat 2 × 14 Go = 28 Go dans une seule requête, ce qui dépasse le timeout front d'OVH mutualisé (hard-limit invisible côté PHP même avec set_time_limit(0)) → 500 Internal Server Error. C'est pour ça que « des hashs de la même taille passaient sans problème avant » : c'est le cas 28 Go des DEUX ZIPs en une requête qui est nouveau (depuis l'introduction des channels), pas la taille du single 14 Go qui passait déjà. Fix : nouveau paramètre $onlyEntryId sur SignManifest::run(). Prend le pas sur $onlyVersion. L'admin action sync_one passe l'entryId (unique par ligne, généré par generate_entry_id()) au lieu du numéro de version. Une ligne cliquée = un ZIP hashé, point. Le bouton « 🔁 Sync (all versions) » (action sync_versions) continue de tout hasher — c'est ce que l'opérateur demande explicitement. Rétro-compat : si $onlyEntryId est null (CLI, cron, anciens callers), $onlyVersion filtre comme avant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -671,11 +671,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
require_once "$root/tools/SignManifest.php";
|
require_once "$root/tools/SignManifest.php";
|
||||||
$signer = new \PSLauncher\Tools\SignManifest($root);
|
$signer = new \PSLauncher\Tools\SignManifest($root);
|
||||||
$force = !empty($_POST['force']);
|
$force = !empty($_POST['force']);
|
||||||
// SignManifest::run filtre par numéro de version ; en cas d'entries
|
// Filtre par entryId (pas par numéro de version). Sinon, quand deux
|
||||||
// de même version sur des channels différents, le hash sera recalculé
|
// entrées partagent le même numéro (channels firefighter vs full sur
|
||||||
// pour toutes celles qui matchent (chacune pointe sur son propre ZIP,
|
// 1.5.4.32 p.ex.), les DEUX ZIPs sont hashés dans la même requête HTTP
|
||||||
// donc le résultat est correct, juste un peu plus de boulot).
|
// → 2 × 14 Go = risque de dépasser le timeout front OVH sur mutualisé.
|
||||||
$result = $signer->run('versions', $force, $version);
|
$result = $signer->run('versions', $force, null, $entryId);
|
||||||
$forceLabel = $force ? ' [FORCE]' : '';
|
$forceLabel = $force ? ' [FORCE]' : '';
|
||||||
$message = "Hash de v{$version}{$forceLabel} :\n" . implode("\n", $result['log']);
|
$message = "Hash de v{$version}{$forceLabel} :\n" . implode("\n", $result['log']);
|
||||||
if (!$result['ok']) $messageType = 'error';
|
if (!$result['ok']) $messageType = 'error';
|
||||||
|
|||||||
@@ -139,10 +139,19 @@ final class SignManifest
|
|||||||
* @param bool $force Si true, ignore le cache et recalcule tous les hashs
|
* @param bool $force Si true, ignore le cache et recalcule tous les hashs
|
||||||
* @param ?string $onlyVersion Si non null, ne touche QUE cette version dans la section
|
* @param ?string $onlyVersion Si non null, ne touche QUE cette version dans la section
|
||||||
* versions[] (les autres restent inchangées). Le scope 'launcher'
|
* versions[] (les autres restent inchangées). Le scope 'launcher'
|
||||||
* est ignoré dans ce cas.
|
* est ignoré dans ce cas. ATTENTION : si plusieurs entrées
|
||||||
|
* partagent le même numéro de version (channels firefighter
|
||||||
|
* vs full sur 1.5.4.32 p.ex.), TOUTES sont hashées — d'où
|
||||||
|
* $onlyEntryId ci-dessous pour cibler une seule ligne.
|
||||||
|
* @param ?string $onlyEntryId Si non null, ne touche QUE l'entrée avec cet id (généré par
|
||||||
|
* generate_entry_id() au backoffice). Prend le pas sur
|
||||||
|
* $onlyVersion. Utilisé par le bouton « 🔁 Hash » d'une
|
||||||
|
* ligne isolée pour éviter de re-hasher les autres channels
|
||||||
|
* qui partagent le même numéro de version (2 × 14 Go dans une
|
||||||
|
* requête HTTP → risque de timeout front OVH).
|
||||||
* @return array{ok:bool, log:string[]}
|
* @return array{ok:bool, log:string[]}
|
||||||
*/
|
*/
|
||||||
public function run(string $scope = 'all', bool $force = false, ?string $onlyVersion = null): array
|
public function run(string $scope = 'all', bool $force = false, ?string $onlyVersion = null, ?string $onlyEntryId = null): array
|
||||||
{
|
{
|
||||||
// Sur OVH mutualisé, un SHA-256 d'un ZIP de 14 Go peut prendre 5-10 min via
|
// Sur OVH mutualisé, un SHA-256 d'un ZIP de 14 Go peut prendre 5-10 min via
|
||||||
// le SAN partagé. Le max_execution_time par défaut (30-60s) tue le process
|
// le SAN partagé. Le max_execution_time par défaut (30-60s) tue le process
|
||||||
@@ -166,7 +175,8 @@ final class SignManifest
|
|||||||
$ts = date('Y-m-d H:i:s');
|
$ts = date('Y-m-d H:i:s');
|
||||||
@file_put_contents($errorLogPath,
|
@file_put_contents($errorLogPath,
|
||||||
"[{$ts}] --- SignManifest::run(scope={$scope}, force=" . ($force?'1':'0')
|
"[{$ts}] --- SignManifest::run(scope={$scope}, force=" . ($force?'1':'0')
|
||||||
. ", onlyVersion=" . ($onlyVersion ?? 'null') . ") ---\n",
|
. ", onlyVersion=" . ($onlyVersion ?? 'null')
|
||||||
|
. ", onlyEntryId=" . ($onlyEntryId ?? 'null') . ") ---\n",
|
||||||
FILE_APPEND);
|
FILE_APPEND);
|
||||||
// Fatal errors → capturés par un shutdown handler. Sinon Apache renvoie
|
// Fatal errors → capturés par un shutdown handler. Sinon Apache renvoie
|
||||||
// juste 500 sans qu'on sache ce qui a claqué.
|
// juste 500 sans qu'on sache ce qui a claqué.
|
||||||
@@ -193,9 +203,9 @@ final class SignManifest
|
|||||||
|
|
||||||
$doVersions = ($scope === 'all' || $scope === 'versions');
|
$doVersions = ($scope === 'all' || $scope === 'versions');
|
||||||
$doLauncher = ($scope === 'all' || $scope === 'launcher');
|
$doLauncher = ($scope === 'all' || $scope === 'launcher');
|
||||||
if ($onlyVersion !== null) {
|
if ($onlyVersion !== null || $onlyEntryId !== null) {
|
||||||
// Mode "hash une seule version" : on ne touche pas au launcher,
|
// Mode "hash une seule entrée / version" : on ne touche pas au launcher,
|
||||||
// et on ne hash que la version demandée dans la section versions[].
|
// et on ne hash que ce qui correspond au filtre demandé dans versions[].
|
||||||
$doLauncher = false;
|
$doLauncher = false;
|
||||||
$doVersions = true;
|
$doVersions = true;
|
||||||
}
|
}
|
||||||
@@ -207,7 +217,15 @@ final class SignManifest
|
|||||||
$hashedVersions = [];
|
$hashedVersions = [];
|
||||||
if ($doVersions) foreach ($manifest['versions'] as &$v) {
|
if ($doVersions) foreach ($manifest['versions'] as &$v) {
|
||||||
$version = $v['version'] ?? '?';
|
$version = $v['version'] ?? '?';
|
||||||
if ($onlyVersion !== null && $version !== $onlyVersion) {
|
$entryId = (string)($v['id'] ?? '');
|
||||||
|
// Filtre par id d'entrée prioritaire sur filtre par version (cas
|
||||||
|
// channels multiples partageant un numéro de version identique —
|
||||||
|
// ex : proserve-firefighter-1.5.4.32 vs proserve-full-1.5.4.32).
|
||||||
|
// Sinon, filtre par numéro de version (rétro-compat).
|
||||||
|
if ($onlyEntryId !== null && $entryId !== $onlyEntryId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($onlyEntryId === null && $onlyVersion !== null && $version !== $onlyVersion) {
|
||||||
continue; // skip silently les autres versions
|
continue; // skip silently les autres versions
|
||||||
}
|
}
|
||||||
$url = $v['download']['url'] ?? '';
|
$url = $v['download']['url'] ?? '';
|
||||||
|
|||||||
Reference in New Issue
Block a user