// 本客户端加过的锁的进程内注册表:为「写请求被 423 拒绝时用自己持有的锁
// 令牌自动重试一次」提供查找依据(RFC 4918 §9.10.5 / §10.4.4)。
// 单独成文件以遵守单文件行数上限(AGENTS.md RL-04)。
///|
/// 注册表里的一条记录:锁令牌 + 规范化路径 + 锁深度。
/// 只有 `depth == Some("infinity")` 的锁才会覆盖其后代路径;
/// `depth` 为 `None`(服务端没回 `depth`)时按「只覆盖自身」处理,宁可
/// 少重试也不越权使用别的资源的令牌。
priv struct KnownLock {
token : String
path : String
depth : String?
}
///|
/// 注册表容量上限:超出后淘汰最旧的一条。
/// 取值只为兜住长期运行的客户端内存,不承担正确性职责
/// (被淘汰的锁只是失去自动重试能力,显式传 `lock_token` 仍然可用)。
const MAX_KNOWN_LOCKS : Int32 = 256
///|
/// 规范化路径用于覆盖判定:压掉重复与结尾的 `/`,统一成单个前导 `/`
/// 的形态,使 `/demo/a.txt`、`demo/a.txt`、`/demo/a.txt/` 视作同一路径;
/// 空路径仍规范化为空串(表示挂载点本身)。
fn normalize_lock_path(path : String) -> String {
let buf = StringBuilder()
for segment in path.split("/") {
if segment.length() > 0 {
buf.write_char('/')
buf.write_view(segment)
}
}
buf.to_string()
}
///|
/// 判断 `ancestor` 是否是 `path` 的祖先(或同一路径),两侧都先规范化。
/// 空路径视为整个挂载点,是所有路径的祖先。
fn is_path_ancestor(ancestor : String, path : String) -> Bool {
let parent = normalize_lock_path(ancestor)
let target = normalize_lock_path(path)
if parent == "" {
true
} else {
target == parent || target.has_prefix(parent + "/")
}
}
///|
/// 记账一把新拿到的锁(`lock` / `refresh_lock` 成功后调用)。
/// 同一把锁重复记账只保留一条,避免占满容量;超出上限淘汰最旧的一条。
/// `declared_depth` 是请求时声明的 `Depth`:服务端响应里没回 `depth` 时
/// 用它兜底,否则祖先路径上的锁会认不出自己的覆盖范围。
fn WebdavClient::remember_lock(
self : WebdavClient,
path : String,
lock : @types.ActiveLock,
declared_depth? : String,
) -> Unit {
let target = normalize_lock_path(path)
let depth = match lock.depth {
Some(value) => Some(value)
None => declared_depth
}
for known in self.known_locks {
if known.token == lock.token && known.path == target {
return
}
}
if self.known_locks.length() >= MAX_KNOWN_LOCKS {
let kept : Array[KnownLock] = []
for i = 1; i < self.known_locks.length(); i = i + 1 {
kept.push(self.known_locks[i])
}
self.known_locks = kept
}
self.known_locks.push({ token: lock.token, path: target, depth, })
}
///|
/// 注销一把已经释放的锁(`unlock` 成功后调用)。
fn WebdavClient::forget_lock(
self : WebdavClient,
path : String,
token : String,
) -> Unit {
let target = normalize_lock_path(path)
let kept : Array[KnownLock] = []
for known in self.known_locks {
if known.token == token && known.path == target {
continue
}
kept.push(known)
}
self.known_locks = kept
}
///|
/// 找一把覆盖 `path` 的已知锁令牌:自身路径上的锁,或锁深度为
/// `"infinity"` 的祖先路径上的锁。取最近记账的一把(后进先出),
/// 找不到返回 `None`。
fn WebdavClient::covering_lock_token(
self : WebdavClient,
path : String,
) -> String? {
let target = normalize_lock_path(path)
for i = self.known_locks.length() - 1; i >= 0; i = i - 1 {
let known = self.known_locks[i]
if known.path == target ||
(known.depth == Some("infinity") && is_path_ancestor(known.path, target)) {
return Some(known.token)
}
}
None
}