下载协议
本文档描述了使用内容寻址存储(CAS)重建 API 从 Xet 协议下载单个文件的完整过程。
概述
Xet 协议中的文件下载是一个两阶段过程:
- 重建查询:查询 CAS API 以获取文件重建元数据
- 数据获取:使用重建元数据下载并重新组装文件
阶段 1:调用重建 API
单个文件重建
要下载给定文件哈希的文件,首先调用重建 API 以获取文件重建。按照 api 中的步骤操作。
请注意,你至少需要一个 read 作用域的身份验证令牌,身份验证参考。
tip
对于大文件,建议批量请求重建,即前 10GB,下载所有数据,然后下一个 10GB,依此类推。客户端可以使用 Range 标头指定文件数据的范围。
阶段 2:理解重建响应
重建 API 返回一个 QueryReconstructionResponse 对象,包含三个关键组件:
QueryReconstructionResponse 结构
{
"offset_into_first_range": 0,
"terms": [
{
"hash": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
"unpacked_length": 263873,
"range": {
"start": 0,
"end": 4
}
},
...
],
"fetch_info": {
"a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456": [
{
"range": {
"start": 0,
"end": 4
},
"url": "https://transfer.xethub.hf.co/xorb/default/a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
"url_range": {
"start": 0,
"end": 131071
}
},
...
],
...
}
}
字段
offset_into_first_range
- 类型:
number - 对于完整文件或当指定的范围起始为 0 时,这保证为
0 - 对于范围查询,这是第一个 term(反序列化/块解压缩)中的字节偏移量,从该偏移量开始保留数据。
- 由于请求的范围可能从块的中间开始,并且数据必须以完整块下载(因为它们可能需要反序列化),因此此偏移量告诉客户端在第一个块(或可能在第一个 term 内的多个块)中跳过多少字节。
terms
- 类型:
Array<CASReconstructionTerm> - 描述从哪个 xorb 下载哪些块的重建 term 的有序列表
- 每个
CASReconstructionTerm包含:hash:Xorb 哈希(64 字符小写十六进制字符串)range:Xorb 内的块索引范围{ start: number, end: number };端部独占[start, end)unpacked_length:解压缩后的预期长度(用于验证)
fetch_info
- 类型:
Map<Xorb Hash (64 字符小写十六进制字符串), Array<CASReconstructionFetchInfo>> - 将 xorb 哈希映射到下载其某些块所需的信息。
- 映射到一个或多个
CASReconstructionFetchInfo的数组
- 映射到一个或多个
- 每个
CASReconstructionFetchInfo包含:url:用于下载 xorb 数据的 HTTP URL,包含授权信息的预签名 URLurl_range(bytes_start, bytes_end):用于 Range 标头的字节范围{ start: number, end: number };端部包含[start, end]- 下载此块范围时,
Range标头必须设置为Range: bytes=<start>-<end>
- 下载此块范围时,
range(index_start, index_end):此 URL 提供的块索引范围{ start: number, end: number };端部独占[start, end)- 此范围指示此 fetch info term 描述此 xorb 内的哪个块索引范围
阶段 3:下载和重建文件
过程概述
-
按顺序处理
terms数组中的每个CASReconstructionTerm -
对于每个
CASReconstructionTerm,使用 term 的哈希查找匹配的 fetch info- 从
CASReconstructionTerm获取 xorb 哈希下的 fetch_info 项列表。保证 xorb 哈希作为键存在于 fetch_info 映射中。 - 线性迭代
CASReconstructionFetchInfo列表,找到一个引用等于或包含 term 的块范围的项。- 保证存在这样的 fetch_info 项。如果不存在,服务器有错误。
- 从
-
使用 HTTP
GET请求下载所需数据,并且必须设置Range标头 -
反序列化下载的 xorb 数据以提取块
- 此系列块包含由
CASReconstructionFetchInfo的range字段指定的索引处的块。修剪开头或结尾的块以匹配重建 term 的range字段指定的块。 - (仅对于第一个 term)跳过
offset_into_first_range字节
- 此系列块包含由
-
按 term 顺序连接结果以重建文件
详细下载过程
下载重建
- 使用重建 API 下载给定文件的重建对象
file_id = "0123...abcdef"
api_endpoint, token = get_token() # 遵循身份验证说明
url = api_endpoint + "/reconstructions/" + file_id
reconstruction = get(url, headers={"Authorization": "Bearer: " + token})
# 将重建分解为组件
terms = reconstruction["terms"]
fetch_info = reconstruction["fetch_info"]
offset_into_first_range = reconstruction["offset_into_first_range"]
将 Term 匹配到 Fetch Info
对于 terms 数组中的每个 CASReconstructionTerm:
- 在
fetch_info映射中查找 term 的hash以获取CASReconstructionFetchInfo列表 - 找到一个
CASReconstructionFetchInfo条目,其中 fetch info 的range包含 term 的range- 线性搜索
CASReconstructionFetchInfo数组,找到CASReconstructionFetchInfo的范围块({ "start": number, "end": number })的 start <= term 的范围 start 且 end >= term 的范围 end 的元素。 - 服务器应该保证匹配,如果没有匹配,此下载被视为失败,服务器出错。
- 线性搜索
for term in terms:
xorb_hash = term["hash"]
fetch_info_entries = fetch_info[xorb_hash]
fetch_info_entry = None
for entry in fetch_info_entries:
if entry["range"][start] <= term["range"]["start"] and entry["range"]["end"] >= term["range"]["end"]:
fetch_info_entry = entry
break
if fetch_info_entry is None:
# 错误!
步骤 2:下载 Xorb 数据
对于每个匹配的 fetch info:
- 向 fetch info 条目中的
url发出 HTTP GET 请求 - 包含
Range标头:bytes={url_range.start}-{url_range.end}
for term in terms:
...
data_url = fetch_info_entry["url"]
range_header = "bytes=" + fetch_info_entry["url_range"]["start"] + "-" + fetch_info_entry["url_range"]["end"]
data = get(data_url, headers={"Range": range_header})