Jean-Yves Didier

added full support for a remote console

......@@ -14,6 +14,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _connection_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9);
/* harmony import */ var _sheet_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(10);
/* harmony import */ var _application_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(11);
/* harmony import */ var _remoteconsole_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(12);
// no longer needed with the use of imports
......@@ -25,6 +26,7 @@ __webpack_require__.r(__webpack_exports__);
let ARCS = {
Component: _component_js__WEBPACK_IMPORTED_MODULE_0__["default"],
isInNode : _isinnode_js__WEBPACK_IMPORTED_MODULE_2__["default"],
......@@ -33,6 +35,7 @@ let ARCS = {
Invocation: _invocation_js__WEBPACK_IMPORTED_MODULE_4__["default"],
Connection: _connection_js__WEBPACK_IMPORTED_MODULE_5__["default"],
Sheet: _sheet_js__WEBPACK_IMPORTED_MODULE_6__["default"],
RemoteConsole: _remoteconsole_js__WEBPACK_IMPORTED_MODULE_8__["default"],
Application: _application_js__WEBPACK_IMPORTED_MODULE_7__["default"],
__lib__: ()=>{}
};
......@@ -2565,6 +2568,113 @@ Application.slot("finish");
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Application);
/***/ }),
/* 12 */
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
class RemoteConsole {
#stack= [];
#server;
#idxSource;
_log = globalThis.console.log;
_info = globalThis.console.info;
_warn = globalThis.console.warn;
_error = globalThis.console.error;
constructor(address) {
let self = this;
console.error = this.error;
console.warn = this.warn;
console.info = this.info;
console.log = this.log;
console.tainted = true;
if (globalThis.window) {
globalThis.window.onerror = this.runtimeException;
}
if (globalThis.WebSocket && globalThis.navigator) {
this.#server = new globalThis.WebSocket(address);
this.#idxSource = (globalThis.navigator.userAgent.match(/firefox|fxios/i))?2:3;
this.#server.onopen = function() {
self.#flush();
}
}
}
#currentPlace() {
let err = new Error();
let lst = err.stack.split("\n");
return lst[this.#idxSource];
}
#send(data) {
if (!this.#server) return ;
if (this.#server.readyState === WebSocket.OPEN ) {
this.#server.send(data);
} else {
this.#stack.push(data);
}
}
#flush () {
if (!this.#server) return ;
if (this.#server.readyState !== WebSocket.OPEN)
return ;
this.#stack.forEach(elt => this.#server.send(elt));
this.#stack = [];
}
#notify(type) {
let self = this;
return function() {
let obj = { type, args: Array.from(arguments), context: self.#currentPlace() };
self[`_${type}`].apply(globalThis.console, obj.args);
let serializedObject = "";
try {
serializedObject = JSON.stringify(obj);
} catch(e) {
obj.args= [ 'Argument(s) not serializable' ];
serializedObject = JSON.stringify(obj);
}
self.#send(serializedObject);
};
}
#runtimeException (msg, url, line, column,err) {
if (!this.#server) return false;
this.#server.send(
JSON.stringify(
{type: "exception", args: [{ message: msg, url: url, line: line, column: column }] }
)
);
return false;
}
log = this.#notify('log');
info = this.#notify('info');
warn = this.#notify('warn');
error = this.#notify('error');
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RemoteConsole);
/***/ })
/******/ ]);
/************************************************************************/
......
This diff is collapsed. Click to expand it.
......@@ -18,7 +18,12 @@ let baseUrl, appDescription, requireMarkup, xhr;
requireMarkup = document.querySelector('[data-arcsapp]');
if (requireMarkup !== undefined) {
baseUrl = requireMarkup.dataset.baseUrl ;
appDescription = requireMarkup.dataset.arcsapp || "arcsapp.json";
appDescription = requireMarkup.dataset.arcsapp || "arcsapp.json";
if( "remoteConsole" in requireMarkup.dataset ) {
let address = requireMarkup.dataset.remoteConsole || "ws://localhost:8088";
let remoteConsole = new ARCS.RemoteConsole(address);
}
}
......
......@@ -37,8 +37,9 @@
"license": "GPL-3.0-or-later",
"devDependencies": {
"chai": "4.3.4",
"chalk": "^5.2.0",
"ws": "^8.13.0",
"copy-webpack-plugin": "^9.0.1",
"eslint": "^8.7.0",
"eslint-webpack-plugin": "^3.0.1",
"jsdoc-webpack-plugin": "^0.3.0",
"mocha": "^9.1.4",
......
......@@ -8,6 +8,7 @@ import Invocation from './invocation.js';
import Connection from './connection.js';
import Sheet from './sheet.js';
import Application from './application.js';
import RemoteConsole from './remoteconsole.js';
let ARCS = {
Component: Component,
......@@ -17,6 +18,7 @@ let ARCS = {
Invocation: Invocation,
Connection: Connection,
Sheet: Sheet,
RemoteConsole: RemoteConsole,
Application: Application,
__lib__: ()=>{}
};
......
......@@ -18,7 +18,12 @@ let baseUrl, appDescription, requireMarkup, xhr;
requireMarkup = document.querySelector('[data-arcsapp]');
if (requireMarkup !== undefined) {
baseUrl = requireMarkup.dataset.baseUrl ;
appDescription = requireMarkup.dataset.arcsapp || "arcsapp.json";
appDescription = requireMarkup.dataset.arcsapp || "arcsapp.json";
if( "remoteConsole" in requireMarkup.dataset ) {
let address = requireMarkup.dataset.remoteConsole || "ws://localhost:8088";
let remoteConsole = new ARCS.RemoteConsole(address);
}
}
......
class ARCSRemoteConsole {
#stack= [];
#server;
#idxSource;
constructor(address) {
this.#server = new globalThis.WebSocket(address);
this.#idxSource = (globalThis.navigator.userAgent.match(/firefox|fxios/i))?2:3;
let self = this;
this.#server.onopen = function() {
self.flush();
}
}
#currentPlace() {
let err = new Error();
let lst = err.stack.split("\n");
return lst[this.#idxSource];
}
#send(data) {
if (server.readyState === WebSocket.OPEN ) {
server.send(data);
} else {
this.#stack.push(data);
}
}
#flush () {
if (server.readyState !== WebSocket.OPEN)
return ;
this.#stack.forEach(elt => server.send(elt));
this.#stack = [];
}
#notify(type) {
let self = this;
return function() {
let obj = { type, args: Array.from(arguments), context: self.#currentPlace() };
let serializedObject = "";
try {
serializedObject = JSON.stringify(obj);
} catch(e) {
obj.args= [ 'Argument(s) not serializable' ];
serializedObject = JSON.stringify(obj);
}
self.#send(serializedObject);
};
}
#runtimeException (msg, url, line, column,err) {
server.send(
JSON.stringify(
{type: "exception", args: [{ message: msg, url: url, line: line, column: column }] }
)
);
return false;
}
log = this.notify('log');
info = this.notify('info');
warn = this.notify('warn');
error = this.notify('error');
static init(address) {
let _address = address || 'ws://localhost:8088';
const remoteConsole = new ARCSRemoteConsole(address);
const console = globalThis.console;
console.error = remoteConsole.error;
console.warn = remoteConsole.warn;
console.info = remoteConsole.info;
console.log = remoteConsole.log;
console.tainted = true;
const window = globalThis.window;
window.onerror = remoteConsole.runtimeException;
}
}
......@@ -25,7 +25,7 @@ class RemoteConsole {
this.#server = new globalThis.WebSocket(address);
this.#idxSource = (globalThis.navigator.userAgent.match(/firefox|fxios/i))?2:3;
this.#server.onopen = function() {
self.flush();
self.#flush();
}
}
}
......
import WebSocket, {WebSocketServer} from 'ws';
import Chalk from 'chalk';
let serverConfig = {
port: 8088,
};
if (process.argv.length > 2) {
serverConfig.port = parseInt(process.argv[2]);
}
let wss = new WebSocketServer(serverConfig);
wss.on('connection', function (ws) {
ws.on('message', function (message) {
let obj = JSON.parse(message);
switch(obj.type) {
case 'log':
console.log(Chalk.green("[log]"), Chalk.white.dim(obj.context),"\n", ...obj.args);
break;
case 'info':
console.log(Chalk.cyan("[info]"), Chalk.white.dim(obj.context),"\n", ...obj.args);
break;
case 'warn':
console.log(Chalk.yellow("[warn]"),Chalk.white.dim(obj.context),"\n", ...obj.args);
break;
case 'error':
console.log(Chalk.red("[error]"), Chalk.white.dim(obj.context),"\n", ...obj.args);
break;
}
//console.log('received: %s', message);
});
});