From 231a72e78cf028d039557e2810b302890f181991 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Mon, 13 Jan 2025 16:38:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B5=81=E5=BC=8F=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=99=A8=20&=20fix:=20gl2=20=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/gl2.ts | 2 +- src/core/render/index.tsx | 1 - src/module/loader/stream.ts | 93 +++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/module/loader/stream.ts diff --git a/src/core/render/gl2.ts b/src/core/render/gl2.ts index b68896e..8a13dbf 100644 --- a/src/core/render/gl2.ts +++ b/src/core/render/gl2.ts @@ -1531,7 +1531,7 @@ export class GL2Program extends EventEmitter { /** * 定义一个 attribute 常量,并存入本着色器程序的 attribute 常量映射,在 es 300 版本中叫做 in * @param attrib attribute 常量名 - * @param type attribute 类型,可选 {@link Shader.Attrib1f} 至 {@link Shader.AttribI4uiv} + * @param type attribute 类型,可选 {@link GL2.ATTRIB_1f} 至 {@link GL2.ATTRIB_I4uiv} * @returns attribute 常量的操作对象,可用于设置其值 */ defineAttribute( diff --git a/src/core/render/index.tsx b/src/core/render/index.tsx index c08f463..5bbbb9f 100644 --- a/src/core/render/index.tsx +++ b/src/core/render/index.tsx @@ -69,7 +69,6 @@ Mota.require('var', 'loading').once('coreInit', () => { - ); }); diff --git a/src/module/loader/stream.ts b/src/module/loader/stream.ts new file mode 100644 index 0000000..d137798 --- /dev/null +++ b/src/module/loader/stream.ts @@ -0,0 +1,93 @@ +import { logger } from '@/core/common/logger'; +import EventEmitter from 'eventemitter3'; + +export interface IStreamController { + /** + * 开始流传输 + */ + start(): Promise; + + /** + * 主动终止流传输 + * @param reason 终止原因 + */ + cancel(reason?: string): void; +} + +export interface IStreamReader { + /** + * 接受字节流流传输的数据 + * @param data 传入的字节流数据,只包含本分块的内容 + * @param done 是否传输完成 + */ + pump(data: Uint8Array | undefined, done: boolean): void; + + /** + * 开始流传输 + * @param stream 传输流对象 + * @param controller 传输流控制对象 + */ + start(stream: ReadableStream, controller: IStreamController): void; + + /** + * 结束流传输 + * @param done 是否传输完成,如果为 false 的话,说明可能是由于出现错误导致的终止 + * @param reason 如果没有传输完成,那么表示失败的原因 + */ + end(done: boolean, reason?: string): void; +} + +interface StreamLoaderEvent { + data: [data: Uint8Array | undefined, done: boolean]; +} + +export class StreamLoader + extends EventEmitter + implements IStreamController +{ + /** 传输目标 */ + private target: Set = new Set(); + /** 读取流对象 */ + private stream?: ReadableStream; + + constructor(public readonly url: string) { + super(); + } + + /** + * 将加载流传递给字节流读取对象 + * @param reader 字节流读取对象 + */ + pipe(reader: IStreamReader) { + this.target.add(reader); + return this; + } + + async start() { + const response = await window.fetch(this.url); + const stream = response.body; + if (!stream) { + logger.error(23); + return; + } + // 获取读取器 + this.stream = stream; + const reader = response.body?.getReader(); + this.target.forEach(v => v.start(stream, this)); + + // 开始流传输 + while (true) { + const { value, done } = await reader.read(); + this.target.forEach(v => v.pump(value, done)); + if (done) break; + } + + this.target.forEach(v => v.end(true)); + } + + cancel(reason?: string) { + if (!this.stream) return; + this.stream.cancel(reason); + this.target.forEach(v => v.end(false, reason)); + } +}