Skip to content

Commit da9f63f

Browse files
committed
[frontend] install communication between page chobitsu and browser CDP
1 parent a252f95 commit da9f63f

File tree

6 files changed

+84
-10
lines changed

6 files changed

+84
-10
lines changed

chobitsu_inject/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
import chobitsu from "chobitsu";
2+
window.$sendToChobitsu = (message) => chobitsu.sendRawMessage(message);
3+
chobitsu.setOnMessage(window.$onChobitsuMessage);

chobitsu_inject/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"chobitsu": "workspace:*"
1616
},
1717
"devDependencies": {
18+
"@rollup/plugin-commonjs": "^28.0.6",
1819
"@rollup/plugin-node-resolve": "^16.0.1",
1920
"rollup": "^4.44.2"
2021
}

chobitsu_inject/rollup.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { nodeResolve } from "@rollup/plugin-node-resolve";
2+
import commonjs from "@rollup/plugin-commonjs";
23

34
export default {
45
input: "index.js",
@@ -9,7 +10,8 @@ export default {
910
plugins: [
1011
nodeResolve({
1112
preferBuiltins: true,
12-
browser: true,
13+
browser: false,
1314
}),
15+
commonjs(),
1416
],
1517
};

frontend/public/sw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ scramjet.addEventListener("request", (e) => {
3131
if (e.url.href.startsWith("https://fake-devtools.invalid")) {
3232
// route the fake origin devtools requests to the local static files
3333
e.response = (async () => {
34-
let response = await fetch("/" + e.url.pathname);
34+
let response = await fetch(e.url.pathname);
3535

3636
let rawHeaders = {};
3737
for (const [key, value] of response.headers.entries()) {

frontend/src/CDP.ts

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class ErrorWithCode extends Error {
1717
let server: CDPServer;
1818
class CDPServer {
1919
id = 0;
20+
2021
constructor(public sendMessage: (message: string) => void) {
2122
console.log("starting cdp server");
2223
server = this;
@@ -30,7 +31,11 @@ class CDPServer {
3031
console.log(msg);
3132

3233
try {
33-
resultMsg.result = await this.callMethod(msg.method, msg.params);
34+
resultMsg.result = await this.callMethod(
35+
msg.method,
36+
msg.params,
37+
msg.sessionId
38+
);
3439
} catch (e) {
3540
console.error("CDP error", e);
3641
if (e instanceof ErrorWithCode) {
@@ -49,6 +54,66 @@ class CDPServer {
4954
this.sendMessage(JSON.stringify(resultMsg));
5055
}
5156

57+
sessionid = 0;
58+
59+
sessions = new Map<
60+
string,
61+
{
62+
tab: Tab;
63+
callbacks: Map<number, (result: any) => void>;
64+
messageid: number;
65+
}
66+
>();
67+
initSession(tab: Tab): string {
68+
const sid = String(this.sessionid++);
69+
70+
const callbacks = new Map<number, (result: any) => void>();
71+
const session = {
72+
tab,
73+
callbacks,
74+
messageid: 1,
75+
};
76+
this.sessions.set(sid, session);
77+
tab.onChobitsuMessage = (message: string) => {
78+
let msg = JSON.parse(message);
79+
if (callbacks.has(msg.id)) {
80+
const callback = callbacks.get(msg.id)!;
81+
callback(msg);
82+
callbacks.delete(session.messageid);
83+
}
84+
};
85+
86+
return sid;
87+
}
88+
89+
async callTabMethod(
90+
sessionid: string,
91+
method: string,
92+
params: object
93+
): Promise<object> {
94+
const session = this.sessions.get(sessionid);
95+
if (!session) {
96+
throw new ErrorWithCode(-32001, `Session ${sessionid} not found`);
97+
}
98+
const msgid = session.messageid++;
99+
100+
const msg = {
101+
id: msgid,
102+
method,
103+
params,
104+
};
105+
if (!session.tab.sendToChobitsu) {
106+
throw new ErrorWithCode(-32001, `Session ${sessionid} not found`);
107+
}
108+
session.tab.sendToChobitsu(JSON.stringify(msg));
109+
110+
return await new Promise((resolve) => {
111+
session.callbacks.set(msgid, (result: any) => {
112+
resolve(result);
113+
});
114+
});
115+
}
116+
52117
emit<T>(method: string, params: T) {
53118
const msg = JSON.stringify({
54119
method,
@@ -57,7 +122,7 @@ class CDPServer {
57122
this.sendMessage(msg);
58123
}
59124

60-
async callMethod(method: string, params: any) {
125+
async callMethod(method: string, params: any, sessionId?: string) {
61126
const [domainName, methodName] = method.split(".");
62127
const domain: any = (Scopes as any)[domainName];
63128
if (domain) {
@@ -66,7 +131,7 @@ class CDPServer {
66131
}
67132
}
68133

69-
if (params.sessionId) {
134+
if (sessionId) {
70135
}
71136

72137
throw Error(`${method} unimplemented`);
@@ -75,6 +140,7 @@ class CDPServer {
75140

76141
import type Protocol from "devtools-protocol";
77142
import { browser } from "./main";
143+
import type { Tab } from "./Tab";
78144
const Scopes = {
79145
Browser: {
80146
getVersion(): Protocol.Browser.GetVersionResponse {
@@ -102,12 +168,14 @@ const Scopes = {
102168
params: Protocol.Target.CreateTargetRequest
103169
): Promise<Protocol.Target.CreateTargetResponse> {
104170
console.log("creating new target");
105-
const tab = browser.newTab(new URL("https://example.com"));
171+
const tab = browser.newTab(new URL("http://127.0.0.1:5014/"));
172+
const sessionid = server.initSession(tab);
106173

174+
await new Promise((resolve) => setTimeout(resolve, 1000));
107175
server.emit<Protocol.Target.AttachedToTargetEvent>(
108176
"Target.attachedToTarget",
109177
{
110-
sessionId: String(tab.id),
178+
sessionId: sessionid,
111179
waitingForDebugger: false,
112180
targetInfo: {
113181
browserContextId: "0",
@@ -121,8 +189,6 @@ const Scopes = {
121189
}
122190
);
123191

124-
await new Promise((resolve) => setTimeout(resolve, 1000));
125-
126192
return {
127193
targetId: String(tab.id),
128194
};

frontend/src/Tab.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,17 +172,20 @@ export class Tab extends StatefulClass {
172172
}
173173

174174
function injectChobitsu(client: ScramjetClient, tab: Tab) {
175+
console.log("injecting chobitsu");
175176
// the fake origin is defined in sw.js
176177
const devtoolsUrl = "https://fake-devtools.invalid";
177178
// make sure to create the element through the proxied document
178179
let devtoolsScript = client.global.document.createElement("script");
179180
devtoolsScript.setAttribute("src", devtoolsUrl + "/chobitsu_inject.js");
181+
client.global.document.head.appendChild(devtoolsScript);
180182

181183
// @ts-expect-error
182184
client.global.$onChobitsuMessage = (message: string) => {
183-
tab.onChobitsuMessage(message);
185+
if (tab.onChobitsuMessage) tab.onChobitsuMessage(message);
184186
};
185187
tab.sendToChobitsu = (message: string) => {
188+
console.warn(message);
186189
// @ts-expect-error
187190
client.global.$sendToChobitsu(message);
188191
};

0 commit comments

Comments
 (0)