2025-04-25 16:37:03 +08:00

104 lines
1.9 KiB
TypeScript

import { useBase } from '/$/base';
import { config } from '/@/config';
export function useStream() {
const { user } = useBase();
let abortController: AbortController | null = null;
// 调用
async function invoke({
url,
method = 'POST',
data,
cb
}: {
url: string;
method?: string;
data?: any;
cb?: (result: any) => void;
}) {
abortController = new AbortController();
let cacheText = '';
return fetch(config.baseUrl + url, {
method,
headers: {
Authorization: user.token,
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
signal: abortController?.signal
})
.then(res => {
if (res.body) {
const reader = res.body.getReader();
const decoder = new TextDecoder('utf-8');
const stream = new ReadableStream({
start(controller) {
function push() {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
return;
}
let text = decoder.decode(value, { stream: true });
if (cb) {
if (cacheText) {
text = cacheText + text;
}
if (text.indexOf('data:') == 0) {
text = '\n\n' + text;
}
try {
const arr = text
.split(/\n\ndata:/g)
.filter(Boolean)
.map(e => JSON.parse(e));
arr.forEach(cb);
cacheText = '';
} catch (err) {
console.error('[parse text]', text);
cacheText = text;
}
}
controller.enqueue(text);
push();
});
}
push();
}
});
return new Response(stream);
}
return res;
})
.catch(err => {
console.error(err);
throw err;
});
}
// 取消
function cancel() {
if (abortController) {
abortController.abort();
abortController = null;
}
}
return {
invoke,
cancel
};
}