gluon: 4.0!
Gluon 4.0, now with a mostly stable IPC API, and more: - Rewrote IPC API to be more friendly and easy to use - Added more versions to Versions API - Fixed refreshing breaking Gluon API - Reduced debug logging
This commit is contained in:
parent
cf69ee38b3
commit
c441cd360e
183
gluon/index.js
183
gluon/index.js
@ -1,7 +1,7 @@
|
|||||||
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
|
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
|
||||||
const log = (...args) => console.log(`[${rgb(88, 101, 242, 'Gluon')}]`, ...args);
|
const log = (...args) => console.log(`[${rgb(88, 101, 242, 'Gluon')}]`, ...args);
|
||||||
|
|
||||||
process.versions.gluon = '3.2';
|
process.versions.gluon = '4.0';
|
||||||
|
|
||||||
const presets = { // Presets from OpenAsar
|
const presets = { // Presets from OpenAsar
|
||||||
'base': '--autoplay-policy=no-user-gesture-required --disable-features=WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService', // Base Discord
|
'base': '--autoplay-policy=no-user-gesture-required --disable-features=WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService', // Base Discord
|
||||||
@ -47,14 +47,24 @@ const findChromiumPath = async () => {
|
|||||||
|
|
||||||
if (!whichChromium) return null;
|
if (!whichChromium) return null;
|
||||||
|
|
||||||
return chromiumPathsWin[whichChromium];
|
return [ chromiumPathsWin[whichChromium], whichChromium ];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFriendlyName = whichChromium => {
|
||||||
|
switch (whichChromium) {
|
||||||
|
case 'stable': return 'Chrome';
|
||||||
|
case 'canary': return 'Chrome Canary';
|
||||||
|
case 'edge': return 'Edge';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDataPath = () => join(__dirname, '..', 'chrome_data');
|
const getDataPath = () => join(__dirname, '..', 'chrome_data');
|
||||||
|
|
||||||
const startChromium = async (url, { windowSize }) => {
|
const startChromium = async (url, { windowSize }) => {
|
||||||
const dataPath = getDataPath();
|
const dataPath = getDataPath();
|
||||||
const chromiumPath = await findChromiumPath();
|
const [ chromiumPath, chromiumName ] = await findChromiumPath();
|
||||||
|
|
||||||
|
const friendlyProductName = getFriendlyName(chromiumName);
|
||||||
|
|
||||||
log('chromium path:', chromiumPath);
|
log('chromium path:', chromiumPath);
|
||||||
log('data path:', dataPath);
|
log('data path:', dataPath);
|
||||||
@ -82,7 +92,7 @@ const startChromium = async (url, { windowSize }) => {
|
|||||||
const onMessage = msg => {
|
const onMessage = msg => {
|
||||||
msg = JSON.parse(msg);
|
msg = JSON.parse(msg);
|
||||||
|
|
||||||
log('received', msg);
|
// log('received', msg);
|
||||||
if (onReply[msg.id]) {
|
if (onReply[msg.id]) {
|
||||||
onReply[msg.id](msg);
|
onReply[msg.id](msg);
|
||||||
delete onReply[msg.id];
|
delete onReply[msg.id];
|
||||||
@ -106,7 +116,7 @@ const startChromium = async (url, { windowSize }) => {
|
|||||||
pipeWrite.write(JSON.stringify(msg));
|
pipeWrite.write(JSON.stringify(msg));
|
||||||
pipeWrite.write('\0');
|
pipeWrite.write('\0');
|
||||||
|
|
||||||
log('sent', msg);
|
// log('sent', msg);
|
||||||
|
|
||||||
const reply = await new Promise(res => {
|
const reply = await new Promise(res => {
|
||||||
onReply[id] = msg => res(msg);
|
onReply[id] = msg => res(msg);
|
||||||
@ -141,6 +151,12 @@ const startChromium = async (url, { windowSize }) => {
|
|||||||
|
|
||||||
// await new Promise(res => setTimeout(res, 1000));
|
// await new Promise(res => setTimeout(res, 1000));
|
||||||
|
|
||||||
|
let browserInfo;
|
||||||
|
sendMessage('Browser.getVersion').then(x => { // get browser info async as not important
|
||||||
|
browserInfo = x;
|
||||||
|
log('browser:', x.product);
|
||||||
|
});
|
||||||
|
|
||||||
const target = (await sendMessage('Target.getTargets')).targetInfos[0];
|
const target = (await sendMessage('Target.getTargets')).targetInfos[0];
|
||||||
|
|
||||||
const { sessionId } = await sendMessage('Target.attachToTarget', {
|
const { sessionId } = await sendMessage('Target.attachToTarget', {
|
||||||
@ -148,11 +164,17 @@ const startChromium = async (url, { windowSize }) => {
|
|||||||
flatten: true
|
flatten: true
|
||||||
});
|
});
|
||||||
|
|
||||||
(await sendMessage('Runtime.enable', {}, sessionId)); // enable runtime API
|
// sendMessage('Page.enable', {}, sessionId); // pause page execution until we inject
|
||||||
|
// sendMessage('Page.waitForDebugger', {}, sessionId);
|
||||||
|
|
||||||
(await sendMessage('Runtime.addBinding', { // setup sending from window to Node via Binding
|
// (await sendMessage('Page.enable', {}, sessionId));
|
||||||
|
// (await sendMessage('Page.stopLoading', {}, sessionId));
|
||||||
|
|
||||||
|
sendMessage('Runtime.enable', {}, sessionId); // enable runtime API
|
||||||
|
|
||||||
|
sendMessage('Runtime.addBinding', { // setup sending from window to Node via Binding
|
||||||
name: '_gluonSend'
|
name: '_gluonSend'
|
||||||
}, sessionId));
|
}, sessionId);
|
||||||
|
|
||||||
const evalInWindow = async func => {
|
const evalInWindow = async func => {
|
||||||
return await sendMessage(`Runtime.evaluate`, {
|
return await sendMessage(`Runtime.evaluate`, {
|
||||||
@ -160,63 +182,95 @@ const startChromium = async (url, { windowSize }) => {
|
|||||||
}, sessionId);
|
}, sessionId);
|
||||||
};
|
};
|
||||||
|
|
||||||
evalInWindow(`(() => {
|
const windowInjectionSource = `(() => {
|
||||||
let onIPCReply = {};
|
let onIPCReply = {}, ipcListeners = {};
|
||||||
window.Gluon = {
|
window.Gluon = {
|
||||||
versions: {
|
versions: {
|
||||||
gluon: '${process.versions.gluon}',
|
gluon: '${process.versions.gluon}',
|
||||||
builder: '${'GLUGUN_VERSION' === 'G\LUGUN_VERSION' ? 'nothing' : 'Glugun GLUGUN_VERSION'}',
|
builder: '${'GLUGUN_VERSION' === 'G\LUGUN_VERSION' ? 'nothing' : 'Glugun GLUGUN_VERSION'}',
|
||||||
node: '${process.versions.node}',
|
node: '${process.versions.node}',
|
||||||
chromium: navigator.userAgentData.brands.find(x => x.brand === "Chromium").version,
|
chromium: '${browserInfo.product.split('/')[1]}' ?? navigator.userAgentData.brands.find(x => x.brand === "Chromium").version,
|
||||||
|
product: '${friendlyProductName}',
|
||||||
|
|
||||||
v8: {
|
v8: {
|
||||||
node: '${process.versions.v8}'
|
node: '${process.versions.v8}',
|
||||||
|
chromium: '${browserInfo.jsVersion}'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
send: async (type, data, id = undefined) => {
|
ipc: {
|
||||||
id = id ?? Math.random().toString().split('.')[1];
|
send: async (type, data, id = undefined) => {
|
||||||
|
id = id ?? Math.random().toString().split('.')[1];
|
||||||
|
|
||||||
window._gluonSend(JSON.stringify({
|
window.Gluon.ipc._send(JSON.stringify({
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
data
|
data
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (id) return;
|
if (id) return;
|
||||||
|
|
||||||
const reply = await new Promise(res => {
|
const reply = await new Promise(res => {
|
||||||
onIPCReply[id] = msg => res(msg);
|
onIPCReply[id] = msg => res(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
|
},
|
||||||
|
|
||||||
|
on: (type, cb) => {
|
||||||
|
if (!ipcListeners[type]) ipcListeners[type] = [];
|
||||||
|
ipcListeners[type].push(cb);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeListener: (type, cb) => {
|
||||||
|
if (!ipcListeners[type]) return false;
|
||||||
|
ipcListeners[type].splice(ipcListeners[type].indexOf(cb), 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
_recieve: msg => {
|
||||||
|
const { id, type, data } = msg;
|
||||||
|
|
||||||
|
if (onIPCReply[id]) {
|
||||||
|
onIPCReply[id]({ type, data });
|
||||||
|
delete onIPCReply[id];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipcListeners[type]) {
|
||||||
|
let reply;
|
||||||
|
|
||||||
|
for (const cb of ipcListeners[type]) {
|
||||||
|
const ret = cb(data);
|
||||||
|
if (!reply) reply = ret; // use first returned value as reply
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply) return Gluon.ipc.send('reply', reply, id); // reply with wanted reply
|
||||||
|
}
|
||||||
|
|
||||||
|
Gluon.ipc.send('pong', {}, id);
|
||||||
|
},
|
||||||
|
|
||||||
|
_send: window._gluonSend
|
||||||
},
|
},
|
||||||
|
|
||||||
_recieve: msg => {
|
|
||||||
const { id, type, data } = msg;
|
|
||||||
|
|
||||||
if (onIPCReply[id]) {
|
|
||||||
onIPCReply[id]({ type, data });
|
|
||||||
delete onIPCReply[id];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.Gluon.recieve?.(type, data) !== true) {
|
|
||||||
window.Gluon.send('pong', {}, id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_send: window._gluonSend
|
|
||||||
};
|
};
|
||||||
|
|
||||||
delete window._gluonSend;
|
delete window._gluonSend;
|
||||||
})();`); // inject nice reciever and sender wrappers
|
})();`;
|
||||||
|
evalInWindow(windowInjectionSource); // inject nice reciever and sender wrappers
|
||||||
|
|
||||||
let onIPCReply = {};
|
// sendMessage('Runtime.runIfWaitingForDebugger', {}, sessionId);
|
||||||
|
|
||||||
|
|
||||||
|
sendMessage(`Page.enable`, {}, sessionId);
|
||||||
|
sendMessage(`Page.addScriptToEvaluateOnNewDocument`, {
|
||||||
|
source: windowInjectionSource
|
||||||
|
}, sessionId);
|
||||||
|
|
||||||
|
let onIPCReply = {}, ipcListeners = {};
|
||||||
const sendToWindow = async (type, data, id = undefined) => {
|
const sendToWindow = async (type, data, id = undefined) => {
|
||||||
id = id ?? Math.random().toString().split('.')[1];
|
id = id ?? Math.random().toString().split('.')[1];
|
||||||
|
|
||||||
evalInWindow(`window.Gluon._recieve(${JSON.stringify({
|
evalInWindow(`window.Gluon.ipc._recieve(${JSON.stringify({
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
data
|
data
|
||||||
@ -238,24 +292,40 @@ delete window._gluonSend;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowMessageCallback(type, data) !== true) { // true = replied itself, otherwise simply pong
|
if (ipcListeners[type]) {
|
||||||
sendToWindow('pong', {}, id);
|
let reply;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let windowMessageCallback = () => {};
|
for (const cb of ipcListeners[type]) {
|
||||||
|
const ret = cb(data);
|
||||||
|
if (!reply) reply = ret; // use first returned value as reply
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply) return sendToWindow('reply', reply, id); // reply with wanted reply
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToWindow('pong', {}, id); // send simple pong to confirm
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
window: {
|
window: {
|
||||||
onMessage: cb => {
|
|
||||||
windowMessageCallback = cb;
|
|
||||||
},
|
|
||||||
send: sendToWindow,
|
|
||||||
|
|
||||||
eval: evalInWindow,
|
eval: evalInWindow,
|
||||||
},
|
},
|
||||||
|
|
||||||
CDP: {
|
ipc: {
|
||||||
|
on: (type, cb) => {
|
||||||
|
if (!ipcListeners[type]) ipcListeners[type] = [];
|
||||||
|
ipcListeners[type].push(cb);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeListener: (type, cb) => {
|
||||||
|
if (!ipcListeners[type]) return false;
|
||||||
|
ipcListeners[type].splice(ipcListeners[type].indexOf(cb), 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
send: sendToWindow,
|
||||||
|
},
|
||||||
|
|
||||||
|
cdp: {
|
||||||
send: (method, params) => sendMessage(method, params, sessionId)
|
send: (method, params) => sendMessage(method, params, sessionId)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -275,12 +345,11 @@ export const open = async (url, { windowSize, onLoad } = {}) => {
|
|||||||
|
|
||||||
Chromium.window.eval(toRun);
|
Chromium.window.eval(toRun);
|
||||||
|
|
||||||
await Chromium.CDP.send(`Page.enable`);
|
await Chromium.cdp.send(`Page.enable`);
|
||||||
await Chromium.CDP.send(`Page.addScriptToEvaluateOnNewDocument`, {
|
await Chromium.cdp.send(`Page.addScriptToEvaluateOnNewDocument`, {
|
||||||
source: toRun
|
source: toRun
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Chromium;
|
return Chromium;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user