Browse Source

Partial IPC system rewrite

pull/46/head
coomdev 2 years ago
parent
commit
f038fd42bd
  1. 2
      README.md
  2. 100
      chrome/dist/background.js
  3. 199
      chrome/dist/main.js
  4. 2
      chrome/manifest.json
  5. 282
      dist/main.js
  6. 100
      firefox/dist/background.js
  7. 203
      firefox/dist/main.js
  8. 2
      firefox/manifest.json
  9. 2
      firefox_update.json
  10. 2
      main.meta.js
  11. 284
      main.user.js
  12. BIN
      pngextraembedder-0.300.xpi
  13. 86
      src/background.ts
  14. 65
      src/f5stego.ts
  15. 219
      src/main.ts
  16. 38
      src/platform.ts
  17. 77
      src/processor.worker.ts

2
README.md

@ -25,7 +25,7 @@ Please report any issue you have with those (only for mainstream browsers)
Also, use this if you plan to use b4k's archive. Also, use this if you plan to use b4k's archive.
- [Install 4chanX (recommended)](https://www.4chan-x.net/builds/4chan-X.user.js) - [Install 4chanX (recommended)](https://www.4chan-x.net/builds/4chan-X.user.js)
- Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.299.xpi) or Chrome-based (Down for "maintainance")) - Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.300.xpi) or Chrome-based (Down for "maintainance"))
For FF users, the extension is signed so you can just drag and drop it on your about:addons tab. For FF users, the extension is signed so you can just drag and drop it on your about:addons tab.

100
chrome/dist/background.js

@ -1879,10 +1879,7 @@
var port1; var port1;
console.log("chrome_api", true); console.log("chrome_api", true);
if (false) { if (false) {
const nmc = new MessageChannel(); iframe = document.createElement("iframe");
port1 = nmc.port1;
port2 = nmc.port2;
const iframe = document.createElement("iframe");
iframe.style.display = "none"; iframe.style.display = "none";
iframe.name = location.origin; iframe.name = location.origin;
const iframeloaded = new Promise((_) => { const iframeloaded = new Promise((_) => {
@ -1891,13 +1888,12 @@
iframe.src = `${chrome.runtime.getURL("")}options.html`; iframe.src = `${chrome.runtime.getURL("")}options.html`;
document.documentElement.appendChild(iframe); document.documentElement.appendChild(iframe);
iframeloaded.then(() => { iframeloaded.then(() => {
iframe.contentWindow?.postMessage("", "*", [port2]); port1 = genPort();
port1.onmessage = (ev) => {
lqueue[ev.data.id](ev.data);
};
}); });
port1.onmessage = (ev) => {
lqueue[ev.data.id](ev.data);
};
} }
console.log("chrome_api");
if (false) { if (false) {
port1 = { port1 = {
onmessage(ev) { onmessage(ev) {
@ -1913,12 +1909,15 @@
}; };
} }
var gid = 0; var gid = 0;
var sendCmd = (cmd, tr) => { var sendCmd = (cmd, tr, overwrite = false, todelete = false) => {
const prom = new Promise((_) => { const prom = new Promise((_) => {
const id = gid++; const id = gid++;
if (overwrite)
cmd.id = id;
lqueue[id] = (e) => { lqueue[id] = (e) => {
_(e); _(e);
delete lqueue[id]; if (todelete)
delete lqueue[id];
}; };
port1.postMessage({ id, ...cmd }, tr || []); port1.postMessage({ id, ...cmd }, tr || []);
}); });
@ -2019,8 +2018,7 @@
} }
} }
} }
var pendingFetches = /* @__PURE__ */ new Map(); var bgCorsFetch = async (c, pendingFetches, id, input, init) => {
var bgCorsFetch = async (c, id, input, init) => {
if (input.startsWith("//")) if (input.startsWith("//"))
input = "https:" + input; input = "https:" + input;
if (init?.body && true) { if (init?.body && true) {
@ -2106,50 +2104,54 @@
var waitConnect = (cb) => { var waitConnect = (cb) => {
window.addEventListener("message", (msg) => { window.addEventListener("message", (msg) => {
cb(msg.ports[0]); cb(msg.ports[0]);
}); }, { once: true });
}; };
var onMessage = (c, cb) => c.onmessage = (e) => { var onMessage = (c, cb) => c.onmessage = (e) => {
cb(e.data); cb(e.data);
}; };
waitConnect((c) => { (async () => {
onMessage(c, async (obj2) => { while (true) {
const { id, name, args, sid, fid, url } = obj2; const c = await new Promise(waitConnect);
if (name == "keepAlive") { const pendingFetches = /* @__PURE__ */ new Map();
console.log("im alive, tho?"); onMessage(c, async (obj2) => {
return; const { id, name, args, sid, fid, url } = obj2;
} if (name == "keepAlive") {
if (name == "abortCorsFetch") { console.log("im alive, tho?");
return; return;
} }
if (name == "corsFetch") { if (name == "abortCorsFetch") {
bgCorsFetch(c, id, ...args); return;
return; }
} if (name == "corsFetch") {
if (name == "revoke") { bgCorsFetch(c, pendingFetches, id, ...args);
URL.revokeObjectURL(url); return;
c.postMessage({ }
id, if (name == "revoke") {
ok: 1 URL.revokeObjectURL(url);
}); c.postMessage({
return; id,
} ok: 1
if (name == "fullyRead") { });
const obj3 = pendingFetches.get(c); return;
if (obj3 && fid in obj3) }
obj3[fid].fetchFully = true; if (name == "fullyRead") {
const obj3 = pendingFetches.get(c);
if (obj3 && fid in obj3)
obj3[fid].fetchFully = true;
c.postMessage({
id,
ok: 1
});
return;
}
const res = await Platform[name](...args);
c.postMessage({ c.postMessage({
id, id,
ok: 1 res
}); });
return;
}
const res = await Platform[name](...args);
c.postMessage({
id,
res
}); });
}); }
}); })();
})(); })();
/*! /*!
* The buffer module from node.js, for the browser. * The buffer module from node.js, for the browser.

199
chrome/dist/main.js

File diff suppressed because one or more lines are too long

2
chrome/manifest.json

@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "PngExtraEmbedder", "name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!", "description": "Discover embedded files on 4chan and archives!",
"version": "0.298", "version": "0.300",
"icons": { "icons": {
"64": "1449696017588.png" "64": "1449696017588.png"
}, },

282
dist/main.js

File diff suppressed because one or more lines are too long

100
firefox/dist/background.js

@ -1879,10 +1879,7 @@
var port1; var port1;
console.log("ff_api", true); console.log("ff_api", true);
if (false) { if (false) {
const nmc = new MessageChannel(); iframe = document.createElement("iframe");
port1 = nmc.port1;
port2 = nmc.port2;
const iframe = document.createElement("iframe");
iframe.style.display = "none"; iframe.style.display = "none";
iframe.name = location.origin; iframe.name = location.origin;
const iframeloaded = new Promise((_) => { const iframeloaded = new Promise((_) => {
@ -1891,13 +1888,12 @@
iframe.src = `${chrome.runtime.getURL("")}options.html`; iframe.src = `${chrome.runtime.getURL("")}options.html`;
document.documentElement.appendChild(iframe); document.documentElement.appendChild(iframe);
iframeloaded.then(() => { iframeloaded.then(() => {
iframe.contentWindow?.postMessage("", "*", [port2]); port1 = genPort();
port1.onmessage = (ev) => {
lqueue[ev.data.id](ev.data);
};
}); });
port1.onmessage = (ev) => {
lqueue[ev.data.id](ev.data);
};
} }
console.log("ff_api");
if (false) { if (false) {
port1 = { port1 = {
onmessage(ev) { onmessage(ev) {
@ -1913,12 +1909,15 @@
}; };
} }
var gid = 0; var gid = 0;
var sendCmd = (cmd, tr) => { var sendCmd = (cmd, tr, overwrite = false, todelete = false) => {
const prom = new Promise((_) => { const prom = new Promise((_) => {
const id = gid++; const id = gid++;
if (overwrite)
cmd.id = id;
lqueue[id] = (e) => { lqueue[id] = (e) => {
_(e); _(e);
delete lqueue[id]; if (todelete)
delete lqueue[id];
}; };
port1.postMessage({ id, ...cmd }, tr || []); port1.postMessage({ id, ...cmd }, tr || []);
}); });
@ -1984,8 +1983,7 @@
}; };
} }
}, filts, ["blocking", "responseHeaders", ...false ? ["extraHeaders"] : []]); }, filts, ["blocking", "responseHeaders", ...false ? ["extraHeaders"] : []]);
var pendingFetches = /* @__PURE__ */ new Map(); var bgCorsFetch = async (c, pendingFetches, id, input, init) => {
var bgCorsFetch = async (c, id, input, init) => {
if (input.startsWith("//")) if (input.startsWith("//"))
input = "https:" + input; input = "https:" + input;
if (init?.body && false) { if (init?.body && false) {
@ -2071,50 +2069,54 @@
var waitConnect = (cb) => { var waitConnect = (cb) => {
window.addEventListener("message", (msg) => { window.addEventListener("message", (msg) => {
cb(msg.ports[0]); cb(msg.ports[0]);
}); }, { once: true });
}; };
var onMessage = (c, cb) => c.onmessage = (e) => { var onMessage = (c, cb) => c.onmessage = (e) => {
cb(e.data); cb(e.data);
}; };
waitConnect((c) => { (async () => {
onMessage(c, async (obj2) => { while (true) {
const { id, name, args, sid, fid, url } = obj2; const c = await new Promise(waitConnect);
if (name == "keepAlive") { const pendingFetches = /* @__PURE__ */ new Map();
console.log("im alive, tho?"); onMessage(c, async (obj2) => {
return; const { id, name, args, sid, fid, url } = obj2;
} if (name == "keepAlive") {
if (name == "abortCorsFetch") { console.log("im alive, tho?");
return; return;
} }
if (name == "corsFetch") { if (name == "abortCorsFetch") {
bgCorsFetch(c, id, ...args); return;
return; }
} if (name == "corsFetch") {
if (name == "revoke") { bgCorsFetch(c, pendingFetches, id, ...args);
URL.revokeObjectURL(url); return;
c.postMessage({ }
id, if (name == "revoke") {
ok: 1 URL.revokeObjectURL(url);
}); c.postMessage({
return; id,
} ok: 1
if (name == "fullyRead") { });
const obj3 = pendingFetches.get(c); return;
if (obj3 && fid in obj3) }
obj3[fid].fetchFully = true; if (name == "fullyRead") {
const obj3 = pendingFetches.get(c);
if (obj3 && fid in obj3)
obj3[fid].fetchFully = true;
c.postMessage({
id,
ok: 1
});
return;
}
const res = await Platform[name](...args);
c.postMessage({ c.postMessage({
id, id,
ok: 1 res
}); });
return;
}
const res = await Platform[name](...args);
c.postMessage({
id,
res
}); });
}); }
}); })();
})(); })();
/*! /*!
* The buffer module from node.js, for the browser. * The buffer module from node.js, for the browser.

203
firefox/dist/main.js

File diff suppressed because one or more lines are too long

2
firefox/manifest.json

@ -7,7 +7,7 @@
}, },
"name": "PngExtraEmbedder", "name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!", "description": "Discover embedded files on 4chan and archives!",
"version": "0.299", "version": "0.300",
"icons": { "icons": {
"64": "1449696017588.png" "64": "1449696017588.png"
}, },

2
firefox_update.json

@ -1 +1 @@
{"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.299","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.299.xpi"}]}}} {"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.300","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.300.xpi"}]}}}

2
main.meta.js

@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name PNGExtraEmbed // @name PNGExtraEmbed
// @namespace https://coom.tech/ // @namespace https://coom.tech/
// @version 0.296 // @version 0.300
// @description uhh // @description uhh
// @author You // @author You
// @match https://boards.4channel.org/* // @match https://boards.4channel.org/*

284
main.user.js

File diff suppressed because one or more lines are too long

BIN
pngextraembedder-0.300.xpi

Binary file not shown.

86
src/background.ts

@ -88,9 +88,11 @@ async function bravedeserialize(src: any): Promise<any> {
} }
} }
const pendingFetches = new Map<MessagePort, { [id in number]: { fetchFully: boolean } }>(); const bgCorsFetch = async (c: MessagePort,
pendingFetches: Map<MessagePort, { [id in number]: { fetchFully: boolean } }>,
const bgCorsFetch = async (c: MessagePort, id: number, input: string, init?: RequestInit) => { id: number,
input: string,
init?: RequestInit) => {
if (input.startsWith('//')) // firefox?? if (input.startsWith('//')) // firefox??
input = 'https:' + input; input = 'https:' + input;
if (init?.body && execution_mode == "chrome_api") { if (init?.body && execution_mode == "chrome_api") {
@ -185,7 +187,7 @@ const waitConnect = (cb: any) => {
//if (msg.origin === meself) { //if (msg.origin === meself) {
cb(msg.ports[0]); cb(msg.ports[0]);
//} //}
}); }, { once: true });
}; };
const onMessage = (c: MessagePort, cb: any) => const onMessage = (c: MessagePort, cb: any) =>
@ -193,43 +195,49 @@ const onMessage = (c: MessagePort, cb: any) =>
cb(e.data); cb(e.data);
}; };
waitConnect((c: any) => { (async () => {
onMessage(c, async (obj: any) => { // eslint-disable-next-line no-constant-condition
const { id, name, args, sid, fid, url } = obj as { url?: string, fid?: number, sid?: number, id: number, name: string, args: Parameters<typeof Platform[keyof Methods<typeof Platform>]> }; while (true) {
if (name == "keepAlive") { const c = await new Promise<MessagePort>(waitConnect);
console.log('im alive, tho?'); const pendingFetches = new Map<MessagePort, { [id in number]: { fetchFully: boolean } }>();
return;
} onMessage(c, async (obj: any) => {
if (name == "abortCorsFetch") { const { id, name, args, sid, fid, url } = obj as any;
//chrome.runtime.sendMessage({ name, sid }); if (name == "keepAlive") {
return; console.log('im alive, tho?');
} return;
if (name == "corsFetch") { }
// this handles the reply if (name == "abortCorsFetch") {
(bgCorsFetch as any)(c, id, ...args); //chrome.runtime.sendMessage({ name, sid });
return; return;
} }
if (name == "corsFetch") {
// this handles the reply
(bgCorsFetch as any)(c, pendingFetches, id, ...args);
return;
}
if (name == "revoke") { if (name == "revoke") {
URL.revokeObjectURL(url!); URL.revokeObjectURL(url!);
c.postMessage({ c.postMessage({
id, ok: 1 id, ok: 1
}); });
return; return;
} }
if (name == "fullyRead") { if (name == "fullyRead") {
const obj = pendingFetches.get(c)!; const obj = pendingFetches.get(c)!;
if (obj && fid! in obj) if (obj && fid! in obj)
obj[fid!].fetchFully = true; obj[fid!].fetchFully = true;
c.postMessage({
id, ok: 1
});
return;
}
const res = await (Platform as any)[name](...args);
c.postMessage({ c.postMessage({
id, ok: 1 id, res
}); });
return;
}
const res = await (Platform as any)[name](...args);
c.postMessage({
id, res
}); });
}); }
}); })();

65
src/f5stego.ts

@ -254,11 +254,8 @@ type FrameType = {
}; };
export class f5stego { export class f5stego {
#randPool!: ArrayBuffer;
constructor(key: ArrayLike<number>, private maxPixels: number = 4096 * 4096) { constructor(key: ArrayLike<number>, private maxPixels: number = 4096 * 4096) {
this.#shuffleInit(key); }
};
embed(image: Uint8Array, data: ArrayLike<number>, k?: number) { embed(image: Uint8Array, data: ArrayLike<number>, k?: number) {
this.parse(image); this.parse(image);
@ -280,66 +277,6 @@ export class f5stego {
#tail: Uint8Array | null = null; #tail: Uint8Array | null = null;
#shuffleInit(key: ArrayLike<number>) {
this.#randPool = new ArrayBuffer(this.maxPixels * 4.125);
if (!key.length) throw 'key needed';
var i = 0,
j = 0,
t = 0,
k = 0,
S = new Uint8Array(256),
rnd = new Uint8Array(this.#randPool);
// init state from key
for (i = 0; i < 256; ++i) S[i] = i;
for (i = 0; i < 256; ++i) {
j = (j + S[i] + key[i % key.length]) & 255;
t = S[i];
S[i] = S[j];
S[j] = t;
}
i = 0;
j = 0;
// shuffle data
for (k = 0; k < this.maxPixels * 4.125; ++k) {
i = (i + 1) & 255;
j = (j + S[i]) & 255;
t = S[i];
S[i] = S[j];
S[j] = t;
rnd[k] = S[(t + S[i]) & 255];
}
}
#stegShuffle(pm: number | Uint32Array | Int16Array) {
let t, l, k, random_index, rand32Array = new Uint32Array(this.#randPool);
if (typeof pm == 'number') {
l = pm;
pm = new Uint32Array(l);
for (k = 1; k < l; k++) {
random_index = rand32Array[k] % (k + 1);
if (random_index != k) pm[k] = pm[random_index];
pm[random_index] = k;
}
} else {
l = pm.length;
for (k = 1; k < l; k++) {
random_index = rand32Array[k] % (k + 1);
// if (random_index != k) {
t = pm[k];
pm[k] = pm[random_index];
pm[random_index] = t;
// }
}
}
return { pm: pm, gamma: new Uint8Array(this.#randPool, l * 4) };
}
#_analyze(coeff: Int16Array) { #_analyze(coeff: Int16Array) {
var _one = 0, var _one = 0,
_zero = 0, _zero = 0,

219
src/main.ts

@ -23,7 +23,7 @@ import NotificationsHandler from './Components/NotificationsHandler.svelte';
import { fireNotification, getEmbedsFromCache, getSelectedFile } from "./utils"; import { fireNotification, getEmbedsFromCache, getSelectedFile } from "./utils";
import { getQueryProcessor, QueryProcessor } from "./websites"; import { getQueryProcessor, QueryProcessor } from "./websites";
import { ifetch, Platform, sendCmd, lqueue, supportedAltDomain, supportedMainDomain } from "./platform"; import { ifetch, Platform, sendCmd, lqueue, supportedAltDomain, supportedMainDomain, genPort } from "./platform";
import TextEmbeddingsSvelte from "./Components/TextEmbeddings.svelte"; import TextEmbeddingsSvelte from "./Components/TextEmbeddings.svelte";
import { HydrusClient } from "./hydrus"; import { HydrusClient } from "./hydrus";
import { registerPlugin } from 'linkifyjs'; import { registerPlugin } from 'linkifyjs';
@ -47,6 +47,7 @@ const processors: ImageProcessor[] =
let cappState: Parameters<typeof appState['set']>[0]; let cappState: Parameters<typeof appState['set']>[0];
settings.subscribe(async b => { settings.subscribe(async b => {
if (!b) return; if (!b) return;
csettings = b;
if (b.hyd) { if (b.hyd) {
// transition from disable to enabled // transition from disable to enabled
if (b.ak) { if (b.ak) {
@ -64,7 +65,6 @@ settings.subscribe(async b => {
} }
} }
} }
csettings = b;
//processors = [...(!csettings.te ? [thirdeye] : []), //processors = [...(!csettings.te ? [thirdeye] : []),
// pngv3, pomf, jpg, webm, gif // pngv3, pomf, jpg, webm, gif
//]; //];
@ -212,6 +212,104 @@ const shouldUseCache = () => {
let cp: CommandProcessor; let cp: CommandProcessor;
class BackgroundEmulator {
async bgCorsFetch(c: MessagePort,
pendingFetches: Map<MessagePort, { [id in number]: { fetchFully: boolean } }>,
id: number,
input: string,
init?: RequestInit) {
try {
const res = await ifetch(input, init);
// don't report progress because monkeys don't have a way to expose partial responses anyway
const headersStr = (res as any).responseHeaders;
const headerObj = headerStringToObject(headersStr);
c.postMessage({
id,
ok: res.ok || true,
setRes: true,
headers: headerObj,
responseHeaders: headersStr,
redirected: res.redirected,
type: res.type,
url: res.url,
status: res.status,
bodyUsed: res.bodyUsed,
statusText: res.statusText,
});
if (['GET', 'POST'].includes(init?.method || 'GET')) {
const data = await res.arrayBuffer();
c.postMessage({
id,
pushData: {
data
}
}, [data]);
}
// let's hope these are delivered in order :%)
c.postMessage({
id,
pushData: {
}
}, []);
} catch (e) {
c.postMessage({
id,
ok: false,
setRes: true,
headers: {},
responseHeaders: '',
redirected: false,
status: 400,
bodyUsed: false,
statusText: 'shit broke',
});
}
}
constructor(private port: MessagePort) {
const pendingFetches = new Map<MessagePort, { [id in number]: { fetchFully: boolean } }>();
port.onmessage = async (obj: MessageEvent) => {
const { id, name, args, sid, fid, url } = obj.data as any;
if (name == "keepAlive") {
console.log('im alive, tho?');
return;
}
if (name == "abortCorsFetch") {
//chrome.runtime.sendMessage({ name, sid });
return;
}
if (name == "corsFetch") {
// this handles the reply
(this.bgCorsFetch as any)(port, pendingFetches, id, ...args);
return;
}
if (name == "revoke") {
URL.revokeObjectURL(url!);
port.postMessage({
id, ok: 1
});
return;
}
if (name == "fullyRead") {
const obj = pendingFetches.get(port)!;
if (obj && fid! in obj)
obj[fid!].fetchFully = true;
port.postMessage({
id, ok: 1
});
return;
}
const res = await (Platform as any)[name](...args);
port.postMessage({
id, res
});
};
}
}
class CommandProcessor { class CommandProcessor {
processor = ProcessWorker(); processor = ProcessWorker();
@ -229,110 +327,6 @@ class CommandProcessor {
let res: IteratorResult<any, any>; let res: IteratorResult<any, any>;
switch (msg.data.type) { switch (msg.data.type) {
case 'ipc':
{
const id = msg.data.msg.id;
if (execution_mode != "userscript") {
if (msg.data.msg.name == 'corsFetch') {
sendCmd(msg.data.msg, msg.data.tr);
lqueue[id] = (res: any) => {
this.processor.postMessage({
type: 'ipc',
id,
res
});
};
} else {
// for complitude, but technically the webworker doesn't run anything besides corsFetch
const repl: any = await sendCmd(msg.data.msg, msg.data.tr);
repl.id = id;
this.processor.postMessage({
type: 'ipc',
id,
res: repl
});
}
} else {
if (msg.data.msg.name == 'fullyRead') {
// ignore
this.processor.postMessage({
type: 'ipc',
res: {
id,
ok: 1
}
});
}
if (msg.data.msg.name == 'corsFetch') {
const { args } = msg.data.msg;
try {
const res = await ifetch(args[0], args[1]);
// don't report progress because monkeys don't have a way to expose partial responses anyway
const headersStr = (res as any).responseHeaders;
const headerObj = headerStringToObject(headersStr);
this.processor.postMessage({
type: 'ipc',
id,
res: {
id,
ok: res.ok || true,
setRes: true,
headers: headerObj,
responseHeaders: headersStr,
redirected: res.redirected,
type: res.type,
url: res.url,
status: res.status,
bodyUsed: res.bodyUsed,
statusText: res.statusText,
}
});
if (!args[1].method || ['GET', 'POST'].includes(args[1].method)) {
const data = await res.arrayBuffer();
this.processor.postMessage({
type: 'ipc',
id,
res: {
id,
pushData: {
data
}
}
}, [data]);
}
// let's hope these are delivered in order :%)
this.processor.postMessage({
type: 'ipc',
id,
res: {
id,
pushData: {
}
}
}, []);
} catch (e) {
this.processor.postMessage({
type: 'ipc',
id,
res: {
id,
ok: false,
setRes: true,
headers: {},
responseHeaders: '',
redirected: false,
status: 400,
bodyUsed: false,
statusText: 'shit broke',
}
});
}
}
// ignore other commands
}
} break;
case 'reply': case 'reply':
if (msg.data.id in this.pendingprom) { if (msg.data.id in this.pendingprom) {
this.pendingprom[msg.data.id](msg.data.res); this.pendingprom[msg.data.id](msg.data.res);
@ -352,7 +346,20 @@ class CommandProcessor {
}); });
break; break;
} }
}; };
if (execution_mode != "userscript") {
const ipcport = genPort();
this.processor.postMessage({ type: 'ipc', port: ipcport }, [ipcport]);
} else {
const nmc = new MessageChannel();
const port1 = nmc.port1;
const port2 = nmc.port2;
new BackgroundEmulator(port2);
const ipcport = port1;
this.processor.postMessage({ type: 'ipc', port: ipcport }, [ipcport]);
}
} }
serializeArg(m: any) { serializeArg(m: any) {

38
src/platform.ts

@ -10,21 +10,26 @@ const localLoad = <T>(key: string, def: T) =>
const localSet = (key: string, value: any) => const localSet = (key: string, value: any) =>
localStorage.setItem('__pee__' + key, JSON.stringify(value)); localStorage.setItem('__pee__' + key, JSON.stringify(value));
export let port1: MessagePort; export let port1: MessagePort;
let port2: MessagePort;
console.log(execution_mode, isBackground); console.log(execution_mode, isBackground);
/* /*
A web worker has no access to the dom, so things like remote fetches are proxied through the main frame A web worker has no access to the dom, so things like remote fetches are proxied through the main frame
*/ */
let iframe: HTMLIFrameElement;
if (execution_mode != 'userscript' && !isBackground && execution_mode != 'worker') { export const genPort = () => {
const nmc = new MessageChannel(); const nmc = new MessageChannel();
port1 = nmc.port1; const port1 = nmc.port1;
port2 = nmc.port2; const port2 = nmc.port2;
iframe.contentWindow?.postMessage('', '*', [port2]);
return port1;
};
if (execution_mode != 'userscript' && !isBackground && execution_mode != 'worker') {
// It has to be a content script // It has to be a content script
const iframe = document.createElement('iframe'); iframe = document.createElement('iframe');
iframe.style.display = 'none'; iframe.style.display = 'none';
iframe.name = location.origin; iframe.name = location.origin;
const iframeloaded = new Promise(_ => { const iframeloaded = new Promise(_ => {
@ -34,15 +39,21 @@ if (execution_mode != 'userscript' && !isBackground && execution_mode != 'worker
//const meself = new URL(chrome.runtime.getURL('')).origin; //const meself = new URL(chrome.runtime.getURL('')).origin;
document.documentElement.appendChild(iframe); document.documentElement.appendChild(iframe);
iframeloaded.then(() => { iframeloaded.then(() => {
iframe.contentWindow?.postMessage('', '*', [port2]); port1 = genPort();
port1.onmessage = (ev) => {
lqueue[ev.data.id](ev.data);
};
}); });
}
export const setupPort = (port: MessagePort) => {
port1 = port;
port1.onmessage = (ev) => { port1.onmessage = (ev) => {
lqueue[ev.data.id](ev.data); lqueue[ev.data.id](ev.data);
}; };
} };
console.log(execution_mode);
// will be later overwritten if it's not launched from the userscript
if (execution_mode == "worker") { if (execution_mode == "worker") {
port1 = { port1 = {
onmessage(ev) { onmessage(ev) {
@ -70,12 +81,15 @@ const visit = (e: any, cb: (e: any) => true | undefined) => {
cb(e); cb(e);
}; };
export const sendCmd = <V>(cmd: any, tr?: Transferable[]) => { export const sendCmd = <V>(cmd: any, tr?: Transferable[], overwrite = false, todelete = false) => {
const prom = new Promise<V>(_ => { const prom = new Promise<V>(_ => {
const id = gid++; const id = gid++;
if (overwrite)
cmd.id = id;
lqueue[id] = (e: any) => { lqueue[id] = (e: any) => {
_(e); _(e);
delete lqueue[id]; if (todelete)
delete lqueue[id];
}; };
port1.postMessage({ id, ...cmd }, tr || []); port1.postMessage({ id, ...cmd }, tr || []);
}); });

77
src/processor.worker.ts

@ -59,6 +59,8 @@ const proxyAsyncGen = (id: number) => {
}; };
const deserializeMessage = (m: any) => { const deserializeMessage = (m: any) => {
if (m instanceof MessagePort)
return m;
if (typeof m == "object" && m.type == 'AsyncGenerator') { if (typeof m == "object" && m.type == 'AsyncGenerator') {
return proxyAsyncGen(m.id); return proxyAsyncGen(m.id);
} }
@ -144,7 +146,7 @@ const processImage = async (srcs: AsyncGenerator<string, void, void>, fn: string
return; return;
} }
return [await proc.extract(cumul), false] as [WorkerEmbeddedFile[], boolean]; return [await proc.extract(cumul), false] as [WorkerEmbeddedFile[], boolean];
} catch(err) { } catch (err) {
console.log(err); console.log(err);
// ignore error and retry with another link // ignore error and retry with another link
} }
@ -153,47 +155,44 @@ const processImage = async (srcs: AsyncGenerator<string, void, void>, fn: string
return ret.filter(e => e).map(e => e!); return ret.filter(e => e).map(e => e!);
}; };
(async () => { onmessage = async (msg: MessageEvent<any>) => {
onmessage = async (msg: MessageEvent<any>) => { const des = deserializeMessage(msg.data);
const des = deserializeMessage(msg.data); switch (des.type) {
switch (des.type) { case 'ipc': {
case 'ipc': { platform.setupPort(des.port);
if (platform.port1.onmessage) break;
platform.port1.onmessage(new MessageEvent("message", { data: des.res })); }
break; case 'cmd': {
} switch (des.fun) {
case 'cmd': { case 'processImage': {
switch (des.fun) { //console.log('Received process image command', des);
case 'processImage': { const res = await processImage(des.args[0], des.args[1], des.args[2], des.args[3]);
//console.log('Received process image command', des); //console.log('Finished process image command', des);
const res = await processImage(des.args[0], des.args[1], des.args[2], des.args[3]); const tr: Transferable[] = [];
//console.log('Finished process image command', des); for (const ef of res) {
const tr: Transferable[] = []; for (const e of ef[0]) {
for (const ef of res) { if (Buffer.isBuffer(e.thumbnail) || e.thumbnail instanceof Uint8Array)
for (const e of ef[0]) { tr.push(e.thumbnail.buffer);
if (Buffer.isBuffer(e.thumbnail) || e.thumbnail instanceof Uint8Array) if (Buffer.isBuffer(e.data) || e.data instanceof Uint8Array)
tr.push(e.thumbnail.buffer); tr.push(e.data.buffer);
if (Buffer.isBuffer(e.data) || e.data instanceof Uint8Array)
tr.push(e.data.buffer);
}
} }
//console.log('Sent reply', res, des);
postMessage({
type: 'reply',
id: des.id,
res
}, [...new Set(tr)]);
} }
//console.log('Sent reply', res, des);
postMessage({
type: 'reply',
id: des.id,
res
}, [...new Set(tr)]);
} }
break;
} }
case 'ag': { break;
const cb = pendinggens[des.id].shift(); }
if (cb) { case 'ag': {
cb(des.res); const cb = pendinggens[des.id].shift();
} if (cb) {
break; cb(des.res);
} }
break;
} }
}; }
})(); };

Loading…
Cancel
Save