Skip to content

Complete MySpeed service integration - #161

Merged
retransmit merged 24 commits into
retransmit:developmentfrom
lxBlazarxl:development
Sep 20, 2026
Merged

retransmit merged 24 commits into
retransmit:developmentfrom
lxBlazarxl:development

Conversation

@lxBlazarxl

Copy link
Copy Markdown
Collaborator

Overview

Implements full support for the MySpeed internet speed monitoring service, featuring a 3-tab interface (Status, History, Config), responsive polling, in-memory history diff caching, dedicated metric visualization cards, and brand asset integration.


Key Changes

1. Status Tab & Execution

  • Unified Status & Action Card: Merged execution status and manual speedtest trigger into a single card with full-width action button.
  • Dynamic Polling & Transitions: Added 5-second polling interval and optimistic UI running state transitions when triggering a manual test.
  • Latest & Recent Results: Displays the most recent speedtest with formatted timestamp and a dedicated "Recent Results" section scoped to 24-hour test runs (/api/speedtests?hour=24).
  • Layout Overflow Fix: Hardened title layout against narrow screen bounds using Flexible and removed duplicate status spinner.

2. History Tab & Incremental Caching

  • Diff-Based History Fetching: Implemented MySpeedHistoryNotifier to cache tests in memory and only pull incremental diffs on polling/tab focus, preventing performance degradation with hundreds of tests.
  • Search by ID: Added search filter bar supporting direct lookup by speedtest ID (/api/speedtests/:id) with loading and error states.
  • Historical Summary: Added aggregated average metrics (Download, Upload, Ping) with dynamic Material 3 color highlights.

3. Metric Cards & Theming

  • Dedicated Metric Boxes: Replaced dark plain tiles with elevated MySpeedTestCard containing dedicated highlighted boxes for Download, Upload, and Ping.
  • Dynamic Theming: Converted hardcoded color accents into dynamic ThemeData tokens (colors.primary, colors.secondary, colors.tertiary, colors.surfaceContainer).

4. Configuration & Storage Tab

  • Server & Cron Overview: Displays active cron schedule, test provider, node information, and property counts.
  • Storage Statistics: Integrated GET /api/storage endpoint with MySpeedStorage model to display database size and total tests stored.
  • Filterable Properties: Search bar to quickly filter configuration key-value pairs with one-tap copy to clipboard.
  • Layout Alignment: Unified card spacing to Insets.md (12px).

5. App & Model Integration

  • Brand Icon: Bundled myspeed.png into assets/service_icons/ for the instance creation picker.
  • Beta Graduation: Removed beta badge from ServiceKind.myspeed in core_models.
  • Appbar Polish: Removed redundant top refresh icon in favor of EasyRefresh pull-to-refresh on all tabs.

Verification

  • service_myspeed Tests: 21 unit & widget tests passing (myspeed_api_test.dart, myspeed_home_test.dart).
  • core_models Tests: 19 tests passing (service_kind_test.dart, serialization).
  • app Tests: All brand icon and service render tests passing (myspeed_brand_icon_test.dart, new_services_render_test.dart).
  • Static Analysis: 0 analyzer issues across all packages.

lxBlazarxl and others added 22 commits September 20, 2026 17:56
…history

GET api/speedtests answers with the last 24 hours and ten rows unless told
otherwise, so the History tab was a day and the day's list was ten tests.
The list call now takes hours, limit and start, the three parameters the
server reads; hour and afterId did nothing. The run call posts to
api/speedtests/run alone, which is the endpoint that exists.
…, and poll the day's list less

Labels follow the app's sentence case. The status poll re-reads the day's
list when a run ends and once a minute, instead of every five seconds,
and no longer touches its ref after the widget is gone.
@retransmit

Copy link
Copy Markdown
Owner

Thanks for building this out to three tabs and checking it against a real MySpeed. It works well against mine too.

I pushed some changes to your branch:

  • GET api/speedtests answers with the last 24 hours and ten rows unless told otherwise, so History was showing one day (152 of my 168 tests) and the 24-hour section showed ten. The list call now sends hours and limit, plus start for paging. hour and afterId are ignored by the server, so they are gone, as is the POST api/speedtests fallback (api/speedtests/run is the endpoint).
  • Labels in sentence case like the rest of the app, "1 test" rather than "1 tests", and the status poll re-reads the day's list when a run ends and once a minute instead of every five seconds.
  • README and STATUS.md list MySpeed.
  • Merged development in, so the shell conflict is resolved.

One thing left before this can go in: MySpeed can be password protected (the passwordLevel setting; the password travels as a password header on every request), and the module ships with no auth, so anyone who has set a password cannot add their server. Could you add that? It needs a password field on the instance form, an arm in AuthInterceptor that sends the header, and authStyle switched accordingly. I can test it against a password-protected instance here once it is up.

…king layer

Support optional password authentication for MySpeed across models, networking, health probes, and UI.

- Update ServiceKind.myspeed auth style from none to apiKey.
- Send password and x-password headers via AuthInterceptor when apiKey is configured.
- Register password and x-password headers in serviceAuthHeaderNames.
- Switch MySpeed health probe mode to _HealthMode.authed on api/speedtests.
- Render obscured optional password field in InstanceFormScreen with helper text for creation and edit settings.
- Add unit and widget tests covering interceptor headers, health response interpretation, and form hydration.
@lxBlazarxl

Copy link
Copy Markdown
Collaborator Author

Thank you for testing this against your instance and for pushing the parameter cleanup, sentence-casing, polling adjustments, and merge, that makes the integration much cleaner and more accurate to MySpeed's server behavior.

My apologies for overlooking password protection in the initial pass. I've just pushed a commit adding full authentication support

…rt will let it through

MySpeed 1.0.9 reads a raw password header and newer builds prefer the
URL-encoded x-password one, so both go out. Dart's HttpHeaders throws on
a value outside printable ASCII, from inside the request, so a password
with an accented or non-Latin character broke every call instead of
merely missing the older header. The raw one now goes only when it fits;
the header-name map says the same.
@retransmit

Copy link
Copy Markdown
Owner

Thanks for the auth, that was quick, and the header choice is right: 1.0.9 reads the raw password header and master prefers the URL-encoded x-password, so both is what it takes. It works here against a password-protected 1.0.9, wrong password shows the warning and the right one connects.

I pushed one change to your branch:

  • Dart refuses a header value outside printable ASCII by throwing inside the request, so a password with an accented or non-Latin character broke every call. The raw password header now goes only when it fits; x-password always goes.

@retransmit
retransmit merged commit 0a1cae0 into retransmit:development Sep 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants