ecsy
Version:
Entity Component System in JS
172 lines (151 loc) • 4.99 kB
JavaScript
/* global Peer */
import { injectScript, generateId } from "./utils.js";
import { hasWindow } from "../Utils.js";
function hookConsoleAndErrors(connection) {
var wrapFunctions = ["error", "warning", "log"];
wrapFunctions.forEach((key) => {
if (typeof console[key] === "function") {
var fn = console[key].bind(console);
console[key] = (...args) => {
connection.send({
method: "console",
type: key,
args: JSON.stringify(args),
});
return fn.apply(null, args);
};
}
});
window.addEventListener("error", (error) => {
connection.send({
method: "error",
error: JSON.stringify({
message: error.error.message,
stack: error.error.stack,
}),
});
});
}
function includeRemoteIdHTML(remoteId) {
let infoDiv = document.createElement("div");
infoDiv.style.cssText = `
align-items: center;
background-color: #333;
color: #aaa;
display:flex;
font-family: Arial;
font-size: 1.1em;
height: 40px;
justify-content: center;
left: 0;
opacity: 0.9;
position: absolute;
right: 0;
text-align: center;
top: 0;
`;
infoDiv.innerHTML = `Open ECSY devtools to connect to this page using the code: <b style="color: #fff">${remoteId}</b> <button onClick="generateNewCode()">Generate new code</button>`;
document.body.appendChild(infoDiv);
return infoDiv;
}
export function enableRemoteDevtools(remoteId) {
if (!hasWindow) {
console.warn("Remote devtools not available outside the browser");
return;
}
window.generateNewCode = () => {
window.localStorage.clear();
remoteId = generateId(6);
window.localStorage.setItem("ecsyRemoteId", remoteId);
window.location.reload(false);
};
remoteId = remoteId || window.localStorage.getItem("ecsyRemoteId");
if (!remoteId) {
remoteId = generateId(6);
window.localStorage.setItem("ecsyRemoteId", remoteId);
}
let infoDiv = includeRemoteIdHTML(remoteId);
window.__ECSY_REMOTE_DEVTOOLS_INJECTED = true;
window.__ECSY_REMOTE_DEVTOOLS = {};
let Version = "";
// This is used to collect the worlds created before the communication is being established
let worldsBeforeLoading = [];
let onWorldCreated = (e) => {
var world = e.detail.world;
Version = e.detail.version;
worldsBeforeLoading.push(world);
};
window.addEventListener("ecsy-world-created", onWorldCreated);
let onLoaded = () => {
// var peer = new Peer(remoteId);
var peer = new Peer(remoteId, {
host: "peerjs.ecsy.io",
secure: true,
port: 443,
config: {
iceServers: [
{ url: "stun:stun.l.google.com:19302" },
{ url: "stun:stun1.l.google.com:19302" },
{ url: "stun:stun2.l.google.com:19302" },
{ url: "stun:stun3.l.google.com:19302" },
{ url: "stun:stun4.l.google.com:19302" },
],
},
debug: 3,
});
peer.on("open", (/* id */) => {
peer.on("connection", (connection) => {
window.__ECSY_REMOTE_DEVTOOLS.connection = connection;
connection.on("open", function () {
// infoDiv.style.visibility = "hidden";
infoDiv.innerHTML = "Connected";
// Receive messages
connection.on("data", function (data) {
if (data.type === "init") {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.onload = () => {
script.parentNode.removeChild(script);
// Once the script is injected we don't need to listen
window.removeEventListener(
"ecsy-world-created",
onWorldCreated
);
worldsBeforeLoading.forEach((world) => {
var event = new CustomEvent("ecsy-world-created", {
detail: { world: world, version: Version },
});
window.dispatchEvent(event);
});
};
script.innerHTML = data.script;
(document.head || document.documentElement).appendChild(script);
script.onload();
hookConsoleAndErrors(connection);
} else if (data.type === "executeScript") {
let value = eval(data.script);
if (data.returnEval) {
connection.send({
method: "evalReturn",
value: value,
});
}
}
});
});
});
});
};
// Inject PeerJS script
injectScript(
"https://cdn.jsdelivr.net/npm/peerjs@0.3.20/dist/peer.min.js",
onLoaded
);
}
if (hasWindow) {
const urlParams = new URLSearchParams(window.location.search);
// @todo Provide a way to disable it if needed
if (urlParams.has("enable-remote-devtools")) {
enableRemoteDevtools();
}
}