acces distant : remplacer un worker de tunnel issu d'une autre copie de l'app

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.
This commit is contained in:
nathaninline committed 2026-07-25 13:29:33 +02:00
1 parent 43ea4ad6c7
commit f8e856ed7c
2 files changed
+55 -2

No files matched your search

+11 -1
View File
@@ -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")
}
}()
+44 -1
View File
@@ -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()