Xmldef Compiler / Runtime MVP
Status: draft / implementation-structure spec.
本文把
xmldefPhase 1 的代码落点再明确一层:哪些模块属于 compiler toolchain,哪些属于 runtime descriptor 层,哪些属于 transport 集成层,哪些属于 Lua binding 编译层。目标是让后续实现不再围绕一个“大而杂的 xmldef codec”展开,而是按干净边界拆开。
如果需要看 Phase 1 范围和交付物,请先读 Xmldef Phase 1 Implementation Plan。如果需要看 descriptor 字段契约,请读 Xmldef Descriptor Spec。
Goal
Phase 1 的实现结构要保证四件事:
- XML 解释只发生在 toolchain,不发生在 runtime 热路径。
- runtime 只依赖 compiled descriptor,不依赖 XML 文件。
XmldefBodyCodec只负责 codec 语义,不兼管 binding、manifest、代码生成。- Lua handler 查找在启动时编译完成,运行时只做
route_id命中。
补充一点:这里的 XmldefBodyCodec 是“当前 Phase 1 方便落地的 runtime 适配名”,不代表 xmldef 只能绑定单一 native binary 表示。长期模型里,xmldef 更偏向 contract source / descriptor provider,后续可驱动多种 payload codec。
Layer Split
推荐拆成这四层:
xmldef xml
-> compiler toolchain
-> descriptor artifacts
-> runtime descriptor layer
-> transport/lua integration对应职责:
- compiler toolchain:读 manifest/XML、做语义校验、构建 canonical IR、输出 descriptor
- descriptor artifacts:
descriptor.debug.json、route_constants.json、manifest.json - runtime descriptor layer:加载 descriptor 并建立查询索引
- transport/lua integration:
XmldefBodyCodec、protocol pipeline adapter、Lua binding registry
Recommended Source Layout
基于仓库当前结构,推荐这样落:
tools/xmldef_compiler/
main.cpp
manifest_loader.hpp/.cpp
xml_loader.hpp/.cpp
semantic_validator.hpp/.cpp
canonical_ir.hpp/.cpp
descriptor_json_writer.hpp/.cpp
route_constants_writer.hpp/.cpp
manifest_writer.hpp/.cpp
include/shield/transport/xmldef/
descriptor_registry.hpp
schema_types.hpp
xmldef_codec.hpp
lua_binding_registry.hpp
src/transport/xmldef/
descriptor_registry.cpp
xmldef_codec.cpp
lua_binding_registry.cpp
tests/transport/
test_xmldef_descriptor_registry.cpp
test_xmldef_codec.cpp
test_xmldef_lua_binding_registry.cpp
tests/integration/
test_xmldef_gateway_flow.cppWhy Under transport
Phase 1 的 runtime xmldef 仍然服务于固定 protocol pipeline,因此建议先落在 shield_transport 子目录中。
但要注意:
- 这是 runtime 侧的 descriptor/codec/binding 层
- 不是 compiler toolchain
- 不是 Unity/U3D generator
toolchain 不应塞进 src/transport/。
Compiler MVP Modules
1. ManifestLoader
职责:
- 读取
protocol/manifest.xml - 解析 package metadata
- 收集 module 列表
- 产出“需要继续加载哪些 XML 文件”的稳定输入
不负责:
- schema 语义校验
- type/method 编号分配
- descriptor 输出
最小接口建议:
load_manifest(path) -> ManifestModel2. XmlLoader
职责:
- 加载 module XML
- 解析 message/type/enum/field 原始语法树
- 保留 source location 供错误报告使用
不负责:
- 业务语义判断
- ID 稳定性策略
最小接口建议:
load_modules(manifest) -> RawModuleAst[]3. SemanticValidator
职责:
- cross-file type resolution
- method/type/field/enum 唯一性检查
- direction/kind 合法性检查
- client-visible 引用边界检查
- reserved ID 冲突检查
这是 compiler MVP 的关键闸口。
任何不满足 descriptor 契约的 XML,都应在这里 fail fast。
最小接口建议:
validate(raw_modules) -> ValidatedSchemaModel4. CanonicalIrBuilder
职责:
- 生成稳定 module/type/method/route 记录
- 归一化
direction - 归一化
kind - 构建 type_ref 树
- 做 canonical sort
- 计算 hash 输入
这里产出的 IR,才是 writer 和 generator 的真正输入。
最小接口建议:
build_ir(validated_model) -> CanonicalPackage5. DescriptorJsonWriter
职责:
- 输出
descriptor.debug.json - 确保字段名、字段顺序和 shape 稳定
- 不丢失 generator/runtime 所需字段
这层不应再重新推导语义,只做 IR 序列化。
6. RouteConstantsWriter
职责:
- 从 canonical IR 输出简化 route 表
- 方便前端 generator、脚本工具和测试直接消费
7. ManifestWriter
职责:
- 输出 build artifact manifest
- 记录 package/version/hash/生成文件列表
它不属于 schema 语义本身,但属于 Phase 1 交付物的一部分。
Runtime MVP Modules
1. DescriptorRegistry
职责:
- 加载
descriptor.debug.json - 建立查询索引
- 提供 method/type/route lookup API
推荐内部索引:
route_id -> MethodDescriptorfull_name -> MethodDescriptortype_id -> TypeDescriptormethod_id -> MethodDescriptor
推荐最小接口:
load_descriptor(path) -> DescriptorRegistry
find_method_by_route(route_id)
find_method_by_name(full_name)
find_type(type_id)
find_request_type(route_id)
find_response_type(route_id)
find_binding_hint(route_id)DescriptorRegistry 不负责:
- Lua function 查找
- bytes encode/decode
- XML fallback
2. SchemaTypes
Phase 1 虽然只用 debug JSON,也仍建议把 runtime 内部 type model 单独抽出来,而不是直接把 JSON object 散传。
建议抽象:
TypeDescriptorStructDescriptorFieldDescriptorEnumDescriptorMethodDescriptorRouteDescriptorTypeRef
这样后续切换到 descriptor.bin 时,不需要改 XmldefBodyCodec 和 Lua binding 层接口。
3. XmldefBodyCodec
职责:
- 根据
route_id查 method schema - decode bytes -> structured business message
- encode business message -> bytes
它依赖:
DescriptorRegistryMethodDescriptorTypeDescriptor
它不负责:
- route policy
- route extraction
- Lua dispatch
- XML 文件读取
推荐内部拆成:
decode_scalardecode_enumdecode_structdecode_listencode_scalarencode_enumencode_structencode_list
这样后续补 map 时可以自然扩展。
4. LuaBindingRegistry
职责:
- 读取 Lua service 暴露的 binding table
- 对照 descriptor methods 做启动期校验
- 编译出
route_id -> cached lua function
推荐接口:
compile_bindings(descriptor_registry, lua_module) -> LuaBindingRegistry
find_handler(route_id) -> cached_function运行时 dispatch 应只做:
route_id -> cached_function不应做:
full_name字符串查找- 每包反射式
module[handler_name] - 动态猜函数名
Transport Integration
xmldef 接入固定 protocol pipeline 的方式应该非常窄:
Envelope
-> RouteExtractor
-> RoutePolicy
-> XmldefBodyCodec.decode
-> LuaBindingRegistry dispatch出站:
Lua business message
-> RouteResolver
-> XmldefBodyCodec.encode
-> Envelope这部分意味着 xmldef runtime 只需要对 BodyCodec 槽位和 Lua dispatch 槽位负责。
它不应重新定义一套 gateway middleware。
Startup Order
Phase 1 推荐启动顺序:
- 读取
descriptor.debug.json - 构建
DescriptorRegistry - 初始化
XmldefBodyCodec - 加载 Lua gateway service module
- 编译
LuaBindingRegistry - 验证所有 required binding
- 开始接收客户端流量
关键点是:
- descriptor 要先于 Lua binding 编译
- Lua binding 要先于 session 收包
- binding 缺失属于启动失败,不属于运行时弱告警
Validation Split
必须区分两类错误:
Compiler-time Errors
- route/type/field/enum ID 冲突
- type 引用不存在
- direction/kind 非法
- client-visible 引用 server-only
这些错误属于 schema 契约错误,必须由 compiler 报。
Startup-time Errors
- descriptor 文件缺失
- descriptor 文件格式版本不兼容
- Lua binding 缺失
- binding 指向不存在函数
这些错误属于部署/接线错误,必须在 runtime startup 报。
Runtime Errors
- decode bytes 失败
- enum value 非法
- required field 缺失
- egress message shape 不匹配 schema
这些错误属于请求级错误,必须作为 transport/protocol 错误返回或记录。
Test Split
测试建议按层拆,不要只做一条大集成测试:
Compiler Tests
- manifest load
- module load
- semantic validation fail cases
- canonical ordering stability
descriptor.debug.jsongolden tests
Runtime Unit Tests
DescriptorRegistrylookupXmldefBodyCodecscalar/enum/struct/list encode/decodeLuaBindingRegistrycompile/validation
Integration Tests
- protocol pipeline ingress decode-local -> Lua handler
- Lua s2c helper -> xmldef encode -> envelope(route_id 只来自 descriptor,不从 body 推断)
- binding 缺失导致启动失败
Phase 1 Non-goals
这篇文档不要求 Phase 1 直接做这些事情:
descriptor.binruntime load- Unity/U3D generator 实现
- Unreal/TS generator
- XML hot reload
- schema patch / diff
- entity/component runtime
这些要么属于后续 phase,要么属于独立 tooling plugin。