Commit graph

4 commits

Author SHA1 Message Date
Vadim Peretokin
cb402cc3e6
infrastructure: use std::chrono literals for time durations (#9493)
#### Brief overview of PR changes/additions

Convert raw millisecond integer literals at time-duration call sites to
`std::chrono` literals, and add `#include <chrono>` to each touched
translation unit. Examples:

- `QTimer::singleShot(0, ...)` → `QTimer::singleShot(0ms, ...)`
- `mpTimerReplay->setInterval(1000)` → `setInterval(1s)`
- `mPendingTimer.start(60000)` → `start(1min)`
- `QObject::startTimer(50)` → `startTimer(50ms)`
- `QTest::qWait(100)` → `QTest::qWait(100ms)`
- `QThread::msleep(10)` → `QThread::sleep(10ms)`

This is a semantics-preserving refactor - every duration is kept exactly
equal to before (e.g. `1000` ms becomes `1s`, `60000` ms becomes
`1min`). No behavioural change.

#### Motivation for adding to Mudlet

Chrono literals make time durations self-documenting and type-safe. `1s`
/ `100ms` read unambiguously where a bare `1000` / `100` forces the
reader to remember each API's unit, and the compiler now rejects unit
mismatches. Only genuine duration arguments were converted - loop
counts, scroll-line counts, sizes, ports and the like were deliberately
left as plain integers.

All targeted APIs provide `std::chrono` overloads in the minimum
supported Qt (6.8.2): `QTimer::singleShot`/`start`/`setInterval` (5.8),
`QObject::startTimer` (5.9), `QThread::sleep(std::chrono::nanoseconds)`
(6.6) and `QTest::qWait(std::chrono::milliseconds)` (6.7).

#### Other info (issues closed, discussion etc)

Test case: the full application builds cleanly and the entire functional
`ctest` suite passes. The only failing test is the known, pre-existing
`PasswordMigrationTest` LSan exit-leak (GTK3/fontconfig noise), which is
unrelated to this change.

Assisted-by: Claude:claude-opus-4-8
2026-07-25 20:24:31 +02:00
Vadim Peretokin
094022f47c
infrastructure: test suites no longer clash when run at the same time (#9483)
#### Brief overview of PR changes/additions
- TelnetServerStub now binds an OS-assigned (ephemeral) port; its log
reports the actual bound port
- All 11 functional tests that hardcoded listen ports (three shared port
4000, two pairs shared 4003/4004) now read the real port back via
serverPort()

#### Motivation for adding to Mudlet
Concurrent test runs (parallel CI jobs, multiple checkouts on one
machine) collided on the fixed ports, causing flaky bind failures and
tests connecting to the wrong run's server.

#### Other info (issues closed, discussion etc)
Follows the pattern GMCPCharLoginTest already used. Verified by running
two copies of TelnetTextDisplayedTest simultaneously - both passed on
distinct ports (37503/42303), impossible before.

**Test case:** Run the functional suite twice in parallel (two build
dirs or ctest -j2 repeated); no "address already in use" failures.

Assisted-by: Claude:claude-opus-4-8
2026-07-20 09:01:51 +02:00
Mike Conley
a97186ad5f
Add: sign in to supported games using your browser (e.g. Google, Discord, or the game's own account) (#9378)
#### Brief overview of PR changes/additions

Adds client-side support for the GMCP `Char.Login` v2 sign-in flow. When
a game offers it, Mudlet automates sign-in *around the game's own login
screen* — it renders no sign-in UI of its own:

- Hands off to the game's interactive screen with an empty
`Char.Login.Credentials {}` when nothing is stored, so the player picks
a provider (Google, Discord, GitHub, the game's own account, …) as text
on the game's own screen.
- Opens the sign-in URL the server pushes (`Char.Login.URL`) in the
system browser — but only after the player has acted on this connection,
never unprompted.
- Autofills a stored character name + password when the profile has
them.
- Persists and replays the server's reconnect token (`Char.Login.Token`
/ `Char.Login.Reconnect`) for instant, password-less reconnects, with a
"forget saved sign-in" control in Preferences → Connection.
- Resumes the *remembered* provider's browser sign-in without a menu
when a saved token has expired or been revoked (`Char.Login.Credentials
{account, provider}`), falling back to the interactive hand-off only
when no provider is remembered.
- Handles token rotation and multiple devices safely: overwrites the
saved token when the server rotates it, and if another running Mudlet
instance sharing the profile's keychain rotates the token mid-flight,
replays the fresh token instead of discarding it.
- For a game that is its own OpenID Provider over TLS, optionally runs
the client-driven PKCE flow end to end (`Char.Login.AuthCode`).

#### Motivation for adding to Mudlet

Modern games are moving to browser-based single sign-on; this lets
Mudlet players use those accounts directly, and reconnect without
re-entering anything — while classic character-name/password logins keep
working unchanged.

#### Other info (issues closed, discussion etc)

- Reworks the approach to resolve @vadi2's UX feedback
(https://github.com/Mudlet/Mudlet/pull/9373#issuecomment-4865669499):
there is **no client pop-up and no in-client chooser**. The game owns
the sign-in screen and offers the choice as text; Mudlet only automates
the mechanical hooks around it (autofill, open URL, save token, replay
token).
- Supersedes and closes #9373.
- Implements the revised v2 draft spec, inspired by #9354.
- Covered by new tests: `OAuthClientFlowTest` (OIDC discovery, PKCE,
loopback capture) and the `GMCPCharLoginTest` functional suite driving a
GMCP server stub through the full client flow.
- Try it out on StickMUD.



https://github.com/user-attachments/assets/566947f6-4f43-4bff-b98c-9328b7a40a2d

---------

Signed-off-by: Michael Conley <sousesider@gmail.com>
2026-07-14 12:20:02 +00:00
Vadim Peretokin
4bb4121504
fix: enable/disable only affecting some same-named items on Windows (#9366)
#### Brief overview of PR changes/additions
Fixes a Windows-only bug where `enableAlias`/`disableAlias` and the
trigger/timer/key equivalents (plus `setTriggerStayOpen`) only toggled
some items when several shared a name, e.g. two groups both named "Druid
Aliases". The cause was `mLookupTable.constFind(name)` + forward
iteration, which could start mid-run in the `QMultiMap` and skip
duplicates depending on the platform's iteration order - fine on
Linux/macOS, broken on Windows; it now uses `equal_range()`, which is
correct everywhere.

#### Motivation for adding to Mudlet
Windows users with items sharing a name (commonly alias/trigger groups)
could only partly enable/disable them, silently leaving the rest in the
wrong state.

#### Other info (issues closed, discussion etc)
Adds a busted spec and a C++ functional test covering aliases, triggers,
timers, keys and scripts. The functional test failed on the Windows CI
runner and passed on Linux/macOS, pinning it to the platform-dependent
`QMultiMap` iteration. Scripts were already correct (they iterate all
matches).

**Test case:** on Windows, two alias groups both named "Druid Aliases" →
`disableAlias("Druid Aliases")` stops both, `enableAlias("Druid
Aliases")` re-enables both. Covered by `EnableDisableByNameTest` and
`Alias_spec.lua`.

---------

Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-03 14:17:58 +02:00