Skip to content

Instantly share code, notes, and snippets.

@tkon99
Created August 25, 2022 12:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkon99/eac47bd5a7458b6be3b46177bf7162a5 to your computer and use it in GitHub Desktop.
Save tkon99/eac47bd5a7458b6be3b46177bf7162a5 to your computer and use it in GitHub Desktop.
Browsy - A proof of concept for a highly compressed web browser that can be used over any connection
<!DOCTYPE html>
<html>
<head>
<title>Browsy</title>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
// var viewer = document.getElementById("viewer");
socket.on("page", (...data) => {
document.getElementById("viewer").setAttribute("src", data);
});
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("viewer").addEventListener('click', (e) => {
e.preventDefault();
socket.emit("click", {x: e.offsetX, y: e.offsetY});
document.getElementById("keyboard").focus();
});
document.getElementById("submit").addEventListener('click', (e) => {
socket.emit("type", {text: document.getElementById("keyboard").value});
document.getElementById("keyboard").value = "";
document.getElementById("keyboard").focus();
});
document.getElementById("navigate").addEventListener('click', (e) => {
socket.emit("navigate", {text: document.getElementById("keyboard").value});
document.getElementById("keyboard").value = "";
document.getElementById("keyboard").focus();
});
document.getElementById("scrollUp").addEventListener('click', (e) => {
socket.emit("scrollUp");
document.getElementById("keyboard").focus();
});
document.getElementById("scrollDown").addEventListener('click', (e) => {
socket.emit("scrollDown");
document.getElementById("keyboard").focus();
});
document.getElementById("refreshImage").addEventListener('click', (e) => {
socket.emit("refreshImage");
document.getElementById("keyboard").focus();
});
});
</script>
</head>
<body>
<h1>Browsy</h1>
<img src="" id="viewer" style="cursor:pointer"/><br>
<input type="text" id="keyboard"/><button id="submit">Type</button><button id="navigate">Navigate</button><br>
<button id="scrollUp">↑</button><button id="scrollDown">↓</button><button id="refreshImage">Update image</button>
</body>
</html>
const puppeteer = require('puppeteer');
const Jimp = require('jimp');
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server, {
pingTimeout: 5*60*1000 // Preserve Session for 5 minutes
});
async function createSession(browser){
const context = await browser.createIncognitoBrowserContext();
const page = await context.newPage();
await page.setViewport({
width: 320,
height: 510,
deviceScaleFactor: 4
});
await page.goto('https://duckduckgo.com');
return page;
}
async function screenshotSession(page){
let screenshot = await page.screenshot();
let image = await Jimp.read(screenshot);
let msg = await image.quality(20).resize(320, Jimp.AUTO, Jimp.RESIZE_NEAREST_NEIGHBOR).quality(10).getBase64Async('image/jpeg');
return msg;
}
async function sessionClick(socket, page, data){
await page.mouse.click(data.x, data.y, { button: 'left' });
let msg = await screenshotSession(page);
socket.emit("page", msg);
return
}
async function sessionType(socket, page, data){
await page.keyboard.type(data.text);
let msg = await screenshotSession(page);
socket.emit("page", msg);
return
}
async function sessionScroll(socket, page, direction){
if(direction == -1){
await page.evaluate(_ => {
window.scrollBy(0, -0.5*window.innerHeight);
});
}else{
await page.evaluate(_ => {
window.scrollBy(0, 0.5*window.innerHeight);
});
}
let msg = await screenshotSession(page);
socket.emit("page", msg);
}
async function sessionNav(socket, page, data){
await page.goto(data.text);
let msg = await screenshotSession(page);
socket.emit("page", msg);
}
(async () => {
const browser = await puppeteer.launch();
app.get('/', (req, res) => {
res.sendFile(__dirname + "/client.html");
});
io.on('connection', (socket) => {
console.log('New connection.');
createSession(browser).then((Session) => {
screenshotSession(Session).then((msg) => {
socket.emit("page", msg);
});
socket.on("click", (data) => {
console.log(data);
sessionClick(socket, Session, data);
});
socket.on("type", (data) => {
sessionType(socket, Session, data);
});
socket.on("scrollUp", (data) => {
sessionScroll(socket, Session, -1);
});
socket.on("scrollDown", (data) => {
sessionScroll(socket, Session, 1);
});
socket.on("refreshImage", (data) => {
screenshotSession(Session).then((msg) => {
socket.emit("page", msg);
});
});
socket.on("navigate", (data) => {
sessionNav(socket, Session, data);
});
// Close out the session
socket.conn.on("close", (reason) => {
console.log("Destroyed Session for "+socket.id);
Session.browserContext().close();
});
});
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
// await browser.close();
})();
{
"name": "browsy",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.1",
"jimp": "^0.16.1",
"puppeteer": "^16.2.0",
"socket.io": "^4.5.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment