Repository navigation
fix(logout): keep Auto Login suppressed while a terminal logout is delayed - #1950
Conversation
…layed TerminalLogoutPrompt requested suppression once and kept retrying the logout, but a pending request lapses after 15 s. A logout delayed past that window reached the login screen unsuppressed and Auto Login logged straight back in. The prompt now renews the pending request every 5 s; a renewal only extends a request that is still pending, so it never re-blocks Auto Login after a script start, restart or manual login cleared it. logoutWithoutAutoLoginStep no longer requests suppression when it is already on the login screen, where the request could never complete. TerminalLogoutPrompt throttles on a monotonic clock, guards its state for begin/reset from other threads, and ignores a logout result or suppression callback from a stop that was reset mid-tick. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughAuto-login suppression requests now support renewal with a shared 15-second pending deadline. Terminal logout prompts throttle attempts, renew suppression during delayed logout, and guard against stale stop callbacks. Logout handling returns Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
… state TerminalLogoutPrompt renewed its suppression request only from inside logoutWithoutAutoLoginStep, which reaches the callback only at LOGGED_IN. A client stuck in CONNECTION_LOST or LOADING for more than 15 s let the request lapse, and Auto Login logged back in once the client dropped to the login screen. The prompt now renews from its own tick on every attempt that has not yet seen the login screen. The prompt's first suppression is now a request followed by a renewal, so a request another source already left pending (for example Rs2Player.logoutWithoutAutoLogin from Inventory Setup) gets a fresh deadline instead of lapsing before the prompt's first renewal. A terminal stop whose prompt first sees the login screen without ever having requested suppression (disconnect or break-handler logout) now posts AutoLoginSuppressionRequest.loggedOut(). AutoLogin moves straight to its suppressed logged-out state if it is still on the login screen, and resumes on a manual login, a script start or an AutoLogin restart. The plain logoutWithoutAutoLoginStep still requests nothing at the login screen, and a stop that was reset or replaced mid-tick never holds. Trim the Javadoc lines added in chsami#1950 and bump AutoLogin to 1.0.7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV
Follow-ups from the review of #1944.
Problem
TerminalLogoutPrompt.tick()requested Auto Login suppression only once and then kept retrying the logout every 600 ms. A pendingAutoLoginSuppressionrequest lapses back toALLOWEDafter 15 s (AWAIT_LOGOUT_MILLIS) if the login screen has not been seen. When the logout took longer than that (combat lockout, repeatedINPUT_BLOCKED), the eventual logout reachedLOGIN_SCREENunsuppressed, so Auto Login logged straight back in after the prompt had reported success.Rs2Player.logoutWithoutAutoLoginSteprequested suppression even when its first read already sawLOGIN_SCREEN. That request can never complete, and for up to 15 s it held off Auto Login after a restart.TerminalLogoutPromptthrottled onSystem.currentTimeMillis(), and its fields were written from the host's startup/callback threads (begin/reset) and read from the script loop (tick) with no synchronization. Areset()+begin()that landed while atick()was inside the logout step let the old tick complete and announce the new stop.Change
AutoLoginSuppressionRequestgainsrenewal()/isRenewal()and a publicPENDING_LOGOUT_MILLIS(15 s, now the source ofAutoLoginSuppression.AWAIT_LOGOUT_MILLIS).new AutoLoginSuppressionRequest()behaves as before.AutoLoginSuppression.renew()restarts the deadline only while a request is still pending. If a script start, an Auto Login restart or a manual login has cleared it, or it has already expired, renewing does nothing. Plain repeatedrequest()calls still do not extend the deadline (repeatedPendingRequestsDoNotExtendDeadlineis unchanged).AutoLoginPluginsends renewals to the newAutoLoginScript.renewAutoLoginSuppression().TerminalLogoutPromptsends the first request as before. After that, on any step that is about to click logout, it renews once the last request or renewal is 5 s old (PENDING_LOGOUT_MILLIS / 3). This keeps suppression alive however long the logout is delayed. I used a renewal rather than a fresh request after the window, as the review suggested, for two reasons:ALLOWEDbetween the expiry and the next tick.logoutWithoutAutoLoginguards against.logoutWithoutAutoLoginStepreturnsLOGGED_OUTatLOGIN_SCREENbefore it runs the suppression request.TerminalLogoutPrompt:System.nanoTime()in milliseconds, the same clockAutoLoginSuppressionuses. A package-private constructor lets tests inject the clock, and the first attempt does not depend on the clock's sign.begin/reset/active/messageand the tick bookkeeping aresynchronized. The lock is not held while the logout step runs (it blocks on the client thread) or while the notification runs (Microbot.showMessageis a modalinvokeAndWait).Public API used by Hub PR 597 (
begin,active,message,tick(),reset,tick(Supplier, Consumer)) is unchanged.Testing
TerminalLogoutPromptTest.delayedLogoutKeepsRenewingSuppressionUntilTheLoginScreen: logout is delayed for 45 s on a fake clock. At every tick, the last request or renewal must be under 15 s old. This fails when the renewal branch is disabled.AutoLoginSuppressionTest.renewalRestartsThePendingDeadlinefails whenrenew()does nothing.renewalNeverReblocksAClearedOrExpiredRequestandrenewalAfterLogoutKeepsWaitingForManualLogincover the restart intent.TerminalLogoutStepTest.loginScreenConfirmsLogoutWithoutAnUncompletableSuppressionexpects 0 requests atLOGIN_SCREENand fails with the old line order.TerminalLogoutPromptTest.restartFromAnotherThreadDuringLogoutIsNotCompletedOrSuppressedByTheOldTickrunsreset()+begin()on a second thread during the logout step. Without the stop counter it fails because the old tick announces the new stop. Its 5 sjointimeout also catches a version that holds the lock across the logout step.TerminalLogoutPromptTest.throttleUsesTheInjectedClockEvenWhenItStartsNegativefails with anextAttemptAt = 0-style throttle. Against the original class it does not compile, because there was no way to inject a clock.AutoLoginPluginSupplyStopTestchecks that renewals are routed separately from requests../gradlew :client:runUnitTests --offline: 331 classes, 2339 tests, 0 failures, 0 errors, 2 skipped. This includesClientThreadGuardrailTest, and no baseline change was needed.AutoLoginScript, and readisSuppressed()by reflection:trueat 14 s andfalseat 16 s. That is the lapse this PR fixes.resumeAutoLogin()(what a script start triggers), a renewal left itfalse, so there is no re-block.TerminalLogoutPrompt.begin()+tick()logged out within 5 tick calls and reported done, with suppressiontrue.logoutWithoutAutoLoginStep()at the login screen then returnedLOGGED_OUT. The client stayed onLOGIN_SCREEN, still suppressed and with no Auto Login attempt logged, for about 5.5 min: from the logout at 12:07:55, through the modal completion dialog (open until 12:12:45), to the end of a 45 s watch at 12:13:30.false; I did not let it log in.🤖 Generated with Claude Code
https://claude.ai/code/session_01LjtEMzQHGuq4M1Mpqk9pPV