close-league-client-in-game: start the idle clock only after a client was seen

A long patch or login can keep the League client closed for more than ten
minutes after launch; the helper then left before the first match.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
lucannez64andClaude Opus 5.5 committed 2026-10-18 20:48:43 +02:00
1 parent bc8fa71a7f
commit 957b960985
3 files changed
+32 -7

No files matched your search

+2 -1
View File
@@ -156,7 +156,8 @@ backend and the game untouched, and takes no action when ownership, the
environment or the stat fields cannot be read. The client UI is recognised by the
name of its executable, not by the command line: `LeagueCrashHandler` processes
carry the client UI name in their arguments only, so they are left alone. It
leaves by itself after ten minutes without a client or a match. Diagnose it in one
leaves by itself ten minutes after the last client or match is gone (the clock does
not run before the first client appears, so a long patch or login is fine). Diagnose it in one
observation, without waiting for a match:
```sh
+13
View File
@@ -194,6 +194,19 @@ class InGameCloseTests(unittest.TestCase):
in_game.close_ui(self.proc, {'123': identity, '124': 1})
self.assertEqual(kill.call_args_list, [])
def test_idle_clock_starts_only_after_a_client_or_match(self):
empty = {'game': False, 'ui': {}}
client = {'game': False, 'ui': {'10': 5}}
match = {'game': True, 'ui': {}}
# Before any client (long patch or login): never idle, however long it takes.
self.assertEqual(in_game.update_idle(empty, False, None, 5000.0), (False, None))
# A client or a match marks the session as seen and keeps the clock stopped.
self.assertEqual(in_game.update_idle(client, False, None, 10.0), (True, None))
self.assertEqual(in_game.update_idle(match, True, 50.0, 60.0), (True, None))
# Afterwards the clock starts once and keeps its start time.
self.assertEqual(in_game.update_idle(empty, True, None, 70.0), (True, 70.0))
self.assertEqual(in_game.update_idle(empty, True, 70.0, 900.0), (True, 70.0))
def test_close_decision_covers_limits_and_cooldown(self):
state = {'game': True, 'ui': {'123': 1}}
self.assertEqual(in_game.close_decision(state, 0, 0.0, 100.0), 'close')
+17 -6
View File
@@ -49,7 +49,7 @@ KILL_GRACE = 2.0
POLL_SECONDS = 5.0
COOLDOWN_SECONDS = 30.0 # minimum between two closes in the same match
MAX_CLOSES = 3 # give up on a client that keeps reopening during a match
IDLE_SECONDS = 600.0 # leave after this long without a client or a game
IDLE_SECONDS = 600.0 # leave after this long without a client or a game, once one was seen
def target_prefix():
@@ -165,6 +165,20 @@ def close_decision(state, closes, last_close, now):
return 'close'
def update_idle(state, seen, idle_since, now):
"""Return (seen, idle_since) after one observation.
The idle clock only starts once a client UI or a match has been seen: a long
patch or login can keep the League client closed for more than IDLE_SECONDS
after launch, and leaving then would skip the match that follows.
"""
active = state['game'] or bool(state['ui'])
seen = seen or active
if active or not seen:
return seen, None
return seen, now if idle_since is None else idle_since
def supervise(proc_root=Path('/proc'), prefix=None, once=False, dry_run=False, out=sys.stdout):
"""Watch for a match and close the client UI while it runs."""
prefix = prefix or target_prefix()
@@ -177,6 +191,7 @@ def supervise(proc_root=Path('/proc'), prefix=None, once=False, dry_run=False, o
closes = 0
last_close = 0.0
limit_reported = False
seen = False
idle_since = None
while True:
state = match_state(proc_root, prefix)
@@ -215,11 +230,7 @@ def supervise(proc_root=Path('/proc'), prefix=None, once=False, dry_run=False, o
'running match (%d processes: %s)'
% (len(closed), ','.join(sorted(closed, key=int))),
file=out, flush=True)
idle = not state['game'] and not state['ui']
if idle and idle_since is None:
idle_since = now
elif not idle:
idle_since = None
seen, idle_since = update_idle(state, seen, idle_since, now)
if once:
if state is not None:
print('close-league-client-in-game: one observation: match=%s client_ui=%d'