test bun stream sse and http-stream
This commit is contained in:
38
demo/bun/src/index.ts
Normal file
38
demo/bun/src/index.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const server = Bun.serve({
|
||||||
|
port: 5002,
|
||||||
|
fetch(request: Bun.BunRequest, server) {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
|
||||||
|
if (url.pathname === '/stream') {
|
||||||
|
// 直接使用 Bun 的原生 ReadableStream
|
||||||
|
const readable = new ReadableStream({
|
||||||
|
async start(controller) {
|
||||||
|
for (let i = 1; i <= 10; i++) {
|
||||||
|
// 检查客户端是否断开
|
||||||
|
if (request.signal.aborted) {
|
||||||
|
console.log('客户端已断开');
|
||||||
|
controller.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.enqueue(`${new Date().toISOString()} 第 ${i} 批数据\n`);
|
||||||
|
await new Promise(r => setTimeout(r, 100)); // 模拟延迟
|
||||||
|
}
|
||||||
|
controller.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request.signal.addEventListener('abort', () => {
|
||||||
|
console.log('Request aborted by client');
|
||||||
|
});
|
||||||
|
return new Response(readable, {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
'Transfer-Encoding': 'chunked'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response('Not Found', { status: 404 });
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.65",
|
"version": "0.0.66",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
port,
|
port,
|
||||||
hostname,
|
hostname,
|
||||||
idleTimeout: 0, // 4 minutes idle timeout (max 255 seconds)
|
idleTimeout: 0, // 4 minutes idle timeout (max 255 seconds)
|
||||||
fetch: async (request: Bun.BunRequest, server: any) => {
|
fetch: async (request: Bun.BunRequest, server: Bun.Server<{}>) => {
|
||||||
const host = request.headers.get('host') || 'localhost';
|
const host = request.headers.get('host') || 'localhost';
|
||||||
const clientInfo = server.requestIP(request); // 返回 { address: string, port: number } 或 null
|
const clientInfo = server.requestIP(request); // 返回 { address: string, port: number } 或 null
|
||||||
const url = new URL(request.url, `http://${host}`);
|
const url = new URL(request.url, `http://${host}`);
|
||||||
@@ -72,6 +72,7 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
|
|
||||||
// 将 Bun 的 Request 转换为 Node.js 风格的 req/res
|
// 将 Bun 的 Request 转换为 Node.js 风格的 req/res
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
|
const reqListener: { event: string; listener: Function }[] = [];
|
||||||
const req: RouterReq = {
|
const req: RouterReq = {
|
||||||
url: url.pathname + url.search,
|
url: url.pathname + url.search,
|
||||||
method: request.method,
|
method: request.method,
|
||||||
@@ -81,12 +82,29 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
remoteAddress: request?.remoteAddress || request?.ip || clientInfo?.address || '',
|
remoteAddress: request?.remoteAddress || request?.ip || clientInfo?.address || '',
|
||||||
remotePort: clientInfo?.port || 0,
|
remotePort: clientInfo?.port || 0,
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
on: (event: string, listener: Function) => {
|
||||||
|
reqListener.push({ event, listener });
|
||||||
|
},
|
||||||
bun: {
|
bun: {
|
||||||
request, // 原始请求对象
|
request, // 原始请求对象
|
||||||
server, // 原始服务器对象
|
server, // 原始服务器对象
|
||||||
|
resolve
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const onClose = () => {
|
||||||
|
reqListener.forEach(item => {
|
||||||
|
if (item.event === 'close') {
|
||||||
|
item.listener();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
reqListener.length = 0;
|
||||||
|
}
|
||||||
|
// 监听请求的取消事件
|
||||||
|
if (request.signal) {
|
||||||
|
request.signal.addEventListener('abort', () => {
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const res: RouterRes = {
|
const res: RouterRes = {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -143,7 +161,7 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
pipe(stream: any) {
|
pipe(stream: ReadableStream | NodeJS.ReadableStream) {
|
||||||
this.writableEnded = true;
|
this.writableEnded = true;
|
||||||
|
|
||||||
// 如果是 ReadableStream,直接使用
|
// 如果是 ReadableStream,直接使用
|
||||||
@@ -164,6 +182,7 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
controller.enqueue(chunk);
|
controller.enqueue(chunk);
|
||||||
});
|
});
|
||||||
stream.on('end', () => {
|
stream.on('end', () => {
|
||||||
|
onClose();
|
||||||
controller.close();
|
controller.close();
|
||||||
});
|
});
|
||||||
stream.on('error', (err: any) => {
|
stream.on('error', (err: any) => {
|
||||||
@@ -171,9 +190,9 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
cancel() {
|
cancel() {
|
||||||
if (stream.destroy) {
|
// 只有NODE流才有destroy方法
|
||||||
stream.destroy();
|
// @ts-ignore
|
||||||
}
|
stream?.destroy?.();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,12 @@ export type RouterReq<T = {}> = {
|
|||||||
};
|
};
|
||||||
body?: string;
|
body?: string;
|
||||||
cookies?: Record<string, string>;
|
cookies?: Record<string, string>;
|
||||||
|
bun?: {
|
||||||
|
request: Bun.BunRequest;
|
||||||
|
server: Bun.Server<{}>;
|
||||||
|
resolve: (response: Response) => void;
|
||||||
|
}
|
||||||
|
on: (event: 'close', listener: Function) => void;
|
||||||
} & T;
|
} & T;
|
||||||
|
|
||||||
export type RouterRes<T = {}> = {
|
export type RouterRes<T = {}> = {
|
||||||
@@ -116,6 +122,6 @@ export type RouterRes<T = {}> = {
|
|||||||
setHeader: (name: string, value: string | string[]) => void;
|
setHeader: (name: string, value: string | string[]) => void;
|
||||||
cookie: (name: string, value: string, options?: any) => void;
|
cookie: (name: string, value: string, options?: any) => void;
|
||||||
write: (chunk: any) => void;
|
write: (chunk: any) => void;
|
||||||
pipe: (stream: any) => void;
|
pipe: (stream: ReadableStream) => void;
|
||||||
end: (data?: any) => void;
|
end: (data?: any) => void;
|
||||||
} & T;
|
} & T;
|
||||||
Reference in New Issue
Block a user