cables_dev/cables_electron/src_client/standalone.js
- import { Logger } from "cables-shared-client";
- import ElectronEditor from "./electron_editor.js";
- import electronCommands from "./cmd_electron.js";
-
- /**
- * frontend class for cables standalone
- * initializes the ui, starts the editor and adds functions custom to this platform
- */
- export default class CablesStandalone
- {
- constructor()
- {
- this._electron = window.nodeRequire("electron");
- this._importSync = window.nodeRequire("import-sync");
-
- window.ipcRenderer = this._electron.ipcRenderer; // needed to have ipcRenderer in electron_editor.js
- this._settings = this._electron.ipcRenderer.sendSync("platformSettings") || {};
- this._usersettings = this._settings.userSettings;
- delete this._settings.userSettings;
- this._config = this._electron.ipcRenderer.sendSync("cablesConfig") || {};
- this.editorIframe = null;
-
- this._startUpLogItems = this._electron.ipcRenderer.sendSync("getStartupLog") || [];
-
- if (!this._config.isPackaged) window.ELECTRON_DISABLE_SECURITY_WARNINGS = true;
-
- this._loadedModules = {};
- }
-
- /**
- * the `gui` object of the current editor, if initialized
- *
- * @type {Gui|null}
- */
- get gui()
- {
- return this.editorWindow ? this.editorWindow.gui : null;
- }
-
- /**
- * the current editor window, if initialized
- *
- * @type {{}|null}
- */
- get editorWindow()
- {
- return this.editorIframe.contentWindow;
- }
-
- /**
- * the CABLES core instance of the current editor window, if initialized
- *
- * @type {{}|null}
- */
- get CABLES()
- {
- return this.editorWindow ? this.editorWindow.CABLES : null;
- }
-
- /**
- * initialize the editor, wait for core and ui to be ready, add
- * custom functionality
- */
- init()
- {
- this.editorIframe = document.getElementById("editorIframe");
- let src = this._config.uiIndexHtml + window.location.search;
- if (window.location.hash)
- {
- src += window.location.hash;
- }
- this.editorIframe.src = src;
- this.editorIframe.onload = () =>
- {
- if (this.editorWindow)
- {
- const waitForAce = this.editorWindow.waitForAce;
- this.editorWindow.waitForAce = () =>
- {
- this._log.info("loading", this._settings.patchFile);
-
- this._incrementStartup();
- this._logStartup("checking/installing op dependencies...");
- this._electron.ipcRenderer.invoke("talkerMessage", "installProjectDependencies").then((npmResult) =>
- {
- this.editorWindow.CABLESUILOADER.cfg.patchConfig.onError = (...args) =>
- {
- // npm runtime error...
- if (args && args[0] === "core_patch" && args[2] && args[2].message && args[2].message.includes("was compiled against a different Node.js version"))
- {
- const dirParts = args[2].message.split("/");
- const opNameIndex = dirParts.findIndex((part) => { return part.startsWith("Ops."); });
- const opName = dirParts[opNameIndex];
- const packageName = dirParts[opNameIndex + 2];
- const onClick = "CABLES.CMD.STANDALONE.openOpDir('', '" + opName + "');";
-
- const msg = "try running this <a onclick=\"" + onClick + "\" > in the op dir</a>:";
- this._log.error(msg);
- this._log.error("`npm --prefix ./ install " + packageName + "`");
- this._log.error("`npx \"@electron/rebuild\" -v " + process.versions.electron);
- }
- };
- waitForAce();
-
- if (npmResult.error && npmResult.data && npmResult.msg !== "UNSAVED_PROJECT")
- {
- npmResult.data.forEach((msg) =>
- {
- const opName = msg.opName ? " for " + msg.opName : "";
- this._log.error("failed dependency" + opName + ": " + msg.stderr);
- });
- }
- else if (npmResult.msg !== "EMPTY" && npmResult.msg !== "UNSAVED_PROJECT")
- {
- npmResult.data.forEach((result) =>
- {
- const npmText = result.stderr || result.stdout;
- this._logStartup(result.opName + ": " + npmText);
- });
- }
-
-
- if (this.gui)
- {
- this.gui.on("uiloaded", () =>
- {
- if (this.editor && this.editor.config && !this.editor.config.patchFile) this.gui.setStateUnsaved();
- });
- }
- });
- };
- if (this._settings.uiLoadStart) this.editorWindow.CABLESUILOADER.uiLoadStart -= this._settings.uiLoadStart;
- this._startUpLogItems.forEach((logEntry) =>
- {
- this._logStartup(logEntry.title);
- });
- if (this.editorWindow.loadjs)
- {
- this.editorWindow.loadjs.ready("cables_core", this._coreReady.bind(this));
- this.editorWindow.loadjs.ready("cablesuinew", this._uiReady.bind(this));
- }
- }
- };
-
- window.addEventListener("message", (event) =>
- {
- if (event.data && event.data.type === "hashchange")
- {
- window.location.hash = event.data.data;
- }
- }, false);
-
- window.addEventListener("hashchange", () =>
- {
- if (this.editorWindow)
- {
- this.editorWindow.postMessage({ "type": "hashchange", "data": window.location.hash }, "*");
- }
- }, false);
-
- this.editor = new ElectronEditor({
- "config": {
- ...this._settings,
- "isTrustedPatch": true,
- "platformClass": "PlatformStandalone",
- "urlCables": "cables://",
- "urlSandbox": "cables://",
- "communityUrl": this._config.communityUrl,
- "user": this._settings.currentUser,
- "usersettings": { "settings": this._usersettings },
- "isDevEnv": !this._config.isPackaged,
- "env": this._config.env,
- "patchId": this._settings.patchId,
- "patchVersion": "",
- "socketcluster": {},
- "remoteClient": false,
- "buildInfo": this._settings.buildInfo,
- "patchConfig": {
- "allowEdit": true,
- "prefixAssetPath": this._settings.currentPatchDir,
- "assetPath": this._settings.paths.assetPath,
- "paths": this._settings.paths
- },
- }
- });
- }
-
- _coreReady()
- {
- if (this.CABLES)
- {
- if (this.CABLES.Op)
- {
- const standAlone = this;
- this.CABLES.Op.prototype.require = function (moduleName)
- {
- return standAlone._opRequire(moduleName, this, standAlone);
- };
- }
- if (this.CABLES.Patch)
- {
- Object.defineProperty(this.CABLES.Patch.prototype, "patchDir", { "get": this._patchDir.bind(this) });
- }
- }
- }
-
- _uiReady()
- {
- this.CABLES.UI.standaloneLogger = () =>
- {
- CABLES.UI = this.CABLES.UI;
- return new Logger("standalone");
- };
- this._log = this.CABLES.UI.standaloneLogger();
- if (this.CABLES)
- {
- const getOpsForFilename = this.CABLES.UI.getOpsForFilename;
- this.CABLES.UI.getOpsForFilename = (filename) =>
- {
- let defaultOps = getOpsForFilename(filename);
- if (defaultOps.length === 0)
- {
- defaultOps.push(this.CABLES.UI.DEFAULTOPNAMES.HttpRequest);
- const addOpCb = this.gui.corePatch().on("onOpAdd", (newOp) =>
- {
- const contentPort = newOp.getPortByName("Content", false);
- if (contentPort) contentPort.set("String");
- this.gui.corePatch().off(addOpCb);
- });
- }
- return defaultOps;
- };
- this.CABLES.CMD.STANDALONE = electronCommands.functions;
- this.CABLES.CMD.commands = this.CABLES.CMD.commands.concat(electronCommands.commands);
- Object.assign(this.CABLES.CMD.PATCH, electronCommands.functionOverrides.PATCH);
- Object.assign(this.CABLES.CMD.RENDERER, electronCommands.functionOverrides.RENDERER);
- const commandOverrides = electronCommands.commandOverrides;
- this.CABLES.CMD.commands.forEach((command) =>
- {
- const commandOverride = commandOverrides.find((override) => { return override.cmd === command.cmd; });
- if (commandOverride)
- {
- Object.assign(command, commandOverride);
- }
- });
- }
- }
-
- _opRequire(moduleName, op, thisClass)
- {
- if (op) op.setUiError("oprequire", null);
- if (moduleName === "electron") return thisClass._electron;
- if (this._loadedModules[moduleName]) return this._loadedModules[moduleName];
-
- try
- {
- // load module by directory name
- const modulePath = window.ipcRenderer.sendSync("getOpModuleDir", { "opName": op.objName || op._name, "opId": op.opId, "moduleName": moduleName });
- this._loadedModules[moduleName] = window.nodeRequire(modulePath);
- return this._loadedModules[moduleName];
- }
- catch (ePath)
- {
- try
- {
- // load module by resolved filename from package.json
- const moduleFile = window.ipcRenderer.sendSync("getOpModuleLocation", { "opName": op.objName || op._name, "opId": op.opId, "moduleName": moduleName });
- this._loadedModules[moduleName] = window.nodeRequire(moduleFile);
- return this._loadedModules[moduleName];
- }
- catch (eFile)
- {
- try
- {
- // load module by module name
- this._loadedModules[moduleName] = window.nodeRequire(moduleName);
- return this._loadedModules[moduleName];
- }
- catch (eName)
- {
- try
- {
- const moduleFile = window.ipcRenderer.sendSync("getOpModuleLocation", { "opName": op.objName || op._name, "opId": op.opId, "moduleName": moduleName, });
- this._loadedModules[moduleName] = this._importSync(moduleFile);
- return this._loadedModules[moduleName];
- }
- catch (eImport)
- {
- let errorMessage = "failed to load node module: " + moduleName + "\n\n";
- errorMessage += "require by import:\n" + eImport + "\n\n";
- errorMessage += "require by name:\n" + eName + "\n\n";
- errorMessage += "require by file:\n" + eFile + "\n\n";
- errorMessage += "require by path:\n" + ePath;
- if (op) op.setUiError("oprequire", errorMessage);
- this._log.error(errorMessage, eName, eFile, ePath);
- return { };
- }
- }
- }
- }
- }
-
- _patchDir(...args)
- {
- return this._settings.currentPatchDir;
- }
-
- _logStartup(title)
- {
- if (this.editorWindow && this.editorWindow.logStartup) this.editorWindow.logStartup(title);
- }
-
- _incrementStartup()
- {
- if (this.editorWindow && this.editorWindow.logStartup) this.editorWindow.incrementStartup();
- }
- }