mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-07 17:52:07 -04:00
Add HostService.data_dir
This commit is contained in:
+16
-8
@@ -209,8 +209,8 @@ if (svc_resource->load(mod_ctx, "config.txt", &buf) == MOD_OK) {
|
||||
}
|
||||
```
|
||||
|
||||
Missing files return `MOD_UNAVAILABLE`. Always `free` what you `load`. Note that the bundle is read-only; for writable
|
||||
storage, use the directory from `svc_host->mod_dir(mod_ctx)`.
|
||||
Missing files return `MOD_UNAVAILABLE`. Always `free` what you `load`. The bundle is read-only; use
|
||||
`HostService::data_dir` for persistent storage.
|
||||
|
||||
### HostService (`mods/svc/host.h`)
|
||||
|
||||
@@ -219,9 +219,17 @@ Mod metadata and runtime interaction with the loader:
|
||||
```cpp
|
||||
IMPORT_SERVICE(HostService, svc_host);
|
||||
|
||||
const char* id = svc_host->mod_id(mod_ctx);
|
||||
const char* dir = svc_host->mod_dir(mod_ctx); // writable per-mod directory
|
||||
svc_host->fail(mod_ctx, MOD_ERROR, "something unrecoverable happened"); // disables the mod
|
||||
// Temporary mod data directory, wiped on startup
|
||||
const char* cacheDir = svc_host->mod_dir(mod_ctx);
|
||||
|
||||
// Persistent mod data directory
|
||||
const char* dataDir = nullptr;
|
||||
if (svc_host->data_dir(mod_ctx, &dataDir) == MOD_OK) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// Report an error and disable the mod
|
||||
svc_host->fail(mod_ctx, MOD_ERROR, "something unrecoverable happened");
|
||||
```
|
||||
|
||||
`get_service`/`publish_service` provide dynamic service lookup; see [Exporting Services](#exporting-services).
|
||||
@@ -927,6 +935,6 @@ const char* nativeDir = svc_host->native_dir(mod_ctx); // read-only
|
||||
```
|
||||
|
||||
Libraries loaded explicitly by the mod remain its responsibility: stop their threads and unload them during
|
||||
`mod_shutdown`. Do not write into `native_dir`; use `mod_dir` for writable state. Native library namespaces are
|
||||
process-wide on some platforms, so two mods cannot safely assume that incompatible libraries with the same filename
|
||||
will remain isolated.
|
||||
`mod_shutdown`. Do not write into `native_dir`; use `data_dir` for persistent storage or `mod_dir` for temporary
|
||||
(session) storage. Native library namespaces are process-wide on some platforms, so two mods cannot safely assume that
|
||||
incompatible libraries with the same filename will remain isolated.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#define HOST_SERVICE_ID "dev.twilitrealm.dusklight.host"
|
||||
#define HOST_SERVICE_MAJOR 2u
|
||||
#define HOST_SERVICE_MINOR 1u
|
||||
#define HOST_SERVICE_MINOR 2u
|
||||
|
||||
/*
|
||||
* Ignore unknown values: later service minors may add events.
|
||||
@@ -96,15 +96,24 @@ typedef struct HostService {
|
||||
ModContext* ctx, ModLifecycleFn fn, void* user_data, uint64_t* out_handle);
|
||||
ModResult (*unwatch_mod_lifecycle)(ModContext* ctx, uint64_t handle);
|
||||
|
||||
/* Minor version 1 */
|
||||
|
||||
/*
|
||||
* Read-only directory containing this platform's packaged native runtime: the mod module
|
||||
* and any RUNTIME_LIBRARIES. The path is absolute and remains valid until mod_shutdown
|
||||
* returns. Libraries loaded dynamically from here are owned by the mod and must be unloaded
|
||||
* during mod_shutdown.
|
||||
*
|
||||
* Added in minor version 1.
|
||||
*/
|
||||
const char* (*native_dir)(ModContext* ctx);
|
||||
|
||||
/* Minor version 2 */
|
||||
|
||||
/*
|
||||
* A persistent writable directory reserved for the calling mod, created on first use.
|
||||
*
|
||||
* The returned path remains valid until mod_shutdown returns. *out_path is null on failure.
|
||||
*/
|
||||
ModResult (*data_dir)(ModContext* ctx, const char** out_path);
|
||||
} HostService;
|
||||
|
||||
MOD_DECLARE_SERVICE(HostService, svc_host, HOST_SERVICE_ID, HOST_SERVICE_MAJOR, HOST_SERVICE_MINOR);
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
/*
|
||||
* Read-only access to the res/ tree of the calling mod's own bundle. Reload serves the new
|
||||
* bundle's contents. For writable storage, use HostService::mod_dir.
|
||||
* bundle's contents. Use HostService::data_dir for persistent storage or HostService::mod_dir
|
||||
* for temporary storage.
|
||||
*/
|
||||
|
||||
#define RESOURCE_SERVICE_ID "dev.twilitrealm.dusklight.resource"
|
||||
|
||||
@@ -166,6 +166,8 @@ struct LoadedMod {
|
||||
std::filesystem::path dir;
|
||||
// Stable UTF-8 storage for HostService::mod_dir.
|
||||
std::string dirUtf8;
|
||||
// Stable UTF-8 storage for HostService::data_dir.
|
||||
std::string dataDirUtf8;
|
||||
|
||||
uint32_t searchDirIndex = 0;
|
||||
// Native lib is dlopen'd in place and stays resident for the session. Reload is unsupported.
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#include "registry.hpp"
|
||||
#include "slot_map.hpp"
|
||||
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/mods/loader/loader.hpp"
|
||||
#include "dusk/mods/log_buffer.hpp"
|
||||
#include "dusk/mods/manifest.hpp"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <borealis/io.hpp>
|
||||
#include <borealis/version.h>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace dusk::mods::svc {
|
||||
namespace {
|
||||
@@ -68,6 +72,41 @@ const char* host_native_dir(ModContext* context) {
|
||||
return mod != nullptr ? mod->nativeDirUtf8.c_str() : "";
|
||||
}
|
||||
|
||||
ModResult host_data_dir(ModContext* context, const char** outPath) {
|
||||
if (outPath == nullptr) {
|
||||
return MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
*outPath = nullptr;
|
||||
|
||||
auto* mod = mod_from_context(context);
|
||||
if (mod == nullptr) {
|
||||
return MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (mod->dataDirUtf8.empty()) {
|
||||
namespace fs = std::filesystem;
|
||||
std::error_code ec;
|
||||
const fs::path path = fs::absolute(dusk::ConfigPath / "mod_data" / mod->metadata.id, ec);
|
||||
if (ec) {
|
||||
log::write(mod->metadata.id, LOG_LEVEL_ERROR,
|
||||
"failed to resolve persistent mod data directory: {}", ec.message());
|
||||
return MOD_ERROR;
|
||||
}
|
||||
|
||||
fs::create_directories(path, ec);
|
||||
if (ec) {
|
||||
log::write(mod->metadata.id, LOG_LEVEL_ERROR,
|
||||
"failed to create persistent mod data directory {}: {}",
|
||||
borealis::io::fs_path_to_string(path), ec.message());
|
||||
return MOD_ERROR;
|
||||
}
|
||||
mod->dataDirUtf8 = borealis::io::fs_path_to_string(path);
|
||||
}
|
||||
|
||||
*outPath = mod->dataDirUtf8.c_str();
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
struct LifecycleWatcher {
|
||||
ModLifecycleFn fn = nullptr;
|
||||
void* userData = nullptr;
|
||||
@@ -148,6 +187,7 @@ constinit HostService s_hostService{
|
||||
.watch_mod_lifecycle = host_watch_mod_lifecycle,
|
||||
.unwatch_mod_lifecycle = host_unwatch_mod_lifecycle,
|
||||
.native_dir = host_native_dir,
|
||||
.data_dir = host_data_dir,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user