wip: refine code

This commit is contained in:
daief
2020-12-11 13:50:29 +08:00
parent 49bf7cd278
commit ec85ffa3c1
4 changed files with 106 additions and 91 deletions

View File

@@ -21,8 +21,9 @@
<div v-for="(rule, idx2) in it.rules" :key="idx2">
<div>
<label>rule-{{ idx2 }}:</label>
<div>apiTest: <input v-model="rule.apiTest" /></div>
<div>apiTest2: <input v-model="rule.apiTest" /></div>
<div>
apiTest: <input v-model="rule.apiTest" style="width: 300px" />
</div>
<div>response: <textarea v-model="rule.response" /></div>
</div>
</div>
@@ -49,7 +50,6 @@ export default defineComponent({
onMounted(() => {
state.matchedSetList = Store.getMatchedSetList();
console.log(state.matchedSetList);
});
watch(
@@ -73,14 +73,11 @@ export default defineComponent({
show.value = false;
},
handleAdd: () => {
state.matchedSetList = [
{
domainTest: location.hostname,
rules: [],
id: uuid4(),
},
...state.matchedSetList,
];
state.matchedSetList.unshift({
domainTest: location.hostname,
rules: [],
id: uuid4(),
});
},
handleAddRule: (i: number) => {
state.matchedSetList[i].rules.push({

View File

@@ -5,6 +5,7 @@ export const cache = new WeakMap<
{
method: string;
url: string;
[k: string]: any;
}
>();

View File

@@ -1,63 +1,82 @@
import { cache, safeParse, vmCtx } from '@/common';
import { cache, vmCtx } from '@/common';
import { Store } from '@/data';
const originalFetch = vmCtx.fetch;
const originalJson = Response.prototype.json;
const originalText = Response.prototype.text;
function proxyRes(response: Response) {
const ruleSet = Store.findCurrentSet();
const matchedRule = ruleSet.rules.find(it =>
response.url.includes(it.apiTest)
);
const res = matchedRule?.response;
const payload = cache.get(response);
return matchedRule?.response;
}
if (res) {
GM_log(
`❗️ [fetch] Response is proxyed:\n`,
`${payload?.method || ''} ${response.url}\n`,
safeParse(res)
);
}
return res;
function log({ method, url, status, response }: any) {
GM_log(`❗️ [fetch] Response is proxyed:\n`);
console.table({
method,
url,
status,
'proxyed response': response,
});
}
if (typeof Response !== 'undefined') {
const nativeFetch = vmCtx.fetch;
const nativeJson = Response.prototype.json;
const nativeText = Response.prototype.text;
Response.prototype.json = async function (this: Response, ...args) {
const nativeRes = await originalJson.apply(this, args);
const res = proxyRes(this);
if (res) {
try {
return JSON.parse(res);
} catch (error) {
console.warn(
`❌ Error when parse proxy response for [${this.url}]. Use original result.`
);
return nativeRes;
}
const nativeRes = await nativeJson.apply(this, args);
const payload = cache.get(this);
if (payload?.proxyedResponse) {
log({
method: payload.method,
url: this.url,
status: this.status,
response: payload.proxyedResponse,
});
return JSON.parse(payload.proxyedResponse);
}
return nativeRes;
};
Response.prototype.text = async function (this: Response, ...args) {
const nativeRes = await originalText.apply(this, args);
const res = proxyRes(this);
if (res) {
return res;
const nativeRes = await nativeText.apply(this, args);
const payload = cache.get(this);
if (payload?.proxyedResponse) {
log({
method: payload.method,
url: this.url,
status: this.status,
response: payload.proxyedResponse,
});
return payload.proxyedResponse;
}
return nativeRes;
};
vmCtx.fetch = async function (...args) {
const res: Response = await originalFetch.apply(this, args);
vmCtx.fetch = async function (input: RequestInfo, init?: RequestInit) {
let method = 'GET';
if (input instanceof Request) {
method = input.method;
} else {
method = init?.method || method;
}
const res: Response = await nativeFetch.apply(this, [input, init]);
const proxyedResponse = proxyRes(res);
cache.set(res, {
method: args[1]?.method || 'GET',
method,
url: res.url,
proxyedResponse,
});
return res;
};
}

View File

@@ -1,58 +1,56 @@
import { cache, safeParse } from '@/common';
import { vmCtx } from '@/common';
import { Store } from '@/data';
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
const NativeXMLHttpRequest = vmCtx.XMLHttpRequest;
XMLHttpRequest.prototype.open = function (...args: any[]) {
cache.set(this, {
method: args[0],
url: args[1],
});
return originalOpen.apply(this, args);
};
XMLHttpRequest.prototype.send = function (
this: XMLHttpRequest,
...args: any[]
vmCtx.XMLHttpRequest = class extends (
NativeXMLHttpRequest
) {
this.addEventListener(
'readystatechange',
function () {
const payload = cache.get(this);
#mockResponse: string;
#url: string;
#method: string;
#proxyed: boolean = false;
if (!payload) {
return;
}
constructor() {
super();
const ruleSet = Store.findCurrentSet();
const matchedRule = ruleSet.rules.find(it =>
payload.url.includes(it.apiTest)
);
['load', 'error'].forEach(ev => {
this.addEventListener(ev, () => {
if (!this.#proxyed) return;
if (matchedRule?.response && this.readyState === 3) {
Object.defineProperty(this, 'response', {
writable: true,
});
Object.defineProperty(this, 'responseText', {
writable: true,
GM_log(`❗️ [XHR] Response is proxyed:\n`);
console.table({
method: this.#method,
url: this.#url,
status: this.status,
'proxyed response': this.#mockResponse,
});
});
});
}
// @ts-ignore
this.response = matchedRule.response;
// @ts-ignore
this.responseText = matchedRule.response;
get response() {
return this.#mockResponse || super.response;
}
GM_log(
`❗️ [XHR] Response is proxyed:\n`,
`${payload.method} ${payload.url}\n`,
safeParse(matchedRule.response)
);
}
},
{
capture: true,
get responseText() {
return this.#mockResponse || super.responseText;
}
open(method: string, url: string): void {
this.#method = method;
this.#url = url;
const ruleSet = Store.findCurrentSet();
const matchedRule = ruleSet.rules.find(it =>
this.#url.includes(it.apiTest)
);
if (matchedRule?.response) {
this.#mockResponse = matchedRule.response;
this.#proxyed = true;
}
);
return originalSend.apply(this, args);
return super.open(method, url);
}
};