// 锁相关的公共类型:令牌归一化、活动锁条目、LOCK / 刷新锁的响应结果。
// 与具体操作实现解耦,单独成文件以遵守单文件行数上限(AGENTS.md RL-04)。
///|
/// 归一化锁令牌:去掉两侧空白与可选的外层 `<>`。
///
/// 令牌在协议里是不透明串(RFC 4918 §6.4):常见形式是
/// `opaquelocktoken:...`,但服务端也可能回裸串(hacdias/webdav 就回
/// 裸数字),所以这里不校验 URI 形式,只统一形状。
/// `Lock-Token` 响应头自带尖括号,请求里传入的则通常不带,
/// 两种输入经这里归一后都变成不带尖括号的裸令牌。
pub fn normalize_lock_token(token : String) -> String {
let trimmed = token.trim().to_owned()
if trimmed.length() >= 2 && trimmed.has_prefix("<") && trimmed.has_suffix(">") {
trimmed[1:trimmed.length() - 1].trim().to_owned()
} else {
trimmed
}
}
///|
/// 锁作用域(RFC 4918 §14.11 `lockscope`):独占写锁或共享写锁。
pub(all) enum LockScope {
/// 独占写锁:同一资源同时只有一把(当前默认)
Exclusive
/// 共享写锁:可以被多个主体同时持有(彼此之间不冲突)
Shared
}
///|
/// 渲染为 `lockscope` 子元素名:`"exclusive"` / `"shared"`。
pub fn LockScope::to_dav(self : LockScope) -> String {
match self {
Exclusive => "exclusive"
Shared => "shared"
}
}
///|
/// 解析 `lockscope` 子元素名(去空白、大小写不敏感):
/// `"shared"` → `Shared`,其余(含空串与未知值)→ `Exclusive`,
/// 与「服务端没给 lockscope 时按独占处理」的既有口径一致。
pub fn LockScope::from_dav(name : String) -> LockScope {
if ascii_upper(name.trim().to_owned()) == "SHARED" {
Shared
} else {
Exclusive
}
}
///|
/// 一条活动锁(RFC 4918 §14.11 `activelock`)。
pub(all) struct ActiveLock {
/// 归一化后的锁令牌(已去掉外层 `<>`)
token : String
/// 锁作用域;服务端没给 `lockscope` 时由调用方回填期望作用域,
/// 最终兜底为 `Exclusive`
scope : LockScope
/// 锁深度:`"0"` / `"infinity"`
depth : String?
/// `owner` 元素的文本内容(嵌套 href 的文本也算在内);
/// 服务端回了空的 `` 时为 `None`
owner : String?
/// 锁超时原文:`"Second-3600"` / `"Infinite"`
timeout : String?
/// `lockroot` 的 href 原文(可能是相对路径,不做归一)
lockroot : String?
}
///|
/// LOCK(申请或刷新)的响应结果。
pub(all) struct LockResult {
/// HTTP 状态码:200 表示锁施加在既有资源上,201 表示服务端借这次锁
/// 创建了空资源(lock-null)
status : Int32
/// 是否 201(lock-null 资源被创建)
created : Bool
/// 服务端确认的锁
lock : ActiveLock
}