From 86e31ada3450a90f71ae7c963770b29703e48be3 Mon Sep 17 00:00:00 2001 From: Dom Date: Wed, 1 Jul 2026 23:48:40 +0200 Subject: [PATCH] =?UTF-8?q?fix(installer):=20upgrade-safe=20voie=201=20?= =?UTF-8?q?=E2=80=94=20preserve=20identite+config,=20tue=20Lea=20avant=20c?= =?UTF-8?q?opie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Poste clinique (Emilie) = install existante + Lea vive + config reelle (machine_id lea-4zbgwxty, vrai serveur). L'installeur regenerait config.txt + machine_id a chaque install => l'upgrade ecrasait l'identite fleet et forcait la resaisie du serveur/token (Gap 1), et ne fermait pas la Lea en cours => DLL python-embed verrouillees (Gap 2). Voie 1 : - FindExistingInstallDir + LoadExistingConfig : detecte l'install, pre-remplit le wizard avec la VRAIE conf et memorise le machine_id. - CurStepChanged(ssInstall) : preserve le machine_id existant (pas de regen). - PrepareToInstall : tue Lea via le PID du lock avant la copie (libere les DLL). Valide sur .11 (upgrade silencieux sur etat Emilie simule) : machine_id + serveur preserves, fausse Lea tuee, lock retire, 4 fixes presents, exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) --- deploy/installer/Lea.iss | 103 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/deploy/installer/Lea.iss b/deploy/installer/Lea.iss index 8ea15091a..a2ab2d63d 100644 --- a/deploy/installer/Lea.iss +++ b/deploy/installer/Lea.iss @@ -182,6 +182,7 @@ var TokenPage: TInputQueryWizardPage; MachineIdValue: string; ConfigFilePath: string; + ExistingMachineId: string; // -------------------------------------------------------------------- // Helper : ajoute des guillemets autour d'une chaine @@ -267,6 +268,72 @@ end; // -------------------------------------------------------------------- procedure LoadConfigFromCommandLine(); forward; +// -------------------------------------------------------------------- +// UPGRADE — trouve le dossier d'une install Lea existante (config.txt present) +// -------------------------------------------------------------------- +function FindExistingInstallDir(): string; +var + Candidates: array[0..1] of string; + I: Integer; +begin + Result := ''; + Candidates[0] := ExpandConstant('{localappdata}\Programs\Lea'); + Candidates[1] := ExpandConstant('{autopf}\Lea'); + for I := 0 to 1 do + begin + if FileExists(Candidates[I] + '\config.txt') then + begin + Result := Candidates[I]; + Exit; + end; + end; +end; + +// -------------------------------------------------------------------- +// UPGRADE — lit le config.txt existant : pre-remplit le wizard avec la +// VRAIE conf du poste (serveur/token/user) et MEMORISE le machine_id pour +// le PRESERVER (ne pas regenerer une nouvelle identite fleet). +// -------------------------------------------------------------------- +procedure LoadExistingConfig(); +var + Dir, ConfPath: string; + Lines: TArrayOfString; + I, EqPos: Integer; + Line, Key, Value: string; +begin + ExistingMachineId := ''; + Dir := FindExistingInstallDir(); + if Dir = '' then Exit; // install neuve -> comportement par defaut + + ConfPath := Dir + '\config.txt'; + if LoadStringsFromFile(ConfPath, Lines) then + begin + for I := 0 to GetArrayLength(Lines) - 1 do + begin + Line := Trim(Lines[I]); + if (Length(Line) = 0) or (Line[1] = '#') then Continue; + EqPos := Pos('=', Line); + if EqPos = 0 then Continue; + Key := Trim(Copy(Line, 1, EqPos - 1)); + Value := Trim(Copy(Line, EqPos + 1, Length(Line))); + + if Key = 'RPA_SERVER_URL' then TokenPage.Values[0] := Value + else if Key = 'RPA_API_TOKEN' then TokenPage.Values[1] := Value + else if Key = 'RPA_USER_NAME' then EnrollmentPage.Values[0] := Value + else if Key = 'RPA_USER_EMAIL' then EnrollmentPage.Values[1] := Value + else if Key = 'RPA_USER_ID' then EnrollmentPage.Values[2] := Value + else if Key = 'RPA_MACHINE_ID' then ExistingMachineId := Value; + end; + end; + + // Fallback : machine_id.txt si absent du config.txt + if (ExistingMachineId = '') and FileExists(Dir + '\machine_id.txt') then + begin + if LoadStringsFromFile(Dir + '\machine_id.txt', Lines) and (GetArrayLength(Lines) > 0) then + ExistingMachineId := Trim(Lines[0]); + end; +end; + // -------------------------------------------------------------------- // Initialisation : cree les pages custom d'enrollment // -------------------------------------------------------------------- @@ -301,7 +368,11 @@ begin TokenPage.Values[0] := SERVER_URL_DEFAULT; TokenPage.Values[1] := DEFAULT_TOKEN; - // Si un fichier /CONFIG= est passe en ligne de commande, pre-remplir + // UPGRADE : si une install existe, pre-remplir avec SA config (pas les + // defauts) et memoriser son machine_id pour le preserver. + LoadExistingConfig(); + + // Si un fichier /CONFIG= est passe en ligne de commande, pre-remplir (prioritaire) LoadConfigFromCommandLine(); end; @@ -508,6 +579,29 @@ begin DeleteFile(PsFile); end; +// -------------------------------------------------------------------- +// UPGRADE — AVANT la copie des fichiers : tuer une Lea en cours (via le +// PID du lock) pour liberer les DLL de python-embed. Evite une install +// partielle / "reboot required". Ne tue QUE le PID du lock (jamais tous +// les pythonw du poste). +// -------------------------------------------------------------------- +function PrepareToInstall(var NeedsRestart: Boolean): String; +var + LockPath: string; + Lines: TArrayOfString; + ResultCode: Integer; +begin + Result := ''; + LockPath := ExpandConstant('{app}\lea_agent.lock'); + if FileExists(LockPath) then + begin + if LoadStringsFromFile(LockPath, Lines) and (GetArrayLength(Lines) > 0) then + Exec('taskkill.exe', '/F /PID ' + Trim(Lines[0]), '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + DeleteFile(LockPath); + Sleep(1500); + end; +end; + // -------------------------------------------------------------------- // Hook : actions apres copie des fichiers (ssPostInstall) // -------------------------------------------------------------------- @@ -515,8 +609,11 @@ procedure CurStepChanged(CurStep: TSetupStep); begin if CurStep = ssInstall then begin - // Genere le machine_id AVANT la copie des fichiers - MachineIdValue := GenerateMachineId(); + // UPGRADE : preserver l'identite existante ; sinon en generer une neuve. + if ExistingMachineId <> '' then + MachineIdValue := ExistingMachineId + else + MachineIdValue := GenerateMachineId(); end; if CurStep = ssPostInstall then