Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions 3rdparty/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
| [Protobuf](https://github.com/protocolbuffers/protobuf) | | vcpkg baseline |
| [arknet](https://github.com/OpenArkStudio/arknet) | | v0.1.0 |
| [RapidXML](https://rapidxml.sourceforge.net/) | | 1.13 |
| [toml++](https://github.com/marzer/tomlplusplus) (application manifests, MIT) | | v3.4.0 fallback |
| [args](https://github.com/Taywee/args/releases/tag/6.2.2) | | 6.2.2 |
| [spdlog](https://github.com/gabime/spdlog/releases/tag/v1.17.0) | v1.x | v1.17.0 |
| [json](https://github.com/nlohmann/json/releases/download/v3.9.1/json.hpp) | v3.9.1 | |
Expand All @@ -20,3 +21,30 @@ arknet is maintained in its own repository and acquired by CMake at the release
tag. RapidXML is supplied by the package manager; the unavailable ArkNX fork is
no longer a submodule. The vcpkg manifest pins the package baseline. See
[network builds and regression tests](../docs/networking.md).

The optional `ark::config` target privately uses toml++ under its
[MIT license](https://github.com/marzer/tomlplusplus/blob/v3.4.0/LICENSE).
CMake prefers an installed `tomlplusplus` 3.4+ package and otherwise fetches commit
`30172438cee64926dc41fdd9c11fb3ba5b2ba9de` (v3.4.0); no parser source is vendored.
See [application manifests](../docs/service-manifests.md) for the configuration API.

### toml++ license notice

```text
MIT License

Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ endif()
option(ARK_BUILD_TESTS "Enable build tests" ON)
option(ARK_BUILD_CORE_TESTS "Build core C++20 regressions" ${ARK_BUILD_TESTS})
option(ARK_BUILD_EXAMPLES "Enable build examples" ON)
set(ark_config_default OFF)
if(ARK_BUILD_APPLICATIONS OR ARK_BUILD_CORE_TESTS)
set(ark_config_default ON)
endif()
option(ARK_BUILD_CONFIG "Build the application manifest reader" ${ark_config_default})
if(ARK_BUILD_APPLICATIONS AND NOT ARK_BUILD_CONFIG)
message(FATAL_ERROR "ARK_BUILD_APPLICATIONS requires ARK_BUILD_CONFIG")
endif()

#---------------------------------------------------------------------------------------
# project switches
Expand Down Expand Up @@ -201,6 +209,10 @@ endif()

find_path(RAPIDXML_INCLUDE_DIR rapidxml.hpp PATH_SUFFIXES rapidxml REQUIRED)

if(ARK_BUILD_CONFIG)
add_subdirectory(src/config)
endif()

add_library(ark_core INTERFACE)
add_library(ark::core ALIAS ark_core)
target_compile_features(ark_core INTERFACE cxx_std_20)
Expand Down
10 changes: 10 additions & 0 deletions build/conf/sample1.app.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[application]
plugin_library_dir = "bin/"
plugin_config_dir = "conf/"

[[plugins]]
name = "AFUtilityPlugin"
config = ""

[[plugins]]
name = "Sample1Plugin"
39 changes: 29 additions & 10 deletions docs/guides/applications.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Application launcher

The `app` executable selects a process identity, reads an XML application manifest and loads its plugin libraries. Start with the runnable [Sample1 quick start](../get-started/quick-start.md); this page explains configuration paths, library names and startup checks.
The `app` executable selects a process identity, reads a TOML or XML application manifest and loads its plugin libraries. Start with the runnable [Sample1 quick start](../get-started/quick-start.md); this page explains configuration paths, library names and startup checks.

## Command-line arguments

| Argument | Required | Meaning |
| --- | --- | --- |
| `--busid` / `-b` | Yes | Logical process Bus address, such as `1.0.1.1`; this is not a socket bind address |
| `--name` / `-n` | Yes | Application name, also used in the log filename |
| `--app_conf` / `-a` | Yes | XML application manifest; use a `*.app.conf` filename |
| `--app_conf` / `-a` | Yes | TOML application manifest with the lowercase `.toml` extension, or a legacy XML `*.app.conf` file |
| `--log_conf` / `-l` | No | Logger configuration; defaults to `./conf/log.conf` |
| `--help` / `-h` | No | Print the launcher's argument reference |

Expand All @@ -29,13 +29,31 @@ Relative paths resolve from the process working directory. Moving the executable
| --- | --- | --- |
| Application manifest | `--app_conf` | `conf/sample1.app.conf` |
| Logger settings | `--log_conf`, or its default | `conf/log.conf` |
| Plugin libraries | `plugin_lib_dir` plus the library filename | `bin/Sample1Plugin.dylib` on macOS Release |
| Per-plugin settings | `plugin_conf_dir` plus that plugin's `conf` value | `conf/my-plugin.conf` when `conf="my-plugin.conf"` |
| Plugin libraries | TOML `plugin_library_dir` or XML `plugin_lib_dir`, plus the library filename | `bin/Sample1Plugin.dylib` on macOS Release |
| Per-plugin settings | TOML `plugin_config_dir` + `config`, or XML `plugin_conf_dir` + `conf` | `conf/my-plugin.conf` when the filename is `my-plugin.conf` |
| Kernel metadata and configuration | The Kernel's `resource/` directory | `resource/meta/entity_class.config`, `resource/server/item.config` |

The launcher passes the per-plugin path to the plugin manager; each module decides how to read its own configuration. Kernel resource paths are separate from the application manifest and are needed only by applications that use those Kernel facilities. See [Data-driven configuration](../concepts/data-driven.md) and [Configuration tools](tools.md).

## Select plugins with XML
## Select plugins

For a new manifest, use TOML. The equivalent of Sample1's XML configuration is checked in as [sample1.app.toml](https://github.com/OpenArkStudio/ark/blob/main/build/conf/sample1.app.toml):

```toml
[application]
plugin_library_dir = "bin/"
plugin_config_dir = "conf/"

[[plugins]]
name = "AFUtilityPlugin"

[[plugins]]
name = "Sample1Plugin"
```

Pass `--app_conf=conf/sample1.app.toml` to select it. The application table is required; directory fields are optional strings. Each plugin requires a unique, nonempty `name`; its optional `config` string selects a per-plugin file. See [Application manifests](../service-manifests.md) for validation rules and format boundaries. Bus, logger and business-resource configuration formats are unchanged.

### Existing XML manifests

The checked-in [Sample1 manifest](https://github.com/OpenArkStudio/ark/blob/main/build/conf/sample1.app.conf) loads a utility plugin and one sample plugin:

Expand All @@ -53,17 +71,17 @@ The checked-in [Sample1 manifest](https://github.com/OpenArkStudio/ark/blob/main
- Use the library stem in `name`, without a platform suffix or a `lib` prefix. The loader appends `.dll`, `.so` or `.dylib`; Debug builds also append `_d` before the suffix.
- An empty `conf` value supplies no per-plugin filename. Sample1 does not need a separate `sample1.conf` file.

Copy the executable and selected plugin libraries from the same build. Keep Debug and Release artifacts in separate runtime directories. The XML list is not a dependency-order contract: modules should resolve their dependencies through the [module API](modules.md), rather than rely on entry order.
Copy the executable and selected plugin libraries from the same build. Keep Debug and Release artifacts in separate runtime directories. The plugin list is not a dependency-order contract: modules should resolve their dependencies through the [module API](modules.md), rather than rely on entry order.

## Check startup and stop the process

For Sample1, look for a log entry containing `sample1_module` and `PostInit`. This identifies entry into the sample's post-initialization callback, which registers its timer. A `LoadPlugin` message alone only identifies a library the loader is attempting to use.
For Sample1, look for a log entry containing `sample1_module` and `PostInit`. This identifies entry into the sample's post-initialization callback, which registers its timer.

On macOS/Linux, Ctrl+C or `SIGTERM` requests shutdown through the application's main loop. On Windows, enter `exit` in the application console. Sample1 logs `PreShut` and then `Shut` during orderly shutdown. This sample check is not a readiness or shutdown guarantee for every plugin combination.

<Aside type="caution" title="Do not use process survival as the readiness check">

The current launcher can return exit code `0` for argument or manifest failures, and it does not aggregate every plugin/module startup result. Check the expected module's initialization log and application-specific readiness before routing traffic to a process. A running PID or a zero exit status alone is insufficient.
Manifest loading or validation failures return exit code `1` before plugin startup. Argument parsing failures, including help handling, still return `0`, and the launcher does not aggregate every plugin/module startup result. Check the expected module's initialization log and application-specific readiness before routing traffic to a process. A running PID or a zero exit status alone is insufficient.

</Aside>

Expand All @@ -72,8 +90,9 @@ The current launcher can return exit code `0` for argument or manifest failures,
| Symptom | Check |
| --- | --- |
| Usage text or `Application parameter is invalid` | Supply all three required arguments; check spelling with `--help` |
| Manifest or logger configuration cannot be read | Check the working directory and both explicit paths; keep the `*.app.conf` naming convention |
| `Load shared library[...] failed` | Check `plugin_lib_dir`, platform suffix, Debug suffix and the library's dependent shared libraries |
| Manifest loading fails | Check the working directory, explicit path and format; a lowercase `.toml` suffix selects TOML, while legacy `*.app.conf` files use XML |
| Logger configuration cannot be read | Check the working directory and `--log_conf` path |
| `Load shared library[...] failed` | Check TOML `plugin_library_dir` or XML `plugin_lib_dir`, platform suffix, Debug suffix and the library's dependent shared libraries |
| Plugin loads but the expected module is unavailable | Check registration, enabled targets and required plugins; see [Create a plugin](plugins.md) |
| Kernel metadata or configuration is missing | Stage the generated `resource/meta/` and `resource/server/` files in the process working directory |

Expand Down
39 changes: 29 additions & 10 deletions docs/guides/applications_CN.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# 应用启动器

`app` 程序设置进程标识、读取 XML 应用配置,并加载所选插件的动态库。首次运行可先按 [Sample1 快速开始](../get-started/quick-start_CN.md)操作;本文说明配置路径、动态库命名和启动检查。
`app` 程序设置进程标识、读取 TOML 或 XML 应用配置,并加载所选插件的动态库。首次运行可先按 [Sample1 快速开始](../get-started/quick-start_CN.md)操作;本文说明配置路径、动态库命名和启动检查。

## 命令行参数

| 参数 | 必填 | 含义 |
| --- | --- | --- |
| `--busid` / `-b` | 是 | 进程的逻辑 Bus 地址,例如 `1.0.1.1`;不是 socket 绑定地址 |
| `--name` / `-n` | 是 | 应用名称,也用于日志文件名 |
| `--app_conf` / `-a` | 是 | XML 应用配置,文件名使用 `*.app.conf` |
| `--app_conf` / `-a` | 是 | 扩展名为小写 `.toml` 的 TOML 应用配置,或旧版 XML `*.app.conf` 文件 |
| `--log_conf` / `-l` | 否 | 日志配置,默认为 `./conf/log.conf` |
| `--help` / `-h` | 否 | 输出启动器的参数说明 |

Expand All @@ -29,13 +29,31 @@
| --- | --- | --- |
| 应用配置 | `--app_conf` | `conf/sample1.app.conf` |
| 日志配置 | `--log_conf`,或使用默认值 | `conf/log.conf` |
| 插件动态库 | `plugin_lib_dir` 加动态库文件名 | macOS Release 使用 `bin/Sample1Plugin.dylib` |
| 插件配置 | `plugin_conf_dir` 加对应插件的 `conf` 值 | `conf="my-plugin.conf"` 时为 `conf/my-plugin.conf` |
| 插件动态库 | TOML `plugin_library_dir` 或 XML `plugin_lib_dir` 加动态库文件名 | macOS Release 使用 `bin/Sample1Plugin.dylib` |
| 插件配置 | TOML `plugin_config_dir` + `config`,或 XML `plugin_conf_dir` + `conf` | 配置文件名为 `my-plugin.conf` 时,对应 `conf/my-plugin.conf` |
| Kernel 元数据和配置 | Kernel 使用的 `resource/` 目录 | `resource/meta/entity_class.config`、`resource/server/item.config` |

启动器把插件配置路径交给插件管理器,具体模块自行读取配置。Kernel 资源路径与应用配置路径相互独立,只有使用相关 Kernel 能力的应用才需要这些资源。详见[数据驱动配置](../concepts/data-driven_CN.md)和[配置工具](tools_CN.md)。

## 使用 XML 选择插件
## 选择插件

新建应用配置可使用 TOML。仓库中的 [sample1.app.toml](https://github.com/OpenArkStudio/ark/blob/main/build/conf/sample1.app.toml) 与 Sample1 的 XML 配置等价:

```toml
[application]
plugin_library_dir = "bin/"
plugin_config_dir = "conf/"

[[plugins]]
name = "AFUtilityPlugin"

[[plugins]]
name = "Sample1Plugin"
```

通过 `--app_conf=conf/sample1.app.toml` 选择该文件。`application` 表必须存在,目录字段为可省略的字符串。每个插件的 `name` 必须非空且唯一;可选的 `config` 字符串指定插件配置文件。字段校验和格式边界见[应用配置清单](../service-manifests_CN.md)。Bus、日志和业务资源配置格式保持现有约定。

### 兼容已有 XML 配置

仓库中的 [Sample1 应用配置](https://github.com/OpenArkStudio/ark/blob/main/build/conf/sample1.app.conf)加载工具插件和一个示例插件:

Expand All @@ -53,17 +71,17 @@
- `name` 使用动态库名称主体,不加平台后缀,也不加 `lib` 前缀。加载器追加 `.dll`、`.so` 或 `.dylib`,Debug 构建还会在后缀前追加 `_d`。
- `conf` 为空表示没有提供插件配置文件名。Sample1 不需要单独的 `sample1.conf`。

程序和所选插件动态库应来自同一次构建,Debug 与 Release 文件分别放置。XML 条目顺序不代表依赖初始化顺序;模块应通过[模块 API](modules_CN.md)查找依赖。
程序和所选插件动态库应来自同一次构建,Debug 与 Release 文件分别放置。插件条目顺序不代表依赖初始化顺序;模块应通过[模块 API](modules_CN.md)查找依赖。

## 确认启动并停止进程

Sample1 的日志出现 `sample1_module` 和 `PostInit`,表示示例已经进入初始化后回调,该回调负责注册定时器。单独一条 `LoadPlugin` 日志只表示加载器正在尝试使用该动态库。
Sample1 的日志出现 `sample1_module` 和 `PostInit`,表示示例已经进入初始化后回调,该回调负责注册定时器。

macOS/Linux 可使用 Ctrl+C 或 `SIGTERM`,由应用主循环处理停止请求。Windows 在应用控制台输入 `exit`。正常停止时,Sample1 依次输出 `PreShut` 和 `Shut`。这个示例检查不代表所有插件组合都具备相同的就绪条件或停止保证。

<Aside type="caution" title="进程存在不等于应用就绪">

当前启动器的参数或应用配置错误可能返回退出码 `0`,也未汇总所有插件、模块的启动结果。接入流量前,应检查目标模块的初始化日志和应用自身的就绪条件,不能只判断 PID 存在或退出码为零。
应用配置读取或校验失败时,启动器会在启动插件前返回退出码 `1`。参数解析失败(包括帮助处理)仍返回 `0`,启动器也未汇总所有插件、模块的启动结果。接入流量前,应检查目标模块的初始化日志和应用自身的就绪条件,不能只判断 PID 存在或退出码为零。

</Aside>

Expand All @@ -72,8 +90,9 @@ macOS/Linux 可使用 Ctrl+C 或 `SIGTERM`,由应用主循环处理停止请
| 现象 | 检查项 |
| --- | --- |
| 输出帮助或 `Application parameter is invalid` | 补齐三个必填参数,用 `--help` 核对拼写 |
| 无法读取应用配置或日志配置 | 核对工作目录和两个配置路径,应用配置文件名使用 `*.app.conf` |
| `Load shared library[...] failed` | 核对 `plugin_lib_dir`、平台后缀、Debug 后缀,以及动态库自身的共享库依赖 |
| 应用配置加载失败 | 检查工作目录、显式路径和文件格式;小写 `.toml` 后缀选择 TOML,旧版 `*.app.conf` 使用 XML |
| 日志配置无法读取 | 检查工作目录和 `--log_conf` 路径 |
| `Load shared library[...] failed` | 核对 TOML `plugin_library_dir` 或 XML `plugin_lib_dir`、平台后缀、Debug 后缀,以及动态库自身的共享库依赖 |
| 插件已加载,但目标模块不存在 | 核对模块注册、启用的构建目标和依赖插件,详见[创建插件](plugins_CN.md) |
| Kernel 元数据或配置缺失 | 在进程工作目录准备生成的 `resource/meta/` 和 `resource/server/` 文件 |

Expand Down
Loading
Loading