Rerun URI 全面解析:rerun:// 协议设计与 re_uri 解析库实战指南
2026/9/15 13:59:17 网站建设 项目流程

Rerun URI 全面解析:rerun:// 协议设计与 re_uri 解析库实战指南

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

re_uri是 Rerun(多模态机器人数据可视化与查询平台)仓库中负责Rerun URI 解析与构造的核心 crate。Rerun 定义了自己的 URL scheme(rerun://rerun+http://rerun+https://),用于跨网络统一寻址 Catalog 服务器、数据集、录制段、文件夹以及本地 Viewer 的代理端点。本文将以 crates/store/re_uri/README.md 及其对应的 rustdoc 文档为主体,结合 crate 源码与测试,完整讲解 Rerun URI 的语法规范、解析流程、默认端口、查询参数与 Fragment 语义,读完你能够独立编写、解析与调试任何形式的 Rerun URI。

Rerun URI 是什么:跨网络统一寻址方案

Rerun 使用自己专属的 URL scheme 在网络上访问信息。正如 crates/store/re_uri/src/lib.rs 的 crate 级文档所述:

  • 支持的 scheme 有三种:rerun+http://rerun+https://,以及作为rerun+https://别名的rerun://
  • 解析时这些 scheme 会被即时转换为标准的http://https://
  • 底层走的是gRPC 协议,URI 中的路径段(如/catalog/recording/12345)会被动态映射到对应的 gRPC 服务与方法上。

也就是说,Rerun URI 本质上是一层"面向用户、可读可分享"的寻址抽象:用户只需要记住rerun://这样的语义化 scheme,底层的传输协议与端点映射由re_uri与 gRPC 客户端/服务端负责完成。这也是该 crate 在 Cargo.toml 中声明的定位——"Parsing and constructing Rerun URIs"。

三种 Scheme 与协议转换规则

Scheme枚举定义在 crates/store/re_uri/src/scheme.rs,仅有两种变体,却覆盖三种书写形式:

书写形式解析结果规范显示底层协议
rerun://RerunHttpsrerun(省略+httpshttps
rerun+https://RerunHttpsrerun(省略+httpshttps
rerun+http://RerunHttprerun+httphttp

关键实现细节(见 scheme.rs):

  • 只要 URL 以rerun+http://开头,就被识别为RerunHttp
  • rerun://rerun+https://开头,则识别为RerunHttps
  • 其它任何前缀都会返回Error::InvalidScheme
  • RerunHttpsDisplay输出时统一呈现为rerun,因此rerun://rerun+https://解析后完全等价(origin.rs 中的test_rerun_alias测试 也验证了这一点)。

Scheme::canonical_url负责把 Rerun scheme 重写为 http(s) 形式:rerun+http://http://rerun://rerun+https://https://

安全警告:本地实例与 TLS

crates/store/re_uri/src/lib.rs 明确警告:大多数本地运行的 Rerun 实例没有配置完整的 TLS。因此:

  • 本地开发、局域网内连接时应使用rerun+http://
  • 代价是底层连接不加密,请勿在不可信网络上传输敏感数据;
  • 公网、生产环境默认使用rerun://(等价于rerun+https://)。

默认端口:两个关键常量

re_uri在 lib.rs 定义了两个全局默认端口:

  • DEFAULT_REDAP_PORT = 51234:redap(Rerun Data Access Protocol)服务器的默认端口;
  • DEFAULT_PROXY_PORT = 9876:Rerun gRPC 代理服务器的默认端口。

端口推断逻辑位于 redap_uri.rs 的FromStr实现:当 URL 路径中包含/proxy时,省略端口则默认9876,否则默认51234。而 origin.rs 的replace_and_parse则负责更通用的缺省端口推断:

  • 目标是localhost/127.0.0.1/0.0.0.0时,使用调用方传入的默认端口(即上面的 51234 或 9876);
  • 目标是公网主机时,https://缺省补443http://缺省补80

这一点在test_parsing测试中体现得非常直观:rerun://example.com解析后端口为 443,rerun+http://example.com解析后端口为 80,而rerun://localhost/catalog解析后端口为 51234。

完整示例:合法 Rerun URI 一览

以下示例直接取自 lib.rs 的 rustdoc,它们是RedapUri::from_str的合法输入,每一行都可以通过uri.parse::<re_uri::RedapUri>()成功解析:

for uri in [ // 访问 catalog 服务器。 "rerun://rerun.io", "rerun://rerun.io:51234/catalog", "rerun+http://localhost:51234/catalog", "rerun+https://localhost:51234/catalog", // 代理:把消息发送给另一个 viewer。 "rerun+http://localhost:51234/proxy", // 链接到 catalog 服务器上的某个数据集。 "rerun://127.0.0.1:1234/dataset/1830B33B45B963E7774455beb91701ae", // 链接到某个数据集的资源(assets)。 "rerun://127.0.0.1:1234/dataset/1830B33B45B963E7774455beb91701ae/assets", // 链接到数据集中的某个录制段(可选时间选择)。 "rerun://127.0.0.1:1234/dataset/1830B33B45B963E7774455beb91701ae?segment_id=sid#time_selection=timeline@1.23s..72s", // 链接到 catalog 中的某个文件夹(数据集名称前缀)。 "rerun://rerun.io/folder/perception.detection", ] { assert!(uri.parse::<re_uri::RedapUri>().is_ok()); }

可以看到 Rerun URI 的通用结构为:

scheme://host[:port]/endpoint[/参数路径][?查询参数][#fragment]

五大端点:RedapUri 的变体体系

RedapUri是解析的顶层结果,定义于 redap_uri.rs,共五种变体,分别对应五类端点。路径段解析时最多取前 3 段(并过滤空段以兼容尾随斜杠),然后按下表匹配:

路径形式RedapUri 变体承载结构
/catalog(或空路径)CatalogCatalogUri { origin }
/entry/<entry_id>EntryEntryUri { origin, entry_id }
/folder/<dotted.path>FolderFolderUri { origin, path }
/dataset/<dataset_id>[/<resource>]DatasetDatasetUri { origin, dataset_id, resource, segment_id, fragment }
/proxyProxyProxyUri { origin }

其中Catalog 是默认端点:即使 URI 没有路径(如rerun://localhost:51234)或只有/,也会解析为Catalog(见test_catalog_default测试)。

Catalog:目录服务器

CatalogUri(endpoints/catalog.rs)只包含一个origin,用于定位 redap 服务器的根目录。rerun://rerun.iorerun://rerun.io:51234/catalog都指向 catalog。

Entry:远程条目

EntryUri(endpoints/entry.rs)由originentry_id组成。entry_idre_log_types::EntryId,底层是一个 TUID。解析时若 ID 非法,返回Error::InvalidTuid。值得注意的兼容性设计:带尾随路径段的 entry URL 仍可解析,保证旧版本 URL 依然能打开条目(见 redap_uri.rs 的test_entry_url_trailing_path)。

Folder:数据集名称前缀分组

FolderUri(endpoints/folder.rs)用点分路径表示目录层级,例如perception.detection。相关工具函数在 dataset_hierarchy.rs:

  • DATASET_HIERARCHY_SEPARATOR = '.':层级分隔符;
  • split_dataset_hierarchy_path:把a.b.c拆成["a", "b", "c"],且尾随分隔符属于叶子名"a.b."["a", "b."]"a."["a."]);
  • dataset_hierarchy_leaf_name:取叶子段。

Folder 路径的序列化会借助url::Urlpercent-encoding,因此含/等特殊字符的文件夹名(如odd%2Fnameodd/name)可以安全往返(见test_folder_endpoint_percent_encoded)。空路径folder/会被拒绝。

Dataset:数据集、资源与录制段

DatasetUri(endpoints/dataset.rs)是结构最丰富的端点,支持以下形式:

<origin>/dataset/$DATASET_ID <origin>/dataset/$DATASET_ID?segment_id=$SEGMENT_ID&time_range=$TIME_RANGE <origin>/dataset/$DATASET_ID/assets <origin>/dataset/$DATASET_ID/assets?segment_id=$ASSET_ID
  • dataset_idre_tuid::Tuid,非法时返回Error::InvalidTuid
  • 资源类型DatasetResourceSegments(默认,指向数据集自身的录制段)与Assets(指向数据集的资源,即其隐藏资源数据集中的录制段);默认资源在序列化时会被省略,只有非默认的/assets才会写进 URL(见test_dataset_url_resource_roundtrip);
  • 未知资源名会回退到默认资源,保证新旧版本 URL 都能打开数据集(见test_dataset_url_unknown_resource);
  • 查询参数segment_idNone表示指向数据集整体(此时store_id()返回None),Some表示指向某个具体录制段;
  • 兼容旧参数partition_id:旧的partition_id会被解析进segment_id,但两者同时出现会报Error::AmbiguousSegmentId(见test_dataset_data_url_legacy_partition_idtest_dataset_data_url_ambiguous_segment_id_partition_id);
  • 未知查询键会被静默忽略,以兼容其它版本产生的 URL。

DatasetUri::store_id()返回录制段加载进哪个 store,并体现了一个关键设计:

  • 数据集的各录制段数据同构,共享同一个 application id(以及蓝图 blueprint)
  • 数据集的各个资源(assets)彼此无关,每个资源独立分配 application id
  • 以上均有对应测试(segments_of_a_dataset_share_an_application_idassets_of_a_dataset_do_not_share_an_application_id)验证。

Proxy:指向本地 Viewer 的代理

ProxyUri(endpoints/proxy.rs)用于访问另一个本地 Viewer的代理端点,常用于把消息转发给正在运行的 viewer。示例:rerun+http://localhost:9876/proxy。由于路径含/proxy,缺省端口自动取 9876。

Fragment:定位实体与时间

URI 的#fragment部分用于指向具体实体或时间点,由 fragment.rs 中的Fragment结构承载,包含三个可选字段:

类型含义
selectionDataPath选中某个实体路径,可带实例索引,如/entity/path[#42]
when(TimelineName, TimeCell)选定某条时间线和该时间线上的时间点
time_selectionTimeSelection选定某条时间线上的时间范围

官方 doc 示例:

selection=/entity/path selection=/entity/path[#42] selection=/entity/path[#42]&when=log_tick@32 selection=/entity/path&when=log_time@2022-01-01T00:00:03.123456789Z when=log_time@2022-01-01T00:00:03.123456789Z

解析规则细节:

  • Fragment 以&分隔键值对,解析时跳过没有=的段
  • selection若重复出现,后出现的覆盖先前的;when若重复,则忽略后续的;
  • 未知键(如focus=foo=test)会直接导致解析失败(test_parse_fragment的 fail_cases);
  • &=支持反斜杠转义:split_on_unescaped_ampersandsplit_at_first_unescaped_equals两个内部函数只把未被\转义的字符当作分隔符;
  • Fragment::parse_forgiving在解析失败时返回Fragment::default(),供 URL 解析容错使用——例如test_dataset_data_url_with_broken_fragment中无法解析的 fragment 会被静默丢弃;
  • 只有DatasetUri会保留 fragment,Catalog/Proxy/Entry/Folder 均不支持(RedapUri::fragment()返回None)。

TimeSelection:时间范围表达式

TimeSelection(time_selection.rs)由timelinerange(绝对时间范围)组成,字符串语法为TIMELINE@time..time,支持序列时间、持续时间和时间戳三种写法:

sequence@1096..2097 duration@+1.096s..+2.097s duration@-1.096s..+2.097s time_selection=timeline@1.23s..72s

解析细节:

  • 先按@拆分出时间线名与范围,再按..拆分出 min/max;
  • min 与 max 的类型必须一致(都是序列或都是时长),否则返回Error::InvalidTimeRange
  • 负数时长甚至支持 Unicode 减号(U+2212),测试test_parse_format_time_selection专门覆盖了该情形;
  • TimeSelection刻意不实现Display(用static_assertions::assert_not_impl_any!强制约束),因为其字符串表示存在歧义,必须通过format()(人类可读)或format_url()(URL 安全、避免禁用的特殊字符)显式格式化。

容错细节:解析时的宽容设计

crates/store/re_uri/src/redap_uri.rs 的解析入口有若干"防呆"设计,值得在实际对接时注意:

  1. 空格兼容:用户手动在地址栏粘贴https://rerun.io/viewer?url=rerun+https://…时,+会被浏览器转成空格。解析器会把rerun httprerun https还原为rerun+httprerun+https(对应测试test_proxy_endpoint_with_space验证"rerun http://127.0.0.1:9876/proxy"可正常解析);
  2. 无 scheme 输入:当输入不含://时,解析器按主机名猜测 scheme——含localhost/127.0.0.1时假定rerun+http://,含rerun.io时假定rerun://(TLS),否则报InvalidScheme
  3. 0.0.0.0 归一化Origin::as_urlDisplay会把不可连接的0.0.0.0显示为127.0.0.1
  4. +编码陷阱url::Url::query_pairs()会把查询串中的+解码为空格(test_url专门验证了%2B才是+的正确编码),因此构造含+的查询参数时务必使用%2B
  5. 错误类型完备:error.rs 定义了InvalidSchemeInvalidTimeRangeUnexpectedUriUnexpectedOpaqueOriginUnexpectedBaseUrlCannotLoadUrlAsRecordingAmbiguousSegmentIdInvalidTuid等错误变体,其中AmbiguousSegmentId专门用于拦截segment_idpartition_id同时出现的情况。

序列化与在仓库中的实际应用

字符串序列化

RedapUri及各类端点 URI 都实现了serde::Serialize/Deserialize,且以纯字符串形式序列化(Serialize输出to_string(),反序列化时再parse),因此 Rerun URI 可以方便地嵌入 JSON 配置、网络协议消息或持久化状态中。

在数据源识别中的角色

re_uri并不是孤立的解析库,它直接参与 Rerun 的数据源分发。在 crates/store/re_data_source/src/data_source.rs 中:

  • LogDataSource::RedapDatasetSegment { uri: re_uri::DatasetUri, open_behavior }:把rerun://URI 指向的录制段作为数据源打开;
  • LogDataSource::RedapProxy(re_uri::ProxyUri):把rerun+http://代理作为数据源。

LogDataSource::from_uri会先把用户输入的 URL 分类成本地文件、stdin、HTTP、gRPC 等类型,其中 Rerun scheme 的 URL 就会落到RedapDatasetSegment/RedapProxy分支,例如:

rerun://127.0.0.1:1234/dataset/1830B33B45B963E7774455beb91701ae/data?segment_id=sid rerun+http://127.0.0.1:9876/proxy

这印证了re_uri是"URL 文本 → 结构化地址 → 实际连接"链路中的第一环。

TableReference:跨录制表引用

table_reference.rs 中的TableReference枚举把"表"的引用抽象为三种:本地表、远程服务器的__entries表、远程条目表;后两者可通过url()转回对应的RedapUri(Catalog 或 Entry),实现了表引用与 URI 之间的双向转换。

小结

Rerun URI 是一套设计完整、容错友好的统一寻址协议:rerun:///rerun+https://走 TLS,rerun+http://用于本地无 TLS 场景;路径段/catalog/entry/<id>/folder/<path>/dataset/<id>[/segments|assets]/proxy分别映射五类端点;查询参数segment_id/旧版partition_id选择录制段;#fragment中的selection/when/time_selection让链接可以精确定位到某个实体、时间点或时间范围。

如果要继续深入:

  • 完整解析与测试实现见 redap_uri.rs(含大量端到端用例);
  • 端口与 origin 推断逻辑见 origin.rs;
  • scheme 规范化见 scheme.rs;
  • 各端点结构见 crates/store/re_uri/src/endpoints/ 目录;
  • 实际消费 Rerun URI 的数据源分发逻辑见 data_source.rs。

【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询