# API Reference All types live in the `lancommander` namespace. Include `` for everything, or include individual headers as needed. --- ## Core Types ### `Result` Every client method returns `Result`. Check success with `operator bool()` or the `.success` field. ```cpp auto result = games.get_all(); if (result) { // result.value contains the data for (auto& g : result.value) printf("%s\n", g.title.c_str()); } else { // result.error contains a human-readable message printf("Error: %s\n", result.error.c_str()); } ``` Static factories: - `Result::ok(T value)` — create a success result - `Result::fail(std::string error)` — create a failure result ### `DownloadProgressFn` ```cpp using DownloadProgressFn = std::function; ``` Callback for download progress. Return `false` to abort the download. ```cpp games.download(game_id, "game.zip", [](uint64_t recv, uint64_t total) -> bool { printf("\r%llu / %llu bytes", recv, total); return true; // return false to cancel }); ``` --- ## HTTP Layer ### `IHttpClient` (abstract) All clients take a reference to an `IHttpClient`. You must provide a concrete backend. ```cpp class IHttpClient { public: virtual void set_base_url(const std::string& url) = 0; virtual void set_bearer_token(const std::string& token) = 0; virtual HttpResponse get(const std::string& path) = 0; virtual HttpResponse post(const std::string& path, const std::string& body, const std::string& content_type = "application/json") = 0; virtual HttpResponse put(const std::string& path, const std::string& body, const std::string& content_type = "application/json") = 0; virtual HttpResponse del(const std::string& path) = 0; virtual bool download(const std::string& path, const std::string& dest_path, DownloadProgressFn progress = nullptr) = 0; virtual HttpResponse post_multipart_file(const std::string& path, const std::string& field_name, const std::string& file_path) = 0; }; ``` ### `HttpResponse` ```cpp struct HttpResponse { int status_code; std::string body; std::map headers; bool ok() const; // true if status_code is 2xx }; ``` ### Built-in Backends | Class | Header | Platform | Dependency | |-------|--------|----------|------------| | `WinInetHttpClient` | `wininet_http_client.h` | Windows (95+) | wininet.lib | | `CurlHttpClient` | `curl_http_client.h` | Any | libcurl | --- ## Clients All clients are constructed with an `IHttpClient&` reference (except `BeaconClient` which uses UDP directly). Call `set_base_url()` and `set_bearer_token()` on the HTTP client before using authenticated endpoints. ### AuthenticationClient ```cpp AuthenticationClient auth(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `login(username, password)` | `Result` | Authenticate and receive tokens | | `validate()` | `Result` | Check if the current token is valid | | `refresh(current_token)` | `Result` | Refresh an expired token | | `logout()` | `void` | Invalidate the current session | | `get_providers()` | `Result>` | List available auth providers | **AuthToken fields**: `access_token`, `refresh_token`, `expiration` ### ConnectionClient Manages the connection lifecycle to a LANCommander server. Unlike other clients, this one maintains internal state. ```cpp ConnectionClient conn(http); conn.set_server_address("http://192.168.1.100:1337"); conn.set_access_token(token.value.access_token); if (conn.ping()) { conn.connect(); } ``` | Method | Returns | Description | |--------|---------|-------------| | `is_connected()` | `bool` | Whether the client is in connected state | | `is_configured()` | `bool` | Whether address and token are both set | | `is_offline_mode()` | `bool` | Whether offline mode is enabled | | `has_server_address()` | `bool` | Whether a server address is set | | `get_server_address()` | `std::string` | The current server address | | `get_access_token()` | `std::string` | The current bearer token | | `update_server_address(address)` | `Result` | Validate via ping, then set the address | | `set_server_address(address)` | `void` | Set address without validation | | `set_access_token(token)` | `void` | Set the bearer token | | `connect()` | `Result` | Mark as connected (requires configured state) | | `disconnect()` | `Result` | Mark as disconnected | | `enable_offline_mode()` | `void` | Disconnect and enable offline mode | | `disable_offline_mode()` | `void` | Disable offline mode | | `ping(address?)` | `Result` | Ping the server with X-Ping/X-Pong validation | **Event callbacks** (C function pointers with `void* user_data`): ```cpp conn.set_on_connect(my_connect_handler, my_data); conn.set_on_disconnect(my_disconnect_handler, my_data); conn.set_on_server_address_changed(my_addr_handler, my_data); conn.set_on_offline_mode_enabled(my_offline_handler, my_data); ``` ### GameClient ```cpp GameClient games(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get_all()` | `Result>` | Fetch all games | | `get(game_id)` | `Result` | Fetch a single game | | `get_manifest(game_id)` | `Result` | Fetch the install manifest | | `get_actions(game_id)` | `Result>` | Get game actions (launch configs) | | `get_addons(game_id)` | `Result>` | Get expansions/mods for a game | | `get_redistributables(game_id)` | `Result>` | Get required redistributables | | `check_for_update(game_id, version)` | `Result` | Check if an update is available | | `download(game_id, dest, progress?)` | `Result` | Download the game archive | | `notify_started(game_id)` | `void` | Notify the server a game was launched | | `notify_stopped(game_id)` | `void` | Notify the server a game was closed | Also exposes a free function: ```cpp bool parse_manifest_json(const std::string& json, GameManifest* out, std::string* error); ``` ### LibraryClient ```cpp LibraryClient library(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get()` | `Result>` | Get the user's library | | `add(game_id)` | `Result` | Add a game to the library | | `remove(game_id)` | `Result` | Remove a game from the library | ### DepotClient ```cpp DepotClient depot(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get()` | `Result` | Fetch the full depot (games, genres, tags, etc.) | | `get_game(game_id)` | `Result` | Fetch a single depot game with full metadata | `DepotResults` contains: `games`, `collections`, `companies`, `engines`, `genres`, `platforms`, `tags`, `popular`, `backlog`. ### MediaClient ```cpp MediaClient media(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `download_thumbnail(media_id, dest)` | `Result` | Download a thumbnail | | `download(media_id, dest, progress?)` | `Result` | Download full media | | `get_for_game(game_id)` | `Result>` | List media for a game | ### SaveClient ```cpp SaveClient saves(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get(game_id)` | `Result>` | List all saves for a game | | `get_latest(game_id)` | `Result` | Get the most recent save | | `download_latest(game_id, dest, progress?)` | `Result` | Download the latest save | | `upload(game_id, zip_path)` | `Result` | Upload a save archive | ### KeyClient Requires an `IMachineInfo` implementation for machine identification during key allocation. ```cpp class MyMachineInfo : public lancommander::IMachineInfo { public: std::string get_computer_name() override { return "MY-PC"; } std::string get_ip_address() override { return "192.168.1.50"; } std::string get_mac_address() override { return "AA:BB:CC:DD:EE:FF"; } }; MyMachineInfo machine; KeyClient keys(http, machine); ``` | Method | Returns | Description | |--------|---------|-------------| | `get_allocated(game_id)` | `Result` | Get the key allocated to this machine | | `allocate(game_id)` | `Result` | Allocate a new key | ### ProfileClient ```cpp ProfileClient profile(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get()` | `Result` | Get the current user profile | | `get_alias()` | `Result` | Get the user's display alias | | `change_alias(alias)` | `Result` | Change the display alias | | `download_avatar(dest)` | `Result` | Download the user's avatar | ### ScriptClient Fetches script contents from the server (does not execute them — see [Script Execution](#script-execution)). ```cpp ScriptClient scripts(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get_game_scripts(game_id)` | `Result>` | Get scripts for a game | | `get_redistributable_scripts(redist_id)` | `Result>` | Get scripts for a redistributable | ### ToolClient ```cpp ToolClient tools(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get(tool_id)` | `Result` | Fetch tool details (with archives and scripts) | | `get_scripts(tool_id)` | `Result>` | Fetch tool scripts | | `download(tool_id, dest, progress?)` | `Result` | Download the tool archive | ### LauncherClient ```cpp LauncherClient launcher(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `check_for_update()` | `Result` | Check for launcher updates | | `download(dest, progress?)` | `Result` | Download the launcher update | **CheckForUpdateResponse fields**: `update_available`, `version`, `download_url` ### RedistributableClient ```cpp RedistributableClient redist(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `download(redist_id, dest, progress?)` | `Result` | Download a redistributable | ### PlaySessionClient ```cpp PlaySessionClient sessions(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `get()` | `Result>` | List all play sessions | | `get_for_game(game_id)` | `Result>` | Get play sessions for a game | **PlaySession fields**: `id`, `start`, `end`, `game_id`, `user_id` ### IssueClient ```cpp IssueClient issues(http); ``` | Method | Returns | Description | |--------|---------|-------------| | `open(description, game_id)` | `Result` | Report an issue for a game | ### BeaconClient Discovers LANCommander servers on the local network via UDP broadcast. Does not require an HTTP client. ```cpp BeaconClient beacon; auto servers = beacon.discover(3000); // 3 second timeout if (servers) { for (auto& s : servers.value) printf("Found: %s at %s\n", s.name.c_str(), s.address.c_str()); } ``` | Method | Returns | Description | |--------|---------|-------------| | `discover(timeout_ms, port?)` | `Result>` | Find servers via UDP broadcast | Default port: `35891` --- ## Archive Extraction ### `IArchiveExtractor` (abstract) Interface for extracting archive files. You must provide a concrete implementation (e.g. using minizip, libarchive, or a platform-native API). ```cpp class IArchiveExtractor { public: virtual ExtractionResult extract( const std::string& archive_path, const std::string& dest_directory, bool skip_existing_matching_crc = true, ExtractionProgressFn progress = ExtractionProgressFn()) = 0; virtual std::vector list(const std::string& archive_path) = 0; }; ``` **ExtractionProgressFn**: ```cpp using ExtractionProgressFn = std::function; // Return false to cancel extraction. ``` **ExtractionResult fields**: `success`, `canceled`, `directory`, `error`, `extracted_files` **ArchiveEntry fields**: `path`, `is_directory`, `crc32`, `compressed_size`, `uncompressed_size` ### `Crc32` Self-contained CRC32 utility with no external dependencies. ```cpp // Incremental usage lancommander::Crc32 crc; crc.update(data, length); crc.update(more_data, more_length); unsigned long checksum = crc.value(); // One-shot file checksum unsigned long file_checksum = lancommander::Crc32::file_crc32("path/to/file"); ``` --- ## Script Execution ### `IScriptRunner` (abstract) Interface for running scripts with variable injection. ```cpp class IScriptRunner { public: virtual ScriptResult run_file( const std::string& script_path, const std::string& working_directory, const std::map& variables) = 0; virtual ScriptResult run_inline( const std::string& script_contents, const std::string& working_directory, const std::map& variables) = 0; }; ``` **ScriptResult fields**: `success`, `exit_code`, `output`, `error` ### `BatchScriptRunner` Runs `.bat`/`.cmd` scripts via `cmd.exe /C`. Variables are injected as environment variables accessible via `%VAR_NAME%` in the script. ```cpp lancommander::BatchScriptRunner runner; std::map vars; vars["InstallDirectory"] = "C:\\Games\\MyGame"; vars["PlayerAlias"] = "Player1"; vars["ServerAddress"] = "http://192.168.1.100:1337"; auto result = runner.run_file( "C:\\Games\\MyGame\\.lancommander\\install.bat", "C:\\Games\\MyGame", vars); if (result.success) { printf("Script output: %s\n", result.output.c_str()); } else { printf("Script failed (exit code %d): %s\n", result.exit_code, result.error.c_str()); } ``` Inline scripts are written to a temporary `.bat` file, executed, and cleaned up: ```cpp auto result = runner.run_inline( "@echo off\necho Installing to %InstallDirectory%\n", "C:\\Games\\MyGame", vars); ``` **Platform support**: Windows only (95 through modern). On non-Windows platforms, returns a "not supported" error. Use `IScriptRunner` to implement shell-based runners for other platforms. --- ## Models All models are plain structs in the `lancommander` namespace. String fields that represent GUIDs or dates are stored as `std::string` for maximum compatibility (no dependency on UUID or date libraries). ### Key Models | Struct | Key Fields | |--------|------------| | `Game` | `id`, `title`, `sort_title`, `description`, `type`, `base_game_id`, `in_library`, `media`, `genres`, `developers`, `publishers` | | `GameManifest` | `id`, `title`, `version`, `actions`, `save_paths`, `redistributables` | | `Tool` | `id`, `name`, `description`, `archives`, `scripts` | | `Archive` | `id`, `version`, `changelog`, `compressed_size`, `uncompressed_size` | | `DepotGame` | `id`, `title`, `collections`, `developers`, `publishers`, `genres`, `platforms`, `tags`, `multiplayer_modes`, `cover` | | `DepotResults` | `games`, `collections`, `companies`, `engines`, `genres`, `platforms`, `tags`, `popular`, `backlog` | ### Entity/Metadata Models | Struct | Fields | |--------|--------| | `Collection` | `id`, `name` | | `Company` | `id`, `name` | | `Engine` | `id`, `name` | | `Genre` | `id`, `name` | | `Platform` | `id`, `name` | | `Tag` | `id`, `name` | | `EntityReference` | `id`, `name` | ### Game-Related Models | Struct | Fields | |--------|--------| | `Action` | `name`, `path`, `arguments`, `working_directory`, `is_primary`, `sort_order`, `variables` | | `MediaRef` | `id`, `type`, `crc32`, `file_id` | | `Media` | `id`, `type` (enum), `file_id`, `crc32`, `source_url` | | `MultiplayerMode` | `type`, `network_protocol`, `min_players`, `max_players`, `spectators` | | `GameCustomField` | `name`, `value` | | `GameExternalId` | `provider`, `external_id` | | `Redistributable` | `id`, `name`, `description` | | `Script` | `type` (enum), `name`, `contents` | | `GameSave` | `id`, `game_id`, `created_on`, `updated_on` | | `PlaySession` | `id`, `start`, `end`, `game_id`, `user_id` | ### Other Models | Struct | Fields | |--------|--------| | `AuthToken` | `access_token`, `refresh_token`, `expiration` | | `AuthenticationProvider` | `name`, `type` | | `User` | `id`, `user_name`, `alias` | | `Key` | `value`, `game_id` | | `Lobby` | `id`, `game_id`, `external_game_id`, `external_username` | | `Page` | `id`, `title`, `slug`, `route`, `contents`, `sort_order` | | `Package` | `path`, `version`, `changelog` | | `Issue` | `description`, `game_id` | | `CheckForUpdateResponse` | `update_available`, `version`, `download_url` | | `ErrorResponse` | `error`, `message`, `details` (vector of `ErrorInfo`) | | `DiscoveredServer` | `address`, `name`, `version` | | `ServerDetail` | `id`, `name`, `path`, `host`, `port`, `autostart`, `scripts`, etc. | ### Enums | Enum | Values | |------|--------| | `GameType` | `MainGame`, `Expansion`, `StandaloneExpansion`, `Mod`, `StandaloneMod` | | `MediaType` | `Icon`, `Cover`, `Background`, `Avatar`, `Logo`, `Manual`, `Thumbnail`, `PageImage`, `Grid`, `Screenshot`, `Video` | | `ScriptType` | `Install`, `Uninstall`, `NameChange`, `KeyChange`, `SaveUpload`, `SaveDownload`, `DetectInstall`, `BeforeStart`, `AfterStop`, `GameStarted`, `GameStopped`, `UserRegistration`, `UserLogin`, `ApplicationStart`, `Package`, `RunWrapper`, `Unknown` | | `MultiplayerType` | `Local`, `LAN`, `Online` | | `NetworkProtocol` | `TCPIP`, `IPX`, `Modem`, `Serial`, `Lobby` | | `ProcessTerminationMethod` | `Close`, `Kill`, `SIGHUP`, `SIGINT`, `SIGKILL`, `SIGTERM` | | `ServerAutostartMethod` | `OnApplicationStart`, `OnPlayerActivity` | | `ServerConsoleType` | `LogFile`, `RCON` |