Files
Endoleap/src/lib/canvas-runtime/import-byte-reader.ts
T

32 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 解析器的统一精确字节读取边界。默认读不可变 Blob,也可注入带块证明的 reader。
* 这里检查范围/长度与取消,不负责整源SHA、JSON语法或业务记录;源级读取失败不能降格为可跳过的坏记录。
*/
import {fault} from '../canvas-core/values.ts';
/** 会破坏整个源读取可信性的错误集合,供上层区分单记录失败与源级暂停/失败。 */
const failures=new Set(['import_source_changed','invalid_import_byte_range','import_read_capacity','import_source_closed','import_source_read_failed','invalid_import_read_proof','import_read_proof_interpreter_unavailable']);
/** 只按 code 是否在固定集合分类,不校验错误对象的来源;其它码(含一般 import_aborted)不在集合内。
* 取消是否应优先由读取调用方看 signal;本分类器不是所有源错误/取消的通用判定器。 */
export const isImportByteFailure=(error:unknown)=>failures.has((error as {code?:string}|undefined)?.code??'');
/** Optional immutable-source port. Implementations return exactly the requested bytes. */
/** 可选只读端口声明完整长度,必须返回所请求区间的精确字节,不能截断或换源。 */
export type ImportByteReader={readonly byteLength:number;read(start:number,end:number,signal:AbortSignal):Promise<Uint8Array>};
/** 校验安全整数范围,允许 end 超出 EOF 并截到 bytes.size;start 超出 EOF 则拒绝。
* reader 长度须等于 Blob 长度,但本函数不逐字节比较 Blob/reader,也不证明同长度源未被替换。
* 外来 Uint8Array 结果复制为自有缓冲,默认 Blob 路径返回此次新读缓冲;不缓存结果或做并发合并。
* 空范围仍会调用 reader/Blob 读取,是否优化零 I/O 由端口决定;bytes 依赖调用方已验证的 Blob 合同。 */
export async function readImportRange(bytes:Blob,reader:ImportByteReader|undefined,start:number,end:number,signal:AbortSignal):Promise<Uint8Array<ArrayBuffer>>{
if(signal.aborted)throw fault('import_aborted');
if(!Number.isSafeInteger(start)||!Number.isSafeInteger(end)||start<0||end<start||start>bytes.size||reader&&reader.byteLength!==bytes.size)throw fault('invalid_import_byte_range');
const limit=Math.min(end,bytes.size);let value:Uint8Array;
// 保留已识别源错误,其它I/O异常统一为source_read_failed;取消优先返回import_aborted。
try{value=reader?await reader.read(start,limit,signal):new Uint8Array(await bytes.slice(start,end).arrayBuffer());}
catch(error){if(signal.aborted)throw fault('import_aborted');if(isImportByteFailure(error))throw error;throw fault('import_source_read_failed');}
if(signal.aborted)throw fault('import_aborted');
// 长度或响应类型不符视为源改变,不能让解析器在缺字节内容上继续产出业务修改。
if(!(value instanceof Uint8Array)||value.byteLength!==limit-start)throw fault('import_source_changed');
return reader?new Uint8Array(value):value as Uint8Array<ArrayBuffer>;
}