Skip to content
tomlubePublic
forked from encounter/borealis

About

Borealis provides cross-platform modules for Aurora-based ports.

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

Borealis

Modules for Aurora-based ports. Borealis provides cross-platform logging, updates, crash reporting, an HTTP client, Discord rich presence, data directory handling, and more.

Supported platforms: Windows, Linux, Android, macOS, iOS and tvOS.

Modules

Target Contents Status
borealis::cli Standard options with cxxopts ✅
borealis::config ConfigVar system with JSON storage planned
borealis::core Shared utilities ✅
borealis::crash In-process crash handler with backtrace unwinding & logging ✅
borealis::data Data directory resolution, portable mode, data migration ✅
borealis::disc Disc inspection and hash verification ✅
borealis::discord Discord rich presence IPC client ✅
borealis::file_select Cross-platform file/folder selection ✅
borealis::http Asynchronous HTTPS client (HTTP/2, TLS 1.2+) ✅
borealis::io File I/O + paths, bookmarks (iOS), and document URIs (Android) ✅
borealis::log fmt-based logging + sinks (console, rotating file, logcat, ring buffer) ✅
borealis::net TCP, UDP, and asynchronous DNS ✅
borealis::presentation Android frame-rate configuration ✅
borealis::sentry Optional sentry-native/crashpad integration and consent state ✅
borealis::task Shared async task pool with cancellation and progress ✅
borealis::ui RmlUi UI framework, document system, and shared components ✅
borealis::update Update checks via GitHub releases ✅
borealis::ws WebSocket client over HTTPS ✅

Borealis also provides an Android platform layer that integrates SDL, Aurora and provides Java-side support for Borealis modules.

Usage

Add borealis as a submodule alongside aurora and link the targets you use:

add_subdirectory(extern/borealis EXCLUDE_FROM_ALL)
target_link_libraries(mygame PRIVATE borealis::log)

Logging

#include <borealis/log.hpp>

namespace {
constexpr borealis::Log Log{"mygame::data"};
}

Log.info("Loaded {}", path);
Log.fatal("Unrecoverable: {}", err);  // flushes all sinks, then Options::onFatal

Initialize once at startup, before aurora_initialize:

borealis::log::init({
    .level = borealis::LogLevel::Info,
    .fileDirectory = cachePath / "logs",
    .filePrefix = "mygame",
});
config.logCallback = borealis::log::aurora_callback();

C code (e.g. OSReport shims) may use the printf-style bridge in <borealis/log_c.h>.

Application identity

Define borealis::AppInfo for modules that need application identity. Version and build strings come from the generated <borealis/version.h>.

inline constexpr borealis::AppInfo AppInfo{
    .orgName = "Twilit Realm",
    .appName = "Dusklight",
    .githubOwner = "TwilitRealm",
    .githubRepo = "dusklight",
    .discordApplicationId = "1495632471994405035",
};

HTTP and update checks

borealis::http provides pollable asynchronous HTTPS requests using WinHTTP on Windows, NSURLSession on Apple, libcurl on Linux or OkHttp on Android. The shared worker pool starts lazily, grows on demand, and releases idle threads automatically. Call borealis::shutdown() during application shutdown to cancel and drain outstanding work.

Asynchronous operations return a Task<T>. Poll with ready() or try_take(), request cancellation with cancel() and use map() to transform results.

auto check = borealis::update::start_latest_github_release_check(AppInfo);
// Poll from the main loop.
if (auto result = check.try_take();
    result && result->status == borealis::update::Status::UpdateAvailable) {
    show_update_prompt(result->latest.tagName, result->latest.htmlUrl);
}

Status::Disabled indicates the build was compiled without an available HTTP backend.

TCP, UDP, and DNS

borealis::net provides non-blocking TCP clients and listeners, UDP sockets, and asynchronous DNS. A Context manages its sockets and event queue, which can be polled from any thread.

#include <borealis/net.hpp>

borealis::net::Context network;
const auto stream = network.connect("tcp://127.0.0.1:34197");

borealis::net::Event event;
while (network.poll(event)) {
    if (event.id == stream && event.kind == borealis::net::Event::Kind::StreamData) {
        consume(event.id, event.data);
    }
}

Endpoints use tcp://host:port or udp://host:port.

WebSocket connections

borealis::ws provides asynchronous WebSocket client connections. Poll each connection for Open, Message, and Closed events.

#include <borealis/ws.hpp>

auto connection = borealis::ws::connect({
    .url = "wss://example.com/events",
    .protocols = {"events.v1"},
});

borealis::ws::Event event;
while (connection.poll(event)) {
    if (event.kind == borealis::ws::Event::Kind::Message) {
        consume(event.messageKind, event.data);
    }
}

Only wss:// is accepted by default.

Data directories

Create a borealis::data::Manager with the application identity, portable path, legacy identities, and files eligible for migration:

borealis::data::Manager dataManager{AppInfo, {
    .portableRelativePath = std::filesystem::path{"data"},
    .legacyApps = {
        {
            .orgName = "OldOrgName",
            .appName = "OldAppName",
        },
    },
    .migration = {
        .directories = {"saves", "texture_replacements"},
        .files = {"config.json"},
        .extensions = {".gci"},
    },
}};

const auto status = dataManager.initialize(userDirectoryOverride);
const auto& paths = dataManager.paths();

Disc inspection and verification

borealis::disc inspects and verifies GameCube and Wii disc images.

constexpr std::array AcceptedDiscs{
    borealis::disc::AcceptedDisc{
        .gameId = "GZ2E01",
        .expectedHash = borealis::disc::parse_xxh3_128("14e886f08e548a000afde98a3195e788"),
    },
};
constexpr std::array<std::string_view, 1> RecognizedGameIds{"RZDE01"};

borealis::disc::Progress progress;
const borealis::disc::Result result = borealis::disc::verify(path,
    {.acceptedDiscs = AcceptedDiscs, .recognizedGameIds = RecognizedGameIds}, &progress);

Game ID, disc number, and revision must match an accepted record. IDs in another record or recognizedGameIds return UnsupportedVersion; other IDs return UnknownGame.

Verification uses XXH3-128. Progress can be polled or canceled from another thread.

Crash unwinding and logging

Install the crash handler once, after logging is initialized:

#include <borealis/crash.hpp>

borealis::log::init(logOptions);
borealis::crash::install();

Reports are written to stderr and the active log file. They include build identity, fault address, module build IDs, and relative virtual addresses for symbolication.

Sentry crash reporting

Set BOREALIS_ENABLE_SENTRY=ON to include sentry-native/crashpad. The DSN and environment are build inputs: BOREALIS_SENTRY_DSN and BOREALIS_SENTRY_ENVIRONMENT. At runtime, BOREALIS_SENTRY_ENABLED, BOREALIS_SENTRY_DSN, and BOREALIS_SENTRY_DEBUG can be used as overrides.

borealis::sentry::Options options{
    .release = std::string(AppInfo.appName) + "@" + BOREALIS_APP_DESCRIBE,
    .databaseDirectory = cachePath / "sentry",
};
if (const char* logPath = borealis::log::file_path()) {
    options.attachments.emplace_back(logPath);
}
borealis::sentry::initialize(options);

Reports require user consent through get_consent() and set_consent(). Call shutdown() before shutting down logging.

Discord Rich Presence

borealis::discord uses Discord's local IPC protocol. Set the application ID in AppInfo:

borealis::discord::initialize(AppInfo, handlers);
borealis::discord::update_presence({
    .details = "Ordon Village",
    .largeImageKey = "icon",
    .largeImageText = std::string(AppInfo.appName),
});

Call run_callbacks() from the main loop and shutdown() during application teardown.

License

Borealis is licensed under the MIT License.

About

Borealis provides cross-platform modules for Aurora-based ports.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages