Heartbeats and threading
Three kinds of calls
Section titled “Three kinds of calls”| Kind | Examples | Where it runs |
|---|---|---|
| State | IsLoggedIn, HasTier, Subscriptions, Variable, Hwid |
Reads an in-memory snapshot. Never blocks; call it from anywhere |
| Async | LoginAsync, FetchVariableAsync, DownloadFileAsync … |
Queued on the SDK’s one worker thread, in order. The callback goes through the dispatcher |
| Blocking | Login, FetchVariable, Heartbeat … |
The network round trip on your thread. Never on a UI thread |
Every function is thread-safe. There is one SDK instance per process.
The dispatcher
Section titled “The dispatcher”Without a dispatcher, callbacks and events run on the SDK’s worker thread. Set one so they arrive where your UI lives:
// Win32: post to a window, handle WM_APP_EONAUTH with eonauth::win32::RunDispatched(lParam).eonauth::SetDispatcher(eonauth::win32::WindowDispatcher(hwnd, WM_APP_EONAUTH));
// Anything else: your own function that runs `work` on the right thread.eonauth::SetDispatcher([](std::function<void()> work) { PostToUiThread(std::move(work)); });Event handlers (AddEventHandler) go through the dispatcher too. AddEventHandler returns an ID for
RemoveEventHandler.
Heartbeats
Section titled “Heartbeats”After sign-in, the worker thread sends a heartbeat at the interval set in App settings, with ±10% random jitter so clients started by the same update don’t arrive at once. Each heartbeat:
- re-checks the user, key, ban, PC lock and blacklist on the server,
- refreshes the subscriptions (raising
SubscriptionsChangedif they changed), - keeps the session’s idle expiry from running out.
A ban or revoked key reaches a running app at its next heartbeat.
When the network drops
Section titled “When the network drops”- A failed heartbeat raises
ConnectionProblem. The user stays signed in, andIsConnectionHealthy()is false. - The SDK retries after 15 seconds, doubling up to the heartbeat interval.
- The first heartbeat that gets through raises
ConnectionRestored. - If nothing gets through before the server-side session expires, it raises
SessionLostwithNetworkError, so the app locks.
Only a definitive answer from the server ends a session. A flaky connection is never mistaken for a ban.
Turn background heartbeats off with Config::autoHeartbeat = false and call Heartbeat() yourself.
Retries
Section titled “Retries”- Connect timeout 5 seconds, receive timeout 15 seconds.
- Network errors and server errors get up to 3 attempts with backoff and jitter. Each retry is freshly encrypted and signed.
RateLimitedis never retried blindly:Result::retryAfterSecondssays how long to wait.- Register, key login and redeem are never retried once the request may have reached the server.
A blind retry could burn a key or create a second account. You get
NetworkErrorwith a message saying it may have gone through, so the user can check before trying again.
The server accepts requests within 30 seconds of its own clock. If the PC’s clock is more than 10
seconds off, the SDK corrects for it using the server’s time and retries once. If that fails, you
get ClockSkew, and UserHint suggests turning on Set time automatically.
Shutting down
Section titled “Shutting down”Call Shutdown() before the process exits, for example in WM_DESTROY. Queued async calls that
haven’t started are dropped and their callbacks don’t run; callbacks already posted to a window that
is being destroyed are dropped too.
Blocking calls
Section titled “Blocking calls”For console tools and your own worker threads, every async call has a blocking twin:
#include "eonauth.h"
int main() { if (!eonauth::Init(MakeConfig())) return 1; eonauth::Result r = eonauth::LoginWithKey(key, username); if (!r) { std::puts(eonauth::UserMessage(r).c_str()); return 2; }
std::string value; if (eonauth::FetchVariable("var_0123456789abcdef0123456789abcdef", &value)) Use(value);
eonauth::Shutdown(true); // also signs out}Logging
Section titled “Logging”eonauth::SetLogHandler([](eonauth::LogLevel level, const std::string& line) { MyLog(level, line); });Lines are already scrubbed: the SDK never logs tokens, keys or passwords, and also redacts anything
shaped like a license key or a long base64 or hex string. Pass nullptr to go back to
stdout/stderr.