From f8e856ed7c76fd4175ccde46b2485fb6ab04751b Mon Sep 17 00:00:00 2001 From: nathaninline Date: Sat, 25 Jul 2026 13:29:33 +0200 Subject: [PATCH] acces distant : remplacer un worker de tunnel issu d'une autre copie de l'app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le worker est detache expres pour survivre a la fermeture de Jean.app : un worker lance par une ancienne copie (translocatee ou version precedente) continue donc de servir l'UI distante avec du code perime — l'alerte App Translocation s'affichait sur app.ajean.link alors que l'app locale tournait bien depuis /Applications. Le fichier PID porte desormais le binaire d'origine en 2e ligne ; au demarrage, un worker dont le binaire differe du notre est redemarre. --- internal/jean/cli_app.go | 12 +++++++++- internal/jean/relay_link.go | 45 ++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/internal/jean/cli_app.go b/internal/jean/cli_app.go index cedd36b..35948e7 100644 --- a/internal/jean/cli_app.go +++ b/internal/jean/cli_app.go @@ -47,7 +47,17 @@ func cmdApp(args []string) error { // fait : sans ça le token reste enregistré et le panneau affiche « service // arrêté » à chaque démarrage de l'app. go func() { - if readLinkToken() != "" && !linkServiceActive() { + if readLinkToken() == "" { + return + } + // Worker rescapé d'une AUTRE copie de l'app (ancienne version, copie + // translocatée…) : il tourne toujours — le tunnel est détaché exprès — et + // continue de servir l'UI distante avec du code périmé. On le remplace. + if linkWorkerIsStale() { + _ = linkServiceCtl("restart") + return + } + if !linkServiceActive() { _ = linkServiceCtl("start") } }() diff --git a/internal/jean/relay_link.go b/internal/jean/relay_link.go index f3dbfbc..b141983 100644 --- a/internal/jean/relay_link.go +++ b/internal/jean/relay_link.go @@ -319,6 +319,41 @@ func linkServiceActive() bool { return strings.TrimSpace(string(out)) == "active" } +// linkUserExe renvoie le binaire qui a lancé le worker de lien en cours (2e ligne +// du fichier PID), "" si inconnu. Sert à repérer un worker rescapé d'une ANCIENNE +// copie de l'app : le tunnel étant détaché exprès pour survivre à la fermeture de +// Jean.app, un worker lancé depuis une copie translocatée (ou simplement une +// version précédente) continue de servir l'UI distante avec du code périmé — +// symptôme vécu : l'alerte App Translocation visible sur app.ajean.link alors que +// l'app locale, elle, tourne bien depuis /Applications. +func linkUserExe() string { + b, err := os.ReadFile(linkPIDPath()) + if err != nil { + return "" + } + lines := strings.SplitN(strings.TrimSpace(string(b)), "\n", 2) + if len(lines) < 2 { + return "" + } + return strings.TrimSpace(lines[1]) +} + +// linkWorkerIsStale : un worker tourne, mais depuis un autre binaire que nous. +func linkWorkerIsStale() bool { + if runtime.GOOS == "linux" || linkUserPID() == 0 { + return false + } + exe, err := os.Executable() + if err != nil { + return false + } + if p, err := filepath.EvalSymlinks(exe); err == nil { + exe = p + } + running := linkUserExe() + return running != "" && running != exe +} + // linkUserPID renvoie le PID du worker de lien s'il tourne vraiment, 0 sinon // (fichier absent, illisible, ou process mort → on nettoie le fichier obsolète). func linkUserPID() int { @@ -326,6 +361,9 @@ func linkUserPID() int { if err != nil { return 0 } + if i := strings.IndexByte(string(b), '\n'); i >= 0 { + b = b[:i] + } pid, _ := strconv.Atoi(strings.TrimSpace(string(b))) if pid <= 0 || !pidAlive(pid) { return 0 @@ -361,6 +399,9 @@ func linkUserSvcCtl(action string) error { if err != nil { return err } + if p, err := filepath.EvalSymlinks(self); err == nil { + self = p // même forme que la comparaison de linkWorkerIsStale + } if err := os.MkdirAll(JeanHome(), 0o755); err != nil { return err } @@ -376,7 +417,9 @@ func linkUserSvcCtl(action string) error { return fmt.Errorf("démarrage de « jean link serve »: %w", err) } pid := cmd.Process.Pid - if err := os.WriteFile(linkPIDPath(), []byte(strconv.Itoa(pid)), 0o644); err != nil { + // PID + binaire d'origine : la 2e ligne permet de détecter plus tard un worker + // rescapé d'une ancienne copie de l'app (voir linkWorkerIsStale). + if err := os.WriteFile(linkPIDPath(), []byte(strconv.Itoa(pid)+"\n"+self+"\n"), 0o644); err != nil { return fmt.Errorf("écriture du PID: %w", err) } _ = cmd.Process.Release()