chore(release): v0.7.16

Durcit la boucle principale de wgsecure-helper : ne capturait que
pywintypes.error (pas Exception en général) et ne protégeait pas
CloseHandle individuellement dans le nettoyage, si bien qu'une
exception inattendue sur une requête pouvait arrêter tout le
service — expliquant un premier échange réussi (juste après
démarrage) puis un service injoignable ensuite. Gère aussi
ERROR_PIPE_CONNECTED (course normale, pas rare, entre CreateNamedPipe
et ConnectNamedPipe) au lieu de la traiter comme une erreur.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 21:50:57 +02:00
co-authored by Claude Sonnet 5
parent 5133868951
commit b4f85c5605
6 changed files with 57 additions and 19 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
__version__ = "0.7.15"
__version__ = "0.7.16"
APP_NAME = "WGSecure"
APP_SHORT = "WGS"
+45 -14
View File
@@ -226,12 +226,12 @@ def _handle_connection(handle, logger: logging.Logger) -> None:
except ValidationError as e:
resp = {"ok": False, "message": str(e)}
logger.info("%s -> ok=%s", cmd, resp.get("ok"))
except (pywintypes.error, ValueError, OSError) as e:
except Exception as e:
logger.exception("Requête invalide ou erreur pipe")
resp = {"ok": False, "message": f"Erreur interne : {e}"}
try:
win32file.WriteFile(handle, (json.dumps(resp) + "\n").encode("utf-8"))
except pywintypes.error:
except Exception:
pass
@@ -273,26 +273,57 @@ class WGSecureHelperService(win32serviceutil.ServiceFramework):
)
logger = _get_logger()
logger.info("Service démarré")
try:
self._serve_forever(logger)
except Exception:
# Filet de sécurité final : si malgré tout ce qui suit une
# exception s'échappe encore, elle laisse au moins une trace
# exploitable ici plutôt qu'un service qui disparaît en
# silence sans rien dans le log.
logger.exception("Arrêt inattendu de la boucle principale")
finally:
logger.info("Service arrêté")
def _serve_forever(self, logger: logging.Logger) -> None:
# Chaque étape est individuellement protégée et ne peut donc jamais
# faire sortir la boucle sur une exception non prévue : un service
# censé tourner indéfiniment sans surveillance ne doit jamais
# s'arrêter à cause d'un incident sur UNE requête. Une version
# antérieure ne capturait que pywintypes.error (pas Exception en
# général) et ne protégeait pas CloseHandle individuellement dans
# le `finally` : une erreur non prévue là pouvait remonter et
# arrêter tout le service — expliquant un premier échange réussi
# (juste après le démarrage du service) puis silence total ensuite.
ERROR_PIPE_CONNECTED = 535
while self._running:
handle = None
try:
handle = _create_pipe_instance()
except pywintypes.error:
logger.exception("Création du pipe impossible")
break
try:
win32pipe.ConnectNamedPipe(handle, None)
try:
win32pipe.ConnectNamedPipe(handle, None)
except pywintypes.error as e:
# Le client s'est connecté entre CreateNamedPipe et
# ConnectNamedPipe : cas normal (pas une erreur), pas
# rare vu la fréquence des appels — sans ce cas
# particulier, la requête était silencieusement ratée
# à chaque fois qu'il se produisait.
if e.winerror != ERROR_PIPE_CONNECTED:
raise
if not self._running:
break
_handle_connection(handle, logger)
except pywintypes.error:
except Exception:
logger.exception("Erreur sur une connexion cliente")
finally:
try:
win32pipe.DisconnectNamedPipe(handle)
except pywintypes.error:
pass
win32file.CloseHandle(handle)
logger.info("Service arrêté")
if handle:
try:
win32pipe.DisconnectNamedPipe(handle)
except Exception:
pass
try:
win32file.CloseHandle(handle)
except Exception:
pass
if __name__ == "__main__":