You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/new/ui/assets/api.js

130 lines
3.1 KiB
JavaScript

/*
* api.js
* Copyright (C) 2024 veypi <i@veypi.com>
*
* Distributed under terms of the MIT license.
*/
class API {
prefix = ''
fetch = window.fetch
constructor(prefix, fetch) {
if (fetch) {
this.fetch = fetch
}
if (typeof prefix === 'string') {
this.prefix = prefix
}
if (!this.prefix.endsWith('/')) {
this.prefix += '/'
}
}
wrapFetch(fetch) {
this.fetch = fetch
}
wrapUrl(url) {
if (url.startsWith('http')) {
return url
} else if (url.startsWith('/')) {
return this.prefix + url.slice(1)
} else {
return this.prefix + url
}
}
async Fetch(url, method, opts, body) {
url = this.wrapUrl(url)
if (!opts) {
opts = {}
}
if (!opts.headers) {
opts.headers = {}
}
opts.method = method
opts.body = JSON.stringify(body)
if (!opts.headers['Content-Type']) {
opts.headers['Content-Type'] = 'application/json'
}
if (opts.query && Object.keys(opts.query).length && url.indexOf('?') === -1) {
url += '?' + new URLSearchParams(opts.query).toString()
}
return this.fetch.bind(window)(url, opts).then((response) => {
if (!response.ok) {
throw response
}
let contentType = response.headers.get('content-type')
if (contentType && contentType.includes('application/json')) {
return response.json()
}
return response.text()
}).then(data => {
if (typeof data === 'string') {
return data
}
if (data.code === 0) {
return data.data
} else if (data.code >= 0) {
throw new Error(JSON.stringify(data))
} else {
return data
}
})
}
async Get(url, opts) {
return this.Fetch(url, 'GET', opts)
}
async Post(url, data, opts) {
return this.Fetch(url, 'POST', opts, data)
}
async Put(url, data, opts) {
return this.Fetch(url, 'PUT', opts, data)
}
async Delete(url, opts) {
return this.Fetch(url, 'DELETE', opts)
}
async Patch(url, data, opts) {
return this.Fetch(url, 'PATCH', opts, data)
}
async SSE(url, opts, cb) {
url = this.wrapUrl(url)
let response = await this.fetch.bind(window)(url, opts)
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let count = 0
let partialLine = ''
try {
while (true) {
const { done, value } = await reader.read();
if (done) break; // 结束时退出循环
// 将Uint8Array转换为字符串
const chunk = decoder.decode(value, { stream: true });
// 处理可能跨多个块的消息
const lines = (partialLine + chunk).split('\n');
partialLine = lines.pop(); // 最后一行可能是未完成的消息
for (const line of lines) {
cb(line, count++)
}
}
// 处理最后一个不完整的行
if (partialLine) {
cb(partialLine, count++)
}
} catch (error) {
console.error(error);
} finally {
reader.releaseLock();
cb('', -1)
}
}
New(prefix) {
return new API(prefix, this.fetch)
}
}
export default new API()