Skip to content

Commit

Permalink
feat: add chunkTemplate config
Browse files Browse the repository at this point in the history
  • Loading branch information
hans000 committed Aug 22, 2024
1 parent 5415209 commit 7af4937
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 47 deletions.
3 changes: 2 additions & 1 deletion readme-zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@
|redirectUrl|string|重定向链接,不能和url一样,会死循环|
|groupId|string|分组id,相同的id会被分配到相同的工作空间|
|chunks|string[]|设置event-source数据源,response、responseText会失效|
|chunkSpeed|number|设置数据吐出的间隔,默认1_000|
|chunkInterval|number|设置数据吐出的间隔,默认1_000|
|chunkTemplate|number|设置数据的格式,默认`data: $1\n\n`|

### code面板
通过指定的hooks来动态的修改数据,支持的hooks有
Expand Down
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ How to solve the above problems? If you can intercept and modify the data before
|redirectUrl|string|cannot be the same as the url, will cause a loop|
|groupId|string|the same group can be used a workspace|
|chunks|string[]|set event-source data source,response、responseText would be overrided|
|chunkSpeed|number|set the interval of chunk,default 1_000|
|chunkInterval|number|set the interval of chunk,default 1_000|
|chunkTemplate|number|set the chunk format,default `data: $1\n\n`|

### Code Panel
call hooks function to modify data, support there hooks
Expand Down
6 changes: 4 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export interface MatchRule {
code?: string
redirectUrl?: string
chunks?: string[]
chunkSpeed?: number
chunkInterval?: number
chunkTemplate?: string
}

if (!process.env.VITE_LOCAL) {
Expand Down Expand Up @@ -79,7 +80,8 @@ const fields = [
'response',
'responseText',
'chunks',
'chunkSpeed',
'chunkInterval',
'chunkTemplate',
]

const isDarkTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
Expand Down
56 changes: 28 additions & 28 deletions src/components/MainEditor/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ export const ConfigSchema: JSONSchema7 = {
},
chunks: {
type: 'array',
items: {
type: 'string'
}
},
chunkSpeed: {
chunkInterval: {
type: 'number'
},
chunkTemplate: {
type: 'string'
}
},
}
Expand Down Expand Up @@ -179,29 +179,29 @@ export const SettingSchema: JSONSchema7 = {
dark: {
type: 'boolean'
},
proxy: {
type: 'object',
patternProperties: {
".+": {
oneOf: [
{
type: 'string'
},
{
type: 'object',
required: ['target'],
properties: {
target: {
type: 'string'
},
rewrite: {
type: 'string'
}
}
}
]
}
}
}
// proxy: {
// type: 'object',
// patternProperties: {
// ".+": {
// oneOf: [
// {
// type: 'string'
// },
// {
// type: 'object',
// required: ['target'],
// properties: {
// target: {
// type: 'string'
// },
// rewrite: {
// type: 'string'
// }
// }
// }
// ]
// }
// }
// }
}
}
33 changes: 24 additions & 9 deletions src/injected/proxy/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* The AGPL License (AGPL)
* Copyright (c) 2022 hans000
*/
import { asyncGenerator, delayRun, tryToProxyUrl } from "../../tools";
import { asyncGenerator, delayRun, formatChunk, tryToProxyUrl } from "../../tools";
import { log } from "../../tools/log";
import { parseUrl } from "../../tools";
import { Options, __global__ } from "./globalVar";
Expand All @@ -21,7 +21,7 @@ export function proxyFetch(options: Options) {

const proxyFetch = new Proxy(__global__.NativeFetch, {
async apply(target, thisArg, args) {
const [input, init] = args
const [input, init] = args as [Request | URL | string, RequestInit]
const isRequest = input instanceof Request
const req = isRequest ? input.clone() : new Request(input.toString(), init)
const url = isRequest
Expand All @@ -35,6 +35,19 @@ export function proxyFetch(options: Options) {
type: 'fetch',
params: [...url.searchParams.entries()],
})

if (matchItem?.requestHeaders) {
Object.entries(matchItem.requestHeaders).forEach(([key, value]) => {
if (init.headers instanceof Headers) {
init.headers.append(key, value)
} else if (Array.isArray(init.headers)) {
init.headers.push([key, value])
} else if (typeof init.headers === 'object') {
init.headers[key] = value
}
})
}

const realFetch = __global__.PageFetch || target
const proxyUrl = tryToProxyUrl(input, __global__.options.proxy)
const proxyInput = isRequest ? new Request(proxyUrl, init) : proxyUrl
Expand All @@ -49,26 +62,28 @@ export function proxyFetch(options: Options) {
...init,
})
}
const realResponse = options.faked
? new Response(new Blob(['null']))

const chunks = matchItem.chunks || []
const isEventSource = !!chunks.length
const realResponse = (options.faked || isEventSource)
? new Response(new Blob(['null']), init)
: await realFetch.call(thisArg, proxyInput, init)
const response = await onFetchIntercept(matchItem)(realResponse)

return new Promise(resolve => {
delayRun(async () => {
let res: Response = response || realResponse

const chunks = matchItem.chunks || []
const isEventSource = !!chunks.length
if (isEventSource) {
res = new Response(new ReadableStream({
async start(controller) {
for await (const value of asyncGenerator(chunks, matchItem.chunkSpeed)) {
controller.enqueue(new TextEncoder().encode(value));
for await (const value of asyncGenerator(chunks, matchItem.chunkInterval)) {
const str = formatChunk(value, matchItem.chunkTemplate)
controller.enqueue(new TextEncoder().encode(str));
}
controller.close();
},
}))
}), init)
}

resolve(res)
Expand Down
7 changes: 4 additions & 3 deletions src/injected/proxy/handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { MatchRule } from "../../App"
import { asyncGenerator, delayRun, modifyXhrProto, modifyXhrProtoProps, toTitleCase, tryToProxyUrl } from "../../tools"
import { asyncGenerator, delayRun, formatChunk, modifyXhrProto, modifyXhrProtoProps, toTitleCase, tryToProxyUrl } from "../../tools"
import { log } from "../../tools/log"
import { parseUrl, parseXML, stringifyHeaders } from "../../tools"
import { HttpStatusCodes } from "./constants"
Expand Down Expand Up @@ -203,9 +203,10 @@ export function proxyFakeXhrInstance(inst: ProxyXMLHttpRequest, options: Options
if (isEventSource) {
// @ts-ignore inst field has been proxy
inst.responseText = ''
for await (const item of asyncGenerator(inst._matchItem.chunks, inst._matchItem.chunkSpeed)) {
for await (const item of asyncGenerator(inst._matchItem.chunks, inst._matchItem.chunkInterval)) {
const str = formatChunk(item, matchItem.chunkTemplate)
// @ts-ignore inst field has been proxy
inst.responseText += item
inst.responseText += str
handleStateChange.call(inst, XMLHttpRequest.LOADING)
}
}
Expand Down
14 changes: 11 additions & 3 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ export function createSymbol(attr: string) {
return Symbol.for(attr)
}

export async function* asyncGenerator(data: string[], delay = 1000) {
for (const item of data) {
export function formatChunk(chunk: string, tpl = 'data: $1\n\n') {
return tpl.replace('$1', chunk)
}

export async function* asyncGenerator(data: unknown[], delay = 1000) {
const list = data.map(item => typeof item !== 'string' ? JSON.stringify(item) : item)
for (const item of list) {
await new Promise(resolve => setTimeout(resolve, delay))
yield item
}
Expand Down Expand Up @@ -235,10 +240,13 @@ export function toTitleCase(str = '') {
return str.replace(/\b[a-z]/g, c => c.toUpperCase())
}

export function tryToProxyUrl(url: string | URL, proxy: Record<string, string | {
export function tryToProxyUrl(url: string | URL | Request, proxy: Record<string, string | {
target: string
rewrite?: string
}> = {}) {
if (url instanceof Request) {
return url.url
}
const urlObj = url instanceof URL ? url : parseUrl(url)
for (const [name, value] of Object.entries(proxy)) {
try {
Expand Down

0 comments on commit 7af4937

Please sign in to comment.