Archivage : verrou exclusif par boîtier, chdir dans cron_quarantaine
This commit is contained in:
+148
-131
@@ -1,14 +1,17 @@
|
||||
<?php
|
||||
// ============================================================================
|
||||
// cron_archivage.php - Traitement périodique des archives de la flotte
|
||||
// (cf synthèse §32-36). Exécuté via cron, dans le conteneur ship2net-php :
|
||||
// docker exec ship2net-php php /var/www/cron_archivage.php
|
||||
// (cf synthèse §32-40, §43). Exécuté NATIVEMENT sur le VPS (pas dans le
|
||||
// conteneur ship2net-php, cf synthèse §38.1), de façon planifiée :
|
||||
// /usr/bin/php /var/www/cron_archivage.php
|
||||
//
|
||||
// Construction progressive, bloc par bloc :
|
||||
// Bloc 1 (ce fichier) : résolution des bateaux actifs + liste des archives
|
||||
// en attente sur chacun.
|
||||
// Blocs suivants (à venir) : récupération, vérification d'intégrité,
|
||||
// résolution de génération, chargement, confirmation.
|
||||
// Pour chaque boîtier connu (TB_Cartes avec une adresse NetBird) : liste des
|
||||
// archives en attente sur son API, récupération, vérification d'intégrité,
|
||||
// déchiffrement, affectation/MMSI (quarantaine si besoin), génération,
|
||||
// chargement, enregistrement dans TB_Archives_traitees, confirmation de
|
||||
// suppression côté CM5. Chaque boîtier est traité sous verrou exclusif
|
||||
// (Verrouiller_boitier(), synthèse §44.6) : un boîtier déjà en cours de
|
||||
// traitement par un autre processus est sauté pour ce passage.
|
||||
// ============================================================================
|
||||
|
||||
// Certains fichiers du site (fonctions_mail.php notamment) utilisent des
|
||||
@@ -315,163 +318,177 @@ function Executer_cron_archivage()
|
||||
foreach ($boitiers as $boitier)
|
||||
{
|
||||
$adresse_mac = $boitier['Adresse_mac'];
|
||||
$resultat = Lister_archives_en_attente($boitier['Adresse_netbird']);
|
||||
|
||||
if (!$resultat['ok'])
|
||||
$verrou = Verrouiller_boitier($adresse_mac);
|
||||
if (!$verrou['ok'])
|
||||
{
|
||||
echo "Boîtier {$adresse_mac} : " . $resultat['raison'] . " - ignoré pour ce cycle.\n";
|
||||
echo "Boîtier {$adresse_mac} : " . $verrou['raison'] . " - ignoré pour ce cycle.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$nb = count($resultat['archives']);
|
||||
if ($nb === 0) continue; // rien à signaler pour ce boîtier ce cycle-ci
|
||||
|
||||
// Résolu UNE SEULE FOIS par boîtier (pas par archive) : toutes les archives d'un même passage
|
||||
// partagent la même adresse MAC, et l'affectation ne change jamais en cours d'exécution du
|
||||
// script - seul un geste administratif explicite la modifie (cf synthèse §38).
|
||||
$affectation = Resoudre_affectation_active($db, $adresse_mac);
|
||||
$libelle = $affectation['existe'] ? "Bateau {$affectation['id_bateau']}" : "Boîtier {$adresse_mac} (aucune affectation active)";
|
||||
echo "{$libelle} : {$nb} archive(s) en attente.\n";
|
||||
|
||||
foreach ($resultat['archives'] as $archive)
|
||||
try
|
||||
{
|
||||
$nom = $archive['nom'];
|
||||
$resultat = Lister_archives_en_attente($boitier['Adresse_netbird']);
|
||||
|
||||
if (Archive_deja_traitee($db, $nom))
|
||||
if (!$resultat['ok'])
|
||||
{
|
||||
echo " - {$nom} : déjà traitée - confirmation de suppression seulement.\n";
|
||||
Confirmer_suppression_archive($boitier['Adresse_netbird'], $nom);
|
||||
echo "Boîtier {$adresse_mac} : " . $resultat['raison'] . " - ignoré pour ce cycle.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$recuperation = Recuperer_archive($boitier['Adresse_netbird'], $nom);
|
||||
if (!$recuperation['ok'])
|
||||
{
|
||||
echo " - {$nom} : ÉCHEC de récupération (" . $recuperation['raison'] . ") - nouvelle tentative au prochain cycle.\n";
|
||||
continue;
|
||||
}
|
||||
$nb = count($resultat['archives']);
|
||||
if ($nb === 0) continue; // rien à signaler pour ce boîtier ce cycle-ci
|
||||
|
||||
if (!Integrite_confirmee($nom, $recuperation['contenu']))
|
||||
{
|
||||
echo " - {$nom} : empreinte invalide, archive potentiellement corrompue - nouvelle tentative au prochain cycle.\n";
|
||||
continue;
|
||||
}
|
||||
// Résolu UNE SEULE FOIS par boîtier (pas par archive) : toutes les archives d'un même passage
|
||||
// partagent la même adresse MAC, et l'affectation ne change jamais en cours d'exécution du
|
||||
// script - seul un geste administratif explicite la modifie (cf synthèse §38).
|
||||
$affectation = Resoudre_affectation_active($db, $adresse_mac);
|
||||
$libelle = $affectation['existe'] ? "Bateau {$affectation['id_bateau']}" : "Boîtier {$adresse_mac} (aucune affectation active)";
|
||||
echo "{$libelle} : {$nb} archive(s) en attente.\n";
|
||||
|
||||
// Aucune affectation active (jamais affecté, ou retiré) : quarantaine directe, sans
|
||||
// déchiffrement - ni l'en-tête ni le contenu ne servent à rien sans bateau à qui l'attribuer
|
||||
// (cf synthèse §38) :
|
||||
if (!$affectation['existe'])
|
||||
foreach ($resultat['archives'] as $archive)
|
||||
{
|
||||
echo " - {$nom} : aucune affectation active pour ce boîtier - mise en quarantaine.\n";
|
||||
Mettre_en_quarantaine_sans_affectation($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac);
|
||||
continue;
|
||||
}
|
||||
$id_bateau = $affectation['id_bateau'];
|
||||
$nom = $archive['nom'];
|
||||
|
||||
$dechiffrement = Decrypter_archive($recuperation['contenu']);
|
||||
if (!$dechiffrement['ok'])
|
||||
{
|
||||
echo " - {$nom} : ÉCHEC de déchiffrement (" . $dechiffrement['raison'] . ") - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Échec de déchiffrement : " . $dechiffrement['raison']);
|
||||
continue;
|
||||
}
|
||||
|
||||
$origine_bdd = $dechiffrement['entete']['Origine_bdd'] ?? 'normale';
|
||||
$mmsi_recu = $dechiffrement['entete']['No_mmsi'] ?? null;
|
||||
$mmsi_attendu_connu = null; // reste null si No_mmsi absent de l'en-tête - sinon toujours renseigné (cf synthèse §39)
|
||||
if ($mmsi_recu !== null)
|
||||
{
|
||||
$verification_mmsi = Verifier_mmsi($db, $id_bateau, $mmsi_recu);
|
||||
$mmsi_attendu_connu = $verification_mmsi['attendu'];
|
||||
if ($verification_mmsi['statut'] === 'quarantaine')
|
||||
if (Archive_deja_traitee($db, $nom))
|
||||
{
|
||||
echo " - {$nom} : MMSI reçu ({$mmsi_recu}) différent de celui attendu ({$verification_mmsi['attendu']}) - mise en quarantaine.\n";
|
||||
Mettre_en_quarantaine_mmsi($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, $mmsi_recu, $verification_mmsi['attendu']);
|
||||
echo " - {$nom} : déjà traitée - confirmation de suppression seulement.\n";
|
||||
Confirmer_suppression_archive($boitier['Adresse_netbird'], $nom);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$version_cible = $dechiffrement['entete']['Version_soft_no_package'] ?? null;
|
||||
$generation_active = Resoudre_generation_active($db, $id_bateau);
|
||||
$nouvelle_generation = Nouvelle_generation_necessaire($origine_bdd, $generation_active);
|
||||
|
||||
echo " - {$nom} : récupérée et intègre (" . strlen($recuperation['contenu']) . " octets), origine=" . $origine_bdd . "\n";
|
||||
|
||||
$fichier_sql = Resoudre_fichier_sql($db, $version_cible);
|
||||
if ($fichier_sql === false)
|
||||
{
|
||||
echo " ÉCHEC : version logicielle '{$version_cible}' inconnue de TB_Versions - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Version logicielle '{$version_cible}' inconnue de TB_Versions", $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
$contenu_fichier_sql = @file_get_contents(REPERTOIRE_VERSIONS_SQL . "/" . $fichier_sql);
|
||||
if ($contenu_fichier_sql === false)
|
||||
{
|
||||
echo " ÉCHEC : fichier {$fichier_sql} introuvable sur le VPS - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Fichier {$fichier_sql} introuvable sur le VPS", $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($nouvelle_generation)
|
||||
{
|
||||
$zone_usine = Extraire_zone_usine($contenu_fichier_sql);
|
||||
if ($zone_usine === false)
|
||||
$recuperation = Recuperer_archive($boitier['Adresse_netbird'], $nom);
|
||||
if (!$recuperation['ok'])
|
||||
{
|
||||
echo " ÉCHEC : marqueur Factory_structure introuvable dans {$fichier_sql} - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Marqueur Factory_structure introuvable dans {$fichier_sql}", $mmsi_recu, $mmsi_attendu_connu);
|
||||
echo " - {$nom} : ÉCHEC de récupération (" . $recuperation['raison'] . ") - nouvelle tentative au prochain cycle.\n";
|
||||
continue;
|
||||
}
|
||||
// 'factory'/'restauration' est toujours un fait rapporté honnêtement par le bateau - à
|
||||
// conserver tel quel pour le diagnostic, qu'une génération existait déjà côté serveur ou
|
||||
// non. Seul 'normale' sans aucune génération existante (un bateau vraiment neuf, qui n'a
|
||||
// jamais rien envoyé) devient 'creation_initiale' (cf synthèse §37).
|
||||
if ($origine_bdd === 'factory' || $origine_bdd === 'restauration')
|
||||
|
||||
if (!Integrite_confirmee($nom, $recuperation['contenu']))
|
||||
{
|
||||
$motif = $origine_bdd;
|
||||
echo " - {$nom} : empreinte invalide, archive potentiellement corrompue - nouvelle tentative au prochain cycle.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Aucune affectation active (jamais affecté, ou retiré) : quarantaine directe, sans
|
||||
// déchiffrement - ni l'en-tête ni le contenu ne servent à rien sans bateau à qui l'attribuer
|
||||
// (cf synthèse §38) :
|
||||
if (!$affectation['existe'])
|
||||
{
|
||||
echo " - {$nom} : aucune affectation active pour ce boîtier - mise en quarantaine.\n";
|
||||
Mettre_en_quarantaine_sans_affectation($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac);
|
||||
continue;
|
||||
}
|
||||
$id_bateau = $affectation['id_bateau'];
|
||||
|
||||
$dechiffrement = Decrypter_archive($recuperation['contenu']);
|
||||
if (!$dechiffrement['ok'])
|
||||
{
|
||||
echo " - {$nom} : ÉCHEC de déchiffrement (" . $dechiffrement['raison'] . ") - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Échec de déchiffrement : " . $dechiffrement['raison']);
|
||||
continue;
|
||||
}
|
||||
|
||||
$origine_bdd = $dechiffrement['entete']['Origine_bdd'] ?? 'normale';
|
||||
$mmsi_recu = $dechiffrement['entete']['No_mmsi'] ?? null;
|
||||
$mmsi_attendu_connu = null; // reste null si No_mmsi absent de l'en-tête - sinon toujours renseigné (cf synthèse §39)
|
||||
if ($mmsi_recu !== null)
|
||||
{
|
||||
$verification_mmsi = Verifier_mmsi($db, $id_bateau, $mmsi_recu);
|
||||
$mmsi_attendu_connu = $verification_mmsi['attendu'];
|
||||
if ($verification_mmsi['statut'] === 'quarantaine')
|
||||
{
|
||||
echo " - {$nom} : MMSI reçu ({$mmsi_recu}) différent de celui attendu ({$verification_mmsi['attendu']}) - mise en quarantaine.\n";
|
||||
Mettre_en_quarantaine_mmsi($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, $mmsi_recu, $verification_mmsi['attendu']);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$version_cible = $dechiffrement['entete']['Version_soft_no_package'] ?? null;
|
||||
$generation_active = Resoudre_generation_active($db, $id_bateau);
|
||||
$nouvelle_generation = Nouvelle_generation_necessaire($origine_bdd, $generation_active);
|
||||
|
||||
echo " - {$nom} : récupérée et intègre (" . strlen($recuperation['contenu']) . " octets), origine=" . $origine_bdd . "\n";
|
||||
|
||||
$fichier_sql = Resoudre_fichier_sql($db, $version_cible);
|
||||
if ($fichier_sql === false)
|
||||
{
|
||||
echo " ÉCHEC : version logicielle '{$version_cible}' inconnue de TB_Versions - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Version logicielle '{$version_cible}' inconnue de TB_Versions", $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
$contenu_fichier_sql = @file_get_contents(REPERTOIRE_VERSIONS_SQL . "/" . $fichier_sql);
|
||||
if ($contenu_fichier_sql === false)
|
||||
{
|
||||
echo " ÉCHEC : fichier {$fichier_sql} introuvable sur le VPS - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Fichier {$fichier_sql} introuvable sur le VPS", $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($nouvelle_generation)
|
||||
{
|
||||
$zone_usine = Extraire_zone_usine($contenu_fichier_sql);
|
||||
if ($zone_usine === false)
|
||||
{
|
||||
echo " ÉCHEC : marqueur Factory_structure introuvable dans {$fichier_sql} - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Marqueur Factory_structure introuvable dans {$fichier_sql}", $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
// 'factory'/'restauration' est toujours un fait rapporté honnêtement par le bateau - à
|
||||
// conserver tel quel pour le diagnostic, qu'une génération existait déjà côté serveur ou
|
||||
// non. Seul 'normale' sans aucune génération existante (un bateau vraiment neuf, qui n'a
|
||||
// jamais rien envoyé) devient 'creation_initiale' (cf synthèse §37).
|
||||
if ($origine_bdd === 'factory' || $origine_bdd === 'restauration')
|
||||
{
|
||||
$motif = $origine_bdd;
|
||||
}
|
||||
else
|
||||
{
|
||||
$motif = 'creation_initiale';
|
||||
}
|
||||
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine);
|
||||
if (!$resultat_generation['ok'])
|
||||
{
|
||||
echo " ÉCHEC de création de génération : " . $resultat_generation['raison'] . " - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Échec de création de génération : " . $resultat_generation['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
$nom_base_cible = $resultat_generation['nom_base'];
|
||||
echo " Nouvelle génération créée : {$nom_base_cible} (motif={$motif}).\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$motif = 'creation_initiale';
|
||||
$nom_base_cible = $generation_active['nom_base'];
|
||||
echo " Génération existante : {$nom_base_cible}.\n";
|
||||
// Bloc suivant : rejeu des segments incrémentaux si la version a changé,
|
||||
// via Extraire_segments_incrementaux() + exécution (même mécanique que Creer_generation).
|
||||
}
|
||||
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine);
|
||||
if (!$resultat_generation['ok'])
|
||||
$chargement = Charger_contenu_archive($nom_base_cible, $dechiffrement['sql']);
|
||||
if (!$chargement['ok'])
|
||||
{
|
||||
echo " ÉCHEC de création de génération : " . $resultat_generation['raison'] . " - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Échec de création de génération : " . $resultat_generation['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
||||
echo " ÉCHEC de chargement dans {$nom_base_cible} : " . $chargement['raison'] . " - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Échec de chargement dans {$nom_base_cible} : " . $chargement['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
$nom_base_cible = $resultat_generation['nom_base'];
|
||||
echo " Nouvelle génération créée : {$nom_base_cible} (motif={$motif}).\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$nom_base_cible = $generation_active['nom_base'];
|
||||
echo " Génération existante : {$nom_base_cible}.\n";
|
||||
// Bloc suivant : rejeu des segments incrémentaux si la version a changé,
|
||||
// via Extraire_segments_incrementaux() + exécution (même mécanique que Creer_generation).
|
||||
}
|
||||
$chargement = Charger_contenu_archive($nom_base_cible, $dechiffrement['sql']);
|
||||
if (!$chargement['ok'])
|
||||
{
|
||||
echo " ÉCHEC de chargement dans {$nom_base_cible} : " . $chargement['raison'] . " - rejetée.\n";
|
||||
Rejeter_archive($db, $boitier['Adresse_netbird'], $nom, $recuperation['contenu'], $adresse_mac, $id_bateau, "Échec de chargement dans {$nom_base_cible} : " . $chargement['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
||||
continue;
|
||||
}
|
||||
echo " Contenu chargé dans {$nom_base_cible}.\n";
|
||||
echo " Contenu chargé dans {$nom_base_cible}.\n";
|
||||
|
||||
// Résolution de la vraie Cle_primaire de la génération (celle juste créée, ou l'existante) :
|
||||
$generation_pour_enregistrement = Resoudre_generation_active($db, $id_bateau);
|
||||
Enregistrer_archive_traitee($db, $nom, $adresse_mac, $id_bateau, $generation_pour_enregistrement['cle'], 'traitee', $mmsi_recu, $mmsi_attendu_connu);
|
||||
// Résolution de la vraie Cle_primaire de la génération (celle juste créée, ou l'existante) :
|
||||
$generation_pour_enregistrement = Resoudre_generation_active($db, $id_bateau);
|
||||
Enregistrer_archive_traitee($db, $nom, $adresse_mac, $id_bateau, $generation_pour_enregistrement['cle'], 'traitee', $mmsi_recu, $mmsi_attendu_connu);
|
||||
|
||||
if (Confirmer_suppression_archive($boitier['Adresse_netbird'], $nom))
|
||||
{
|
||||
echo " Archive confirmée et supprimée côté CM5.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo " AVERTISSEMENT : confirmation de suppression échouée (le fichier restera côté CM5, sans conséquence - cf synthèse §32.5).\n";
|
||||
if (Confirmer_suppression_archive($boitier['Adresse_netbird'], $nom))
|
||||
{
|
||||
echo " Archive confirmée et supprimée côté CM5.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo " AVERTISSEMENT : confirmation de suppression échouée (le fichier restera côté CM5, sans conséquence - cf synthèse §32.5).\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Liberer_boitier($verrou['poignee']);
|
||||
}
|
||||
}
|
||||
|
||||
Fermeture_bdd();
|
||||
|
||||
Reference in New Issue
Block a user