aster_forge_utils
aster_forge_utils 收纳低依赖、产品无关的小工具。它不是杂物间,只有确实跨项目重复、且不属于更具体 crate 的 helper 才应该放进来。
适用场景
- boolean-like 字符串解析。
- Gravatar hash 和 URL 拼接。
- best-effort 临时文件和目录清理。
- HTML 和 inline script 占位符 escaping。
- 单段 HTTP byte range 解析与 representation-relative 区间计算。
- HTTP date 和条件请求 ETag 比较。
- UUID 和 token 生成。
- 网络地址和 trusted proxy 解析。
- 安全数值转换。
- 路径渲染和运行时临时目录路径。
- RAII 临时文件/目录清理。
- UTF-8 安全截断和字符数量统计。
- URL 解析、origin/base URL 规范化。
- public-site origin 列表解析和 origin/path 拼接。
- 不可信 XML 的非递归结构校验、嵌套深度限制和 DTD/ENTITY 拒绝。
- 指数退避的纯机械计算和随机抖动;重试条件、取消、日志与业务状态仍由调用方负责。
不适合放在这里的内容:
- 产品配置结构。
- 配置值 normalizer 和运行时默认值读取,应该用
aster_forge_config。 - 文件名校验,应该用
aster_forge_validation。 - object key 校验,应该用
aster_forge_storage_core。 - API pagination,应该用
aster_forge_api。
Cargo 接入
[dependencies]
aster_forge_utils = { git = "https://github.com/AsterCommunity/AsterForge" }当前没有 feature flag。退避模块默认可用,使用 rand 生成抖动;需要可重复测试时使用 确定性的 apply_jitter。
模块
avatar
主要 API:
gravatar_hash(email)gravatar_url(email, size, base_url)
gravatar_hash 会 trim、lowercase 邮箱后计算 Gravatar 使用的 MD5 hex。gravatar_url 拼出 Aster 服务当前统一使用的公开 URL 形状:{base}/{hash}?d=identicon&s={size}&r=g。
Gravatar base URL 的配置写入校验和默认值回退在 aster_forge_config 中,别放回 utils。产品侧仍然负责用户头像来源策略、上传头像路由、缓存头、可用尺寸,以及是否启用 Gravatar。
bool_like
parse_bool_like(value) 支持常见布尔字符串。适合环境变量和兼容配置读取。
backoff
主要 API:
exponential_delay(initial_delay, retry_index):按 0-based 索引计算未封顶的指数延迟,使用饱和加法。cap_delay(delay, max_delay):应用硬上限。apply_jitter(delay, percent):应用确定性的百分比,适合测试和明确的策略组合。randomized_jitter(delay, min_percent, max_percent):在包含边界内采样百分比并应用抖动。
这些函数只处理时间算术。数据库重试、配置订阅重连和事务重试可以复用它们,但必须在 产品或领域 crate 中保留各自的 retryability、sleep/shutdown、attempt 起点、cap/jitter 顺序、稳定连接重置和观测语义。不要把它们包装成一个会吞掉这些差异的万能 retry runner。
fs
主要 API:
cleanup_temp_file(path)cleanup_temp_dir(path)cleanup_runtime_temp_root(temp_root)
这些 helper 面向临时文件和临时目录的 best-effort 清理:缺失文件/目录会被忽略,其他失败记录 warn 日志但不返回错误。cleanup_temp_dir 会对 DirectoryNotEmpty 做短暂重试,覆盖 macOS Spotlight/Finder 或文件监听器在删除过程中短暂写入目录的情况。
不要把它们用于需要事务语义、用户可见错误或存储驱动一致性的删除操作;那些场景应该保留产品侧 显式错误处理。
html
主要 API:
escape_html(value)escape_script_json(value)
escape_html 用于把普通文本插入已经存在的 HTML text/attribute 占位符,例如后端渲染 index.html 里的标题、图标 URL、CSP meta 和 CSRF token 名称。它会转义 &、"、'、 <、>。
escape_script_json 用于 JSON 序列化之后、插入 inline <script> 之前的二次 escaping。 它会转义 HTML parser 相关字符和 JavaScript 行分隔符,避免 </script> 这类文本打断脚本块。
这两个 helper 不是富文本 sanitizer。用户提交的 HTML 是否允许、如何过滤标签和属性,仍然是产品 安全策略。
id
主要 API:
new_uuid()new_short_token()UniqueUuidAttempt<T>UNIQUE_UUID_MAX_ATTEMPTS
唯一 UUID 生成流程通过 UniqueUuidAttempt 把“候选冲突”和“成功结果”表达出来。产品侧决定冲突如何查询数据库。
http_range
主要 API:
parse_single_byte_range(raw, total_size)HttpByteRangeHttpRangeError
该模块只处理 transport-neutral 的单段 bytes= range:支持 bounded、open-ended 和 suffix 形式,按 representation 长度截断越界 end,并明确区分非法 unit、多段 range、数字错误、空 representation 和 unsatisfiable range。它不决定 HTTP 状态码,也不打开 storage stream;REST、 WebDAV 或内部传输协议应在自己的响应边界映射错误和选择读取方式。
http_validators
主要 API:
format_http_date(time)parse_http_date(value)http_date_epoch_seconds(time)if_match_header_matches(raw, resource_exists, current_etag)if_none_match_header_matches(raw, resource_exists, current_etag)
该模块实现 transport-neutral 的 HTTP conditional request 基础语义:If-Match 使用强 ETag 比较,If-None-Match 使用弱比较,二者都支持 *,并拒绝没有任何 entity tag 的空列表。实现不依赖 Actix/Axum;产品负责把 HttpValidatorError 映射为 REST、WebDAV、 WOPI 或其他协议所需的状态码和响应体。
net
主要 API:
is_loopback_host(host)parse_trusted_proxies(values)is_trusted_proxy(ip, trusted)real_ip_from_forwarded_for(...)
适合反向代理、真实客户端 IP 和 loopback http 判断。产品侧仍要决定 trusted proxy 配置来源。
numbers
提供 i64_to_usize、u64_to_i64、calc_total_chunks 等检查转换。不要在产品里用裸 as 处理外部输入和数据库值,容易溢出或静默截断。
paths
提供:
join_pathnormalize_pathrender_runtime_relative_pathresolve_config_relative_pathresolve_config_relative_sqlite_urltemp_file_pathruntime_temp_dirupload_temp_dirtask_temp_dir
这些函数处理的是运行时路径,不负责 object storage key 安全。
raii
TempFileGuard 和 TempDirGuard 用于测试或临时流程失败时自动清理。长期资源生命周期不要靠 RAII guard 偷偷控制,产品服务应该显式管理。
text
主要 API:
char_count(value)truncate_utf8_to_max_bytes(value, max_bytes)
char_count 统计的是 Unicode scalar value,不是 grapheme cluster。它适合现有 Aster 服务里“最多 N 个 chars()”这种规则;如果产品要按用户感知字符处理,需要在产品侧另设 Unicode segmentation 策略。
truncate_utf8_to_max_bytes 用于保守的字节限制,例如文件名、任务展示名、外部错误摘要等。 它不会截断到非法 UTF-8 边界。
url
主要 API:
parse_urlparse_absolute_urlhas_http_schemeis_https_or_loopback_httpnormalize_http_base_urlnormalize_originparse_public_site_originsnormalize_public_site_origins_config_valueruntime_public_site_origins_withpublic_site_origin_for_requestjoin_origin_and_path
适合 external auth callback、CORS origin、公开 base URL 等配置规范化。public_site_* helper 只处理产品无关的 origin 解析、去重、请求 origin 匹配和 URL 拼接;产品侧仍然保留具体 config key、runtime snapshot、日志上下文和错误映射。
错误边界
UtilsError 分为:
InvalidValueNumericConversion
产品侧应在配置加载、API handler 或 service 边界映射成具体错误。不要把 UtilsError 直接作为产品 API error 类型。
测试要求
- 每个产品接入点覆盖非法输入。
- 数值转换测试要包含负数、超上限和边界值。
- URL/origin 测试要覆盖 loopback HTTP、HTTPS、wildcard。
- HTTP range 测试要覆盖 bounded/open-ended/suffix、end 截断、空文件、零 suffix、多段请求、
u64上界和 unsatisfiable offset。 - trusted proxy 测试要覆盖多代理链。
参考项目
- AsterDrive:URL、proxy、upload chunk、token、临时路径和数值转换场景丰富。
- AsterYggdrasil:适合看轻量项目如何直接调用 Forge utils,避免保留无意义 facade。