globalFetch 함수 코드 개선

This commit is contained in:
testman
2024-03-25 05:26:35 +09:00
parent 4a7f249db4
commit 7444090c9c

View File

@@ -488,7 +488,33 @@ export async function loadData() {
} }
} }
const knownHostes = ["localhost","127.0.0.1"] export async function getFetchData(id:string) {
for(const log of fetchLog){
if(log.chatId === id){
return log
}
}
return null
}
const knownHostes = ["localhost","127.0.0.1","0.0.0.0"]
interface GlobalFetchArgs {
plainFetchForce?: boolean;
body?: any;
headers?: { [key: string]: string };
rawResponse?: boolean;
method?: 'POST' | 'GET';
abortSignal?: AbortSignal;
useRisuToken?: boolean;
chatId?: string;
}
interface GlobalFetchResult {
ok: boolean;
data: any;
headers: { [key: string]: string };
}
export function addFetchLog(arg:{ export function addFetchLog(arg:{
body:any, body:any,
@@ -512,43 +538,44 @@ export function addFetchLog(arg:{
return fetchLog.length - 1 return fetchLog.length - 1
} }
export async function getFetchData(id:string) {
for(const log of fetchLog){
if(log.chatId === id){
return log
}
}
return null
}
export async function globalFetch(url:string, arg:{
plainFetchForce?:boolean, export async function globalFetch(url: string, arg: GlobalFetchArgs = {}): Promise<GlobalFetchResult> {
body?:any,
headers?:{[key:string]:string},
rawResponse?:boolean,
method?:"POST"|"GET",
abortSignal?:AbortSignal,
useRisuToken?:boolean,
chatId?:string
} = {}): Promise<{
ok: boolean;
data: any;
headers:{[key:string]:string},
}> {
try { try {
const db = get(DataBase) const db = get(DataBase)
const method = arg.method ?? "POST" const method = arg.method ?? "POST"
db.requestmet = "normal" db.requestmet = "normal"
if(arg.abortSignal && arg.abortSignal.aborted){ if (arg.abortSignal?.aborted) { return { ok: false, data: 'aborted', headers: {} }}
return {
ok: false,
data: 'aborted',
headers: {}
}
}
function addFetchLog(response:any, success:boolean){ const urlHost = new URL(url).hostname
const forcePlainFetch = (knownHostes.includes(urlHost) && !isTauri) || db.usePlainFetch || arg.plainFetchForce
if (knownHostes.includes(urlHost) && !isTauri && !isNodeServer)
return { ok: false, headers: {}, data: 'You are trying local request on web version. This is not allowed due to browser security policy. Use the desktop version instead, or use a tunneling service like ngrok and set the CORS to allow all.' }
// Simplify the globalFetch function: Detach built-in functions
const fetchData = async (url, arg) => {
if (forcePlainFetch) {
return await fetchWithPlainFetch(url, arg);
}
if (isTauri) {
return await fetchWithTauri(url, arg);
}
if (Capacitor.isNativePlatform()) {
return await fetchWithCapacitor(url, arg);
}
return await fetchWithProxy(url, arg);
};
} catch (error) {
console.error(error);
return { ok: false, data: `${error}`, headers: {} };
}
}
// Decoupled globalFetch built-in function
function addFetchLogInGlobalFetch(response:any, success:boolean, url:string, arg:GlobalFetchArgs){
try{ try{
fetchLog.unshift({ fetchLog.unshift({
body: JSON.stringify(arg.body, null, 2), body: JSON.stringify(arg.body, null, 2),
@@ -571,251 +598,102 @@ export async function globalFetch(url:string, arg:{
chatId: arg.chatId chatId: arg.chatId
}) })
} }
} }
const urlHost = (new URL(url)).hostname // Decoupled globalFetch built-in function
let forcePlainFetch = (knownHostes.includes(urlHost) && (!isTauri)) || db.usePlainFetch || arg.plainFetchForce async function fetchWithPlainFetch(url: string, arg: GlobalFetchArgs): Promise<GlobalFetchResult> {
//check if the url is a local url like localhost
if(urlHost.includes("localhost") || urlHost.includes("172.0.0.1") || urlHost.includes("0.0.0.0")){
if((!isTauri) && (!isNodeServer)){
return {
ok: false,
data: 'You are trying local request on web version. this is not allowed dude to browser security policy. use the desktop version instead, or use tunneling service like ngrok and set the cors to allow all.',
headers: {}
}
}
}
if(forcePlainFetch){
try { try {
let headers = arg.headers ?? {} const headers = { 'Content-Type': 'application/json', ...arg.headers };
if(!headers["Content-Type"]){ const response = await fetch(new URL(url), { body: JSON.stringify(arg.body), headers, method: arg.method, signal: arg.abortSignal });
headers["Content-Type"] = `application/json` const data = arg.rawResponse ? new Uint8Array(await response.arrayBuffer()) : await response.json();
} const ok = response.ok && response.status >= 200 && response.status < 300;
const furl = new URL(url) addFetchLogInGlobalFetch(data, ok, url, arg);
return { ok, data, headers: Object.fromEntries(response.headers) };
const da = await fetch(furl, {
body: JSON.stringify(arg.body),
headers: arg.headers,
method: method,
signal: arg.abortSignal
})
if(arg.rawResponse){
addFetchLog("Uint8Array Response", da.ok && da.status >= 200 && da.status < 300)
return {
ok: da.ok && da.status >= 200 && da.status < 300,
data: new Uint8Array(await da.arrayBuffer()),
headers: Object.fromEntries(da.headers)
}
}
else{
const dat = await da.json()
addFetchLog(dat, da.ok && da.status >= 200 && da.status < 300)
return {
ok: da.ok && da.status >= 200 && da.status < 300,
data: dat,
headers: Object.fromEntries(da.headers)
}
}
} catch (error) { } catch (error) {
return { return { ok: false, data: `${error}`, headers: {} };
ok: false,
data: `${error}`,
headers: {}
} }
} }
}
if(isTauri){ // Decoupled globalFetch built-in function
const body = (!arg.body) ? null : async function fetchWithTauri(url: string, arg: GlobalFetchArgs): Promise<GlobalFetchResult> {
(arg.body instanceof URLSearchParams) ? (Body.text(arg.body.toString())) : (Body.json(arg.body)) const body = !arg.body ? null : arg.body instanceof URLSearchParams ? Body.text(arg.body.toString()) : Body.json(arg.body);
const headers = arg.headers ?? {} const headers = arg.headers ?? {};
const fetchPromise = TauriFetch(url, { const fetchPromise = TauriFetch(url, {
body: body, body,
method: method, method: arg.method,
headers: headers, headers,
timeout: { timeout: { secs: get(DataBase).timeOut, nanos: 0 },
secs: db.timeOut,
nanos: 0
},
responseType: arg.rawResponse ? ResponseType.Binary : ResponseType.JSON, responseType: arg.rawResponse ? ResponseType.Binary : ResponseType.JSON,
});
}) let abortFn = () => {};
const abortPromise = new Promise<"aborted">((res, rej) => {
abortFn = () => res("aborted");
arg.abortSignal?.addEventListener('abort', abortFn);
});
//abort the promise when abort signal is triggered const result = await Promise.any([fetchPromise, abortPromise]);
let abortFn:() => void = () => {} arg.abortSignal?.removeEventListener('abort', abortFn);
const abortPromise = (new Promise<"aborted">((res,rej) => { if (result === 'aborted') {
abortFn = () => { return { ok: false, data: 'aborted', headers: {} };
res("aborted")
}
if(arg.abortSignal){
arg.abortSignal?.addEventListener('abort', abortFn)
}
}))
const result = await Promise.any([fetchPromise,abortPromise])
if(arg.abortSignal){
arg.abortSignal.removeEventListener('abort', abortFn)
} }
if(result === 'aborted'){ const data = arg.rawResponse ? new Uint8Array(result.data as number[]) : result.data;
return { addFetchLogInGlobalFetch(data, result.ok, url, arg);
ok: false, return { ok: result.ok, data, headers: result.headers };
data: 'aborted', }
headers: {}
}
}
if(arg.rawResponse){ // Decoupled globalFetch built-in function
addFetchLog("Uint8Array Response", result.ok) async function fetchWithCapacitor(url: string, arg: GlobalFetchArgs): Promise<GlobalFetchResult> {
return { const { body, headers = {}, rawResponse } = arg;
ok: result.ok, headers["Content-Type"] = body instanceof URLSearchParams ? "application/x-www-form-urlencoded" : "application/json";
data: new Uint8Array(result.data as number[]),
headers: result.headers const res = await CapacitorHttp.request({ url, method: arg.method, headers, data: body, responseType: rawResponse ? "arraybuffer" : "json" });
}
} addFetchLogInGlobalFetch(rawResponse ? "Uint8Array Response" : res.data, true, url, arg);
else{
addFetchLog(result.data, result.ok)
return {
ok: result.ok,
data: result.data,
headers: result.headers
}
}
}
else if (Capacitor.isNativePlatform()){
const body = arg.body
const headers = arg.headers ?? {}
if(arg.body instanceof URLSearchParams){
if(!headers["Content-Type"]){
headers["Content-Type"] = `application/x-www-form-urlencoded`
}
}
else{
if(!headers["Content-Type"]){
headers["Content-Type"] = `application/json`
}
}
const res = await CapacitorHttp.request({
url: url,
method: method,
headers: headers,
data: body,
responseType: arg.rawResponse ? 'arraybuffer' : 'json'
})
if(arg.rawResponse){
addFetchLog("Uint8Array Response", true)
return { return {
ok: true, ok: true,
data: new Uint8Array(res.data as ArrayBuffer), data: rawResponse ? new Uint8Array(res.data as ArrayBuffer) : res.data,
headers: res.headers headers: res.headers,
} };
} }
addFetchLog(res.data, true)
return {
ok: true,
data: res.data,
headers: res.headers
}
}
else{
try {
let body:any
if(arg.body instanceof URLSearchParams){
const argBody = arg.body as URLSearchParams
body = argBody.toString()
let headers = arg.headers ?? {}
if(!headers["Content-Type"]){
headers["Content-Type"] = `application/x-www-form-urlencoded`
}
}
else{
body = JSON.stringify(arg.body)
let headers = arg.headers ?? {}
if(!headers["Content-Type"]){
headers["Content-Type"] = `application/json`
}
}
if(arg.rawResponse){
const furl = ((!isTauri) && (!isNodeServer)) ? `${hubURL}/proxy2` : `/proxy2`
let headers = { // Decoupled globalFetch built-in function
async function fetchWithProxy(url: string, arg: GlobalFetchArgs): Promise<GlobalFetchResult> {
try {
const furl = !isTauri && !isNodeServer ? `${hubURL}/proxy2` : `/proxy2`;
const headers = {
"risu-header": encodeURIComponent(JSON.stringify(arg.headers)), "risu-header": encodeURIComponent(JSON.stringify(arg.headers)),
"risu-url": encodeURIComponent(url), "risu-url": encodeURIComponent(url),
"Content-Type": "application/json", "Content-Type": arg.body instanceof URLSearchParams ? "application/x-www-form-urlencoded" : "application/json",
} ...(arg.useRisuToken && { "x-risu-tk": "use" }),
if(arg.useRisuToken){ };
headers["x-risu-tk"] = "use"
const body = arg.body instanceof URLSearchParams ? arg.body.toString() : JSON.stringify(arg.body);
const response = await fetch(furl, { body, headers, method: arg.method, signal: arg.abortSignal });
const isSuccess = response.ok && response.status >= 200 && response.status < 300;
if (arg.rawResponse) {
const data = new Uint8Array(await response.arrayBuffer());
addFetchLogInGlobalFetch("Uint8Array Response", isSuccess, url, arg);
return { ok: isSuccess, data, headers: Object.fromEntries(response.headers) };
} }
const da = await fetch(furl, { const text = await response.text();
body: body,
headers: headers,
method: method,
signal: arg.abortSignal
})
addFetchLog("Uint8Array Response", da.ok && da.status >= 200 && da.status < 300)
return {
ok: da.ok && da.status >= 200 && da.status < 300,
data: new Uint8Array(await da.arrayBuffer()),
headers: Object.fromEntries(da.headers)
}
}
else{
const furl = ((!isTauri) && (!isNodeServer)) ? `${hubURL}/proxy2` : `/proxy2`
let headers = {
"risu-header": encodeURIComponent(JSON.stringify(arg.headers)),
"risu-url": encodeURIComponent(url),
"Content-Type": "application/json"
}
if(arg.useRisuToken){
headers["x-risu-tk"] = "use"
}
const da = await fetch(furl, {
body: body,
headers: headers,
method: method
})
const daText = await da.text()
try { try {
const dat = JSON.parse(daText) const data = JSON.parse(text);
addFetchLog(dat, da.ok && da.status >= 200 && da.status < 300) addFetchLogInGlobalFetch(data, isSuccess, url, arg);
return { return { ok: isSuccess, data, headers: Object.fromEntries(response.headers) };
ok: da.ok && da.status >= 200 && da.status < 300, } catch (error) {
data: dat, const errorMsg = text.startsWith('<!DOCTYPE') ? "Responded HTML. Is your URL, API key, and password correct?" : text;
headers: Object.fromEntries(da.headers) addFetchLogInGlobalFetch(text, false, url, arg);
return { ok: false, data: errorMsg, headers: Object.fromEntries(response.headers) };
} }
} catch (error) { } catch (error) {
addFetchLog(daText, false) return { ok: false, data: `${error}`, headers: {} };
let errorMsg = (daText.startsWith('<!DOCTYPE')) ? ("Responded HTML. is your url, api key and password correct?") : (daText)
return {
ok:false,
data: errorMsg,
headers: Object.fromEntries(da.headers)
}
}
}
} catch (error) {
return {
ok:false,
data: `${error}`,
headers: {}
}
}
}
} catch (error) {
console.error(error)
return {
ok:false,
data: `${error}`,
headers: {}
}
} }
} }