Ask once whether to register a download on the ModDB listing - #220
Ask once whether to register a download on the ModDB listing#220Pixnop wants to merge 3 commits into
Conversation
The launcher is listed on ModDB as mod 11016, and that listing's download count is most of what decides whether anyone browsing the site finds it. The listing holds a 315-byte archive pointing at the GitHub releases page, not a build. This adds a prompt shown once, on startup, offering to request that archive so the listing registers one download. Three answers, all equal: count me in, no thanks, already did it. Whichever is pressed is stored in the config and the question never comes back. Only the first one makes a request, exactly one, and only after a click. Closing the dialog without answering stores nothing, so the question survives to the next launch rather than being read as consent or as a refusal. The request goes through the main process: the current file id is resolved from the ModDB API first, since a new upload mints a new one, and only then is the counting endpoint touched, capped at 256 KB. A failure anywhere along the way is logged at debug and dropped, with nothing shown to the player. Refs #219
|
Adjusted the dialog copy in one respect, because the implementation turned out more honest than the sentence describing it. The bounded network layer follows no redirect, and the counter increments before the site issues its 302, so the archive's bytes never actually transfer. The copy said the launcher fetches the archive and throws it away, which promises a download that does not happen. It now says the launcher asks ModDB once for the listing's archive, that this registers as one download, and that the launcher does not keep it. Same meaning for the reader, no claim the code does not back. 190 renderer tests still pass with the new string. |
|
Follow-up commit on a log line, found by reading a real run's debug log rather than the tests. Accepting the prompt printed 'Attempted to redirect, but redirect policy was error', because the counting endpoint answers with a 302 and the bounded network layer refuses to follow redirects, so the generic catch treated the successful outcome as a failure. Anyone debugging something unrelated would have followed that trail for nothing. That branch now says what happened: the endpoint answered with its redirect, which is the counted outcome, not followed on purpose. Everything else about the behaviour is unchanged, the request is still one attempt and still silent to the user. Reading Electron's message is the only signal available for that distinction, so the comment says as much: if the wording ever changes upstream, the request behaves identically and only this line falls back to the generic branch. The new test pins the counted-outcome line and fails when the branch is removed, checked by mutation. The log had to be mocked module-wide rather than spied, since freshHandlers resets the module registry between tests and a spy would watch an instance the handler no longer imports. |
RiftLauncher has a ModDB listing whose download counter is most of what decides whether anyone browsing that site ever sees the launcher. The listing holds no build. It holds a 315 byte text archive pointing at the GitHub releases page, and the binaries stay on GitHub exactly as they are.
This adds one prompt, shown once, asking whether the launcher may request that little archive so the listing registers a download. It does not download the launcher from ModDB and it does not touch where updates come from.
The measurements are in issue #219: requesting the CDN URL leaves the counter alone, requesting the site's own download endpoint increments it. That endpoint is the only door that counts. In practice the bounded network layer follows no redirect, so the archive's bytes never even transfer.
Kept honest by construction, not by wording
Three answers drawn and treated as equals: count me in, no thanks, already did it. Whichever is pressed gets written to the config and the question never returns, on any later launch, whatever the answer was. Only the yes makes a request, exactly one, and only after a click. Nothing runs on a timer or at startup on its own.
Closing the dialog without pressing anything writes nothing. The question comes back next launch rather than counting as a yes or a no, because silence is neither. No default focus, no colour or size pushing one button over the others, and no download count displayed anywhere that would turn a question into a scoreboard.
Implementation
The request happens in the main process through the existing bounded network layer, behind the same trusted-sender gate as its neighbours. The listing's current file id is resolved from the ModDB API first, since a new upload mints a new id and a stale one would count towards an entry nobody is looking at, and only then is the counting endpoint touched, capped at 256 KB. Nothing is written to disk.
If the API is unreachable, the listing carries no readable release, or the request fails, the whole thing is dropped silently. The answer is still recorded so the player is never asked twice, and no error reaches them, because this is a courtesy they offered rather than a task they are waiting on.
Both allowlist rules the two calls use were already there, so no new host or path is opened. Widening API_URL_RULES to cover the download endpoint would have been the shorter route and was refused on purpose: a feature about a counter is the last place to hand the renderer a way to reach that counter.
Tests
The prompt appears only when the question is unanswered. Each of the three answers is recorded, only the yes fetches, and the dismissal writes nothing. The file id is resolved before the counting endpoint is hit. A failure at either step still records the answer silently. Config normalization covers an unknown stored value falling back to unasked. Every one of those was checked against a deliberate mutation of the code it guards.