FEATURED · 精选文章

【Eclipse OpenSOVD学习之八】 路由与处理器

发布时间 / 2026/9/11 19:23:44
来源 / 创域科博编辑部
栏目 / 资讯中心
【Eclipse OpenSOVD学习之八】 路由与处理器 07. 路由与处理器1. 背景与原理1.1 SOVD 路由的层次SOVD API 分三层/sovd/version-info 版本发现不在 /v1 下因为发现必须先于版本化访问 /sovd/v1/ 根能力 /sovd/v1/{collection} 实体集合 单个实体能力 /sovd/v1/{collection}/{id}/{relation} 关系hosts / belongs-to / is-located-on / contains /sovd/v1/{collection}/{id}/data[/...] 数据资源1.2 三个设计约束一致性快照一次请求内可能多次查拓扑例如先确认 component 存在再取其 apps必须落在同一快照否则会返回不一致的结果。能力即存在性只有当实体确实拥有某能力如挂了 DataProvider、有 area_id时才在 capabilities 中给出对应 href。统一错误格式所有错误必须是GenericError且内部错误细节不能外泄。2. 当前实现架构2.1 路由表opensovd-server/src/routes/方法路径Handler位置GET/v1/root_capabilitiesentities/mod.rs:49GET/v1/componentscomponent_listentities/component.rs:40GET/v1/components/{id}component_capabilitiesentities/component.rs:75GET/v1/components/{id}/hostscomponent_hostsentities/component.rs:132GET/v1/components/{id}/belongs-tocomponent_belongs_toentities/component.rs:173GET/v1/appsapp_listentities/app.rs:37GET/v1/apps/{id}app_capabilitiesentities/app.rs:73GET/v1/apps/{id}/is-located-onapp_is_located_onentities/app.rs:118GET/v1/apps/{id}/belongs-toapp_belongs_toentities/app.rs:151GET/v1/areasarea_listentities/area.rs:36GET/v1/areas/{id}area_capabilitiesentities/area.rs:72GET/v1/areas/{id}/containsarea_containsentities/area.rs:105GET/v1/{components,apps}/{id}/data-categories*_data_categoriesdata.rs:67 / 245GET/v1/{components,apps}/{id}/data-groups*_data_groupsdata.rs:98 / 276GET/v1/{components,apps}/{id}/data*_data_listdata.rs:160 / 316GET/v1/{components,apps}/{id}/data/{data_id}*_data_readdata.rs:199 / 355PUT/v1/{components,apps}/{id}/data/{data_id}*_data_writedata.rs:225 / 381GET/version-infoversion_infoversion.rs:30共23 条路由。注意实体路由全是 GET无增删改——拓扑变更只能通过代码注入或 DiscoveryProvider见 04 章。2.2 应用状态与提取#[derive(Clone)] pub struct AppStateV { pub vendor_info: OptionV, pub topology: Topology } implV FromRefAppStateV for Topology { fn from_ref(state: AppStateV) - Topology { state.topology.clone() } }借助FromRefhandler 可直接写State(topology): StateTopology无需接触整个AppState。3. 核心流程与算法3.1 Handler 统一骨架10 个数据 handler 完全同构let topo topology.read().await; // ① 取读锁 let entity topo.get_component(component_id) // ② 查实体 .map_err(|_| Error::EntityNotFound(component_id.clone()))?; let provider entity.data_provider() // ③ 取 provider .ok_or_else(|| Error::ProviderNotAvailable(data.into()))?; let items provider.categories().await?; // ④ await 业务 Ok(Json(Response { data: ..., schema: ... })) // ⑤ 封装响应关键点topoTopologyReadGuard的生命周期跨越了第 ④ 步的.await——见 §4.1 缺陷 1。3.2 查询参数解析与过滤映射SOVD 采用form style、explodetrue的重复键语义?groupsagroupsbtagsx。pub struct DataQuery { pub groups: OptionVecString, pub categories: OptionVecString, pub tags: OptionVecString, #[serde(default, rename include-schema)] pub include_schema: bool, }映射算法fn data_filter(query: DataQuery) - DataFilter { let groups query.groups.unwrap_or_default(); let categories query.categories.unwrap_or_default(); let scope if !groups.is_empty() { Some(DataScope::Groups(groups)) } else if !categories.is_empty() { Some(DataScope::Categories(categories)) } else { None }; DataFilter { scope, tags: query.tags.unwrap_or_default() } }groups 优先categories 被静默丢弃。提取器使用WithRejectionQueryDataQuery, Error解析失败 →Error::BadQuery→ 400 incomplete-request。3.3 百分号编码算法路径段必须严格按 RFC 3986 编码实体 ID 允许任意字符串constPATH_SEGMENT_ENCODE_SET:AsciiSetCONTROLS.add(b ).add(b).add(b#).add(b).add(b).add(b?).add(b).add(b{).add(b}).add(b/).add(b%).add(b).add(b);// 示意实际以源码为准fnencode_path_segment(s:str)-String{utf8_percent_encode(s,PATH_SEGMENT_ENCODE_SET).to_string()}自定义AsciiSet而非percent_encoding预设集是为了精确控制哪些字符需要转义保留-._~等未保留字符。3.4 集合列举与 tags 过滤let items: VecEntityReference components .filter(|e| { let tags e.tags(); query.tags.is_empty() || query.tags.iter().any(|t| tags.contains(t)) // OR 语义 }) .map(|e| EntityReference { id, name, translation_id, href, tags }) .collect();3.5 错误映射算法| 变体 | HTTP | error_code | vendor_code | | EntityNotFound(id) | 404 | vendor-specific | entity-not-found | | ProviderNotAvailable(p) | 404 | vendor-specific | provider-not-available | | Data(NotFound) | 404 | error-response | — | | Data(ReadOnly) | 400 | error-response | — | | Data(Internal) | 500 | error-response | 消息脱敏 | | BadQuery | 400 | incomplete-request | — | | Topology(NotFound) | 404 | error-response | — |内部错误脱敏let message match e { DataError::Internal(msg) { tracing::error!(target: srv, error %msg, Internal error); An internal error occurred.to_string() } _ e.to_string(), };3.6 Schema 惰性生成schema:query.include_schema.then(EntityCapabilities::schema)bool::then(f)—— 只有include_schematrue时才调用惰性避免所有请求都付出 schema 生成成本。4. 待完善与风险4.1 并发与性能严重读锁跨await高所有 handler 在provider.read/list/write期间一直持有TopologyReadGuard。后果慢 provider例如转发到 UDS 的请求可能数十毫秒到秒级会阻塞所有拓扑写入者发现事件、运行时变更锁持有时间 整个请求耗时吞吐受限于最慢的 provider修复建议先取锁拿到 provider 的克隆、立即放锁、再 await。当前阻碍是data_provider: OptionBoxdyn DataProvider不可 cheap clone见 03 章 §4.2 缺陷 5——把Box改为Arc即可解锁此优化。这是全项目收益最高的单点优化。include-schema每次重算schema_for!中data.rs:192/348在请求路径上生成 schema未缓存。schema 是静态的应 lazy static 缓存。4.2 语义正确性中groups 与 categories 同时传参被静默吞掉中应 400 incomplete-request否则客户端误判。写请求体无WithRejection中PUT的Json(body)解析失败时返回 axum 默认纯文本 400破坏 SOVD 统一错误格式与读路径的WithRejectionQuery..不一致。DataCategory::Custom()低?category空值会变成Custom()data-groups静默返回空列表而非 400。errors字段恒为None低ReadResponse.errors从未填充部分成功/部分失败的语义未实现。4.3 信息丢失中list端点丢弃每个 item 的 schema中include_schema时返回的是响应信封ItemsMetadata的 schema而每个数据项自己的 schema 被丢弃映射时未带m.schema。客户端无法知道每项数据的结构。is_readable/is_writable不出现在响应中高同 03 章core 的Metadata有这两个标志models 层没有 →客户端只能靠 PUT 试探才能知道某项是否可写。ResponseT未 deriveJsonSchema低include-schema只能给到Items级别无法描述带schema字段的完整信封。4.4 能力覆盖严重22 项能力仅填充约 9 项高..Default::default()使faults、operations、configurations、bulk-data、data-lists、modes、locks、logs、updates、functions、subcomponents、subareas、cyclic-subscriptions等恒为None。详见 01 章 §4.1。无实体写操作中POST/PUT/DELETE实体完全缺失拓扑只能通过代码或发现变更。对于服务端定位是合理的网关聚合场景但限制了作为独立 server 的可用性。4.5 建议的改进顺序优先级事项P0Boxdyn DataProvider→Arcdyn ...handler 取到 provider 后立即放锁P0modelsMetadata补齐is_readable/is_writable/schemaP1写请求体加WithRejection统一错误格式P1缓存 schemalazy staticP1groupscategories 同传 → 400P2list响应携带每项 schemaP2按能力优先级逐步填充 capabilitiesfaults → operations → modes → locks5. 关键代码位置内容路径路由组装opensovd-server/src/routes/mod.rs:66-85根能力opensovd-server/src/routes/entities/mod.rs:49-72百分号编码集opensovd-server/src/routes/entities/mod.rs:79-99component 路由与 handleropensovd-server/src/routes/entities/component.rs:27-...app / area handler.../app.rs:27-...、.../area.rs:27-...数据路由注册opensovd-server/src/routes/data.rs:37-62data_filter映射opensovd-server/src/routes/data.rs:138-154read / write handleropensovd-server/src/routes/data.rs:199-243错误枚举与映射opensovd-server/src/routes/error.rs:20-84版本信息opensovd-server/src/routes/version.rs:30
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻