This is an automated email from the ASF dual-hosted git repository.
erisu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-paramedic.git
The following commit(s) were added to refs/heads/master by this push:
new 341aa4a feat!: replace socket.io with ws (#283)
341aa4a is described below
commit 341aa4a1745f04acf27d81b2d818d1423a5f9d74
Author: エリス <[email protected]>
AuthorDate: Wed Dec 10 10:27:50 2025 +0900
feat!: replace socket.io with ws (#283)
---
.ratignore | 1 -
LICENSE | 6 -
NOTICE | 9 -
lib/LocalServer.js | 207 +++++++++++++++++------
lib/PluginsManager.js | 2 +-
lib/paramedic.js | 2 +-
package-lock.json | 271 +-----------------------------
package.json | 4 +-
paramedic-plugin/JasmineParamedicProxy.js | 34 ++--
paramedic-plugin/paramedic.js | 42 ++++-
paramedic-plugin/plugin.xml | 2 +-
paramedic-plugin/socket.io.min.js | 7 -
12 files changed, 221 insertions(+), 366 deletions(-)
diff --git a/.ratignore b/.ratignore
index 2369ebe..dc327fc 100644
--- a/.ratignore
+++ b/.ratignore
@@ -18,4 +18,3 @@
.git/
coverage/
node_modules/
-paramedic-plugin/socket.io.min.js
diff --git a/LICENSE b/LICENSE
index 0dc930c..f433b1a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -175,9 +175,3 @@
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
-
-================================================================================
-paramedic-plugin/socket.io.min.js
-================================================================================
-Copyright (c) 2014-2023 Guillermo Rauch
-MIT License - http://opensource.org/licenses/mit-license.php
diff --git a/NOTICE b/NOTICE
index 0b5ca3b..8ec56a5 100644
--- a/NOTICE
+++ b/NOTICE
@@ -3,12 +3,3 @@ Copyright 2012 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
-
---
-
-This product includes software developed by:
-
-- ./paramedic-plugin/socket.io.min.js
-
- Copyright 2014-2023 Guillermo Rauch
- Licensed under the MIT License
diff --git a/lib/LocalServer.js b/lib/LocalServer.js
index 034cf6c..cda76ee 100644
--- a/lib/LocalServer.js
+++ b/lib/LocalServer.js
@@ -17,32 +17,58 @@
under the License.
*/
+const { spawn } = require('node:child_process');
+const http = require('node:http');
+const { EventEmitter } = require('node:events');
+
+const WebSocket = require('ws');
const Q = require('q');
-const io = require('socket.io');
const portChecker = require('tcp-port-used');
-const { EventEmitter } = require('events');
const shell = require('shelljs');
-const { spawn } = require('child_process');
+
const { logger, execPromise, utilities } = require('./utils');
-// how many ms without a pong packet to consider the connection closed
-const CONNECTION_HEARBEAT_PING_TIMEOUT = 60000;
-// how many ms before sending a new ping packet
-const CONNECTION_HEARBEAT_PING_INTERVAL = 25000;
+/**
+ * How long (in milliseconds) a client is allowed to go without responding
+ * to a "ping" before the server treats the connection as closed.
+ */
+const WS_HEARTBEAT_TIMEOUT = 60000;
+/**
+ * How often (in milliseconds) the server will sends a WebSocket "ping"
+ * to verify if the client is still active.
+ */
+const WS_HEARTBEAT_INTERVAL = 25000;
+// List of valid websocket events
+const WS_VALID_EVENTS = [
+ 'deviceLog',
+ 'disconnect',
+ 'deviceInfo',
+ 'jasmineStarted',
+ 'specStarted',
+ 'specDone',
+ 'suiteStarted',
+ 'suiteDone',
+ 'jasmineDone'
+];
+/**
+ * TODO: Remove file transfer server from this repo. Should be managed by file
transfer plugin.
+ */
class LocalServer extends EventEmitter {
constructor (port) {
super();
this.port = port;
- this.server = { alive: false };
+ this.fileTransferServer = { alive: false };
+ this.httpServer = null;
+ this.wss = null;
}
cleanUp () {
logger.normal('local-server: killing local file transfer server if
it\'s up...');
- if (this.server.alive) {
- this.server.alive = false;
- this.server.process.kill('SIGKILL');
+ if (this.fileTransferServer.alive) {
+ this.fileTransferServer.alive = false;
+ this.fileTransferServer.process.kill('SIGKILL');
}
}
@@ -63,64 +89,149 @@ class LocalServer extends EventEmitter {
return execPromise('npm i');
}).then(() => {
logger.normal('local-server: starting local file transfer server');
- this.server.process = spawn('node', ['server.js']);
- this.server.alive = true;
+ this.fileTransferServer.process = spawn('node', ['server.js']);
+ this.fileTransferServer.alive = true;
logger.info('local-server: local file transfer server started');
shell.popd();
shell.popd();
- return this.server;
+ return this.fileTransferServer;
});
}
createSocketListener () {
- const listener = io(this.port, {
- pingTimeout: CONNECTION_HEARBEAT_PING_TIMEOUT,
- pingInterval: CONNECTION_HEARBEAT_PING_INTERVAL,
- cors: '*'
- });
+ this.httpServer = http.createServer();
+ this.wss = new WebSocket.Server({ server: this.httpServer });
- listener.on('connection', (socket) => {
- logger.info('local-server: new socket connection');
- this.connection = socket;
-
- // server methods
- [
- 'deviceLog',
- 'disconnect',
- 'deviceInfo',
- 'jasmineStarted',
- 'specStarted',
- 'specDone',
- 'suiteStarted',
- 'suiteDone',
- 'jasmineDone'
- ].forEach((route) => {
- socket.on(route, (data) => {
- this.emit(route, data);
- });
+ /**
+ * When a client connects, we begin listening for all supported events
sent
+ * from the device. These include lifecycle events such as:
+ * - test has started (jasmineStarted) or finished (jasmineDone)
+ * - spec has started (specStarted) or finished (specDone)
+ * - suite has started (suiteStarted) or finished (suiteDone)
+ * - device logs, device info, etc.
+ *
+ * We also maintain a simple heartbeat mechanism. Every time the
client sends
+ * a WebSocket "pong" or any message, we update the timestamp of the
last
+ * activity. If the client stops responding for too long, the server
will
+ * assume the device has gone away and will terminate the connection.
+ *
+ * This prevents Paramedic from hanging indefinitely when a device or
WebView
+ * unexpectedly disconnects.
+ */
+ this.wss.on('connection', (ws) => {
+ ws.lastActivity = Date.now();
+ logger.verbose(
+ `[paramedic] local-server: new websocket connection
(${toReadableDateTime(ws.lastActivity)})`
+ );
+
+ ws.on('pong', () => {
+ ws.lastActivity = Date.now();
+ logger.verbose(
+ `[paramedic] local-server: received pong
(${toReadableDateTime(ws.lastActivity)})`
+ );
+ });
+
+ ws.on('message', (raw) => {
+ ws.lastActivity = Date.now();
+ logger.verbose(
+ `[paramedic] local-server: received message
(${toReadableDateTime(ws.lastActivity)})`
+ );
+
+ let msg;
+ try {
+ msg = JSON.parse(raw.toString());
+ } catch (err) {
+ logger.error(
+ '[paramedic] local-server: invalid JSON message with
error: ' + err.message
+ );
+ return;
+ }
+
+ const { event, data } = msg;
+ if (WS_VALID_EVENTS.includes(event)) {
+ this.emit(event, data);
+ }
});
+
+ ws.on('close', () => {
+ this.emit('disconnect');
+ });
+ });
+
+ // The heartbeat ping
+ const interval = setInterval(() => {
+ for (const ws of this.wss.clients) {
+ const idleTime = Date.now() - ws.lastActivity;
+
+ if (idleTime > WS_HEARTBEAT_TIMEOUT) {
+ logger.warn('[paramedic] local-server: WebSocket has timed
out and terminating.');
+ ws.terminate();
+ continue;
+ }
+
+ ws.ping();
+ }
+ }, WS_HEARTBEAT_INTERVAL);
+
+ this.httpServer.listen(this.port, '0.0.0.0', () => {
+ logger.info(
+ `[paramedic] local-server: WebSocket server listening on
ws://0.0.0.0:${this.port}`
+ );
});
+
+ this.wss.stop = () => {
+ clearInterval(interval);
+ this.httpServer.close();
+ };
}
- // Connection address could be platform specific so we pass platform as
param here
- getConnectionAddress (platformId) {
- // build connection uri for localhost based on platform
- return platformId === utilities.ANDROID
- ? 'http://10.0.2.2' // TODO This only seems to work sometimes. See
PR #56
- : 'http://127.0.0.1';
+ /**
+ * Returns the IP address the app should use to reach the Medic server.
+ *
+ * iOS simulators/devices and Android physical devices, with ADB reverse
+ * port enabled can access the host machine using 127.0.0.1.
+ *
+ * Android emulators must use their special loopback address 10.0.2.2.
+ *
+ * @param {string} platform - Platform name (e.g., "android" or "ios").
+ * @param {boolean} shouldReversePort - Whether ADB reverse port is
enabled.
+ * @returns {string} IP address the host
+ */
+ getServerIP (platform, shouldReversePort = false) {
+ // Android emulator
+ if (platform === utilities.ANDROID && !shouldReversePort) {
+ return '10.0.2.2';
+ }
+ // iOS simulator/devices & Android device with reverse, or desktop
+ return '127.0.0.1';
}
- // Connection url could be platform specific so we pass platform as param
here
- getConnectionUrl (platformId) {
- return this.getConnectionAddress(platformId) + ':' + this.port;
+ /**
+ * Returns the full URL for the Medic server used to collect test results.
+ *
+ * @param {string} platform - Platform name (e.g., "android" or "ios").
+ * @returns {string} Fully qualified Medic server URL
+ */
+ getMedicAddress (platform) {
+ return `ws://${this.getServerIP(platform)}:${this.port}`;
}
isDeviceConnected () {
- return !!this.connection;
+ return this.wss && this.wss.clients.size > 0;
}
}
+/**
+ * Converts Unix Epoch time into human readable time
+ *
+ * @param {number} epochMs - Unix Epoch time in milliseconds
+ * @returns {string}
+ */
+function toReadableDateTime (epochMs) {
+ return new Date(epochMs).toLocaleString();
+}
+
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
diff --git a/lib/PluginsManager.js b/lib/PluginsManager.js
index 37322e0..dd31888 100644
--- a/lib/PluginsManager.js
+++ b/lib/PluginsManager.js
@@ -52,7 +52,7 @@ class PluginsManager {
} else {
// no server address specified, starting a local server
const server = new Server(0);
- const fileServerUrl =
server.getConnectionAddress(this.config.getPlatformId()) + ':5001';
+ const fileServerUrl =
`http://${server.getServerIP(this.config.getPlatformId())}:5001`;
additionalArgs += ' --variable
FILETRANSFER_SERVER_ADDRESS=' + fileServerUrl;
}
}
diff --git a/lib/paramedic.js b/lib/paramedic.js
index 2456270..965e247 100644
--- a/lib/paramedic.js
+++ b/lib/paramedic.js
@@ -75,7 +75,7 @@ class ParamedicRunner {
this.injectReporters();
this.subcribeForEvents();
- const logUrl =
this.server.getConnectionUrl(this.config.getPlatformId());
+ const logUrl =
this.server.getMedicAddress(this.config.getPlatformId());
this.writeMedicJson(logUrl);
logger.normal('Start building app and running tests at ' +
(new Date()).toLocaleTimeString());
diff --git a/package-lock.json b/package-lock.json
index 07baadf..0bce2ad 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,10 +16,10 @@
"minimist": "^1.2.8",
"q": "^1.5.1",
"shelljs": "^0.10.0",
- "socket.io": "^4.8.1",
"tcp-port-used": "^1.0.2",
"tmp": "^0.2.5",
- "tree-kill": "^1.2.2"
+ "tree-kill": "^1.2.2",
+ "ws": "^8.18.3"
},
"bin": {
"cordova-paramedic": "main.js"
@@ -310,21 +310,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@socket.io/component-emitter": {
- "version": "3.1.2",
- "resolved":
"https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
- "integrity":
"sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
- "license": "MIT"
- },
- "node_modules/@types/cors": {
- "version": "2.8.19",
- "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
- "integrity":
"sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved":
"https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -346,15 +331,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/node": {
- "version": "24.10.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
- "integrity":
"sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
- "license": "MIT",
- "dependencies": {
- "undici-types": "~7.16.0"
- }
- },
"node_modules/@xmldom/xmldom": {
"version": "0.8.11",
"resolved":
"https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
@@ -364,19 +340,6 @@
"node": ">=10.0.0"
}
},
- "node_modules/accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity":
"sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "license": "MIT",
- "dependencies": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
@@ -630,15 +593,6 @@
],
"license": "MIT"
},
- "node_modules/base64id": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
- "integrity":
"sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
- "license": "MIT",
- "engines": {
- "node": "^4.5.0 || >= 5.9"
- }
- },
"node_modules/big-integer": {
"version": "1.6.52",
"resolved":
"https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
@@ -796,15 +750,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/cookie": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
- "integrity":
"sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/cordova-common": {
"version": "6.0.0",
"resolved":
"https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz",
@@ -823,19 +768,6 @@
"node": ">=20.9.0"
}
},
- "node_modules/cors": {
- "version": "2.8.5",
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
- "integrity":
"sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
- "license": "MIT",
- "dependencies": {
- "object-assign": "^4",
- "vary": "^1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved":
"https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -1021,52 +953,6 @@
"objectorarray": "^1.0.5"
}
},
- "node_modules/engine.io": {
- "version": "6.6.4",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
- "integrity":
"sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
- "license": "MIT",
- "dependencies": {
- "@types/cors": "^2.8.12",
- "@types/node": ">=10.0.0",
- "accepts": "~1.3.4",
- "base64id": "2.0.0",
- "cookie": "~0.7.2",
- "cors": "~2.8.5",
- "debug": "~4.3.1",
- "engine.io-parser": "~5.2.1",
- "ws": "~8.17.1"
- },
- "engines": {
- "node": ">=10.2.0"
- }
- },
- "node_modules/engine.io-parser": {
- "version": "5.2.3",
- "resolved":
"https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
- "integrity":
"sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/engine.io/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity":
"sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
"node_modules/enhanced-resolve": {
"version": "5.18.3",
"resolved":
"https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
@@ -2747,27 +2633,6 @@
"node": ">=8.6"
}
},
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity":
"sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved":
"https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity":
"sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -2815,6 +2680,7 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity":
"sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/natural-compare": {
@@ -2824,15 +2690,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/negotiator": {
- "version": "0.6.3",
- "resolved":
"https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity":
"sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved":
"https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -2845,15 +2702,6 @@
"node": ">=8"
}
},
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved":
"https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity":
"sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved":
"https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
@@ -3520,98 +3368,6 @@
"integrity":
"sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
- "node_modules/socket.io": {
- "version": "4.8.1",
- "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
- "integrity":
"sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
- "license": "MIT",
- "dependencies": {
- "accepts": "~1.3.4",
- "base64id": "~2.0.0",
- "cors": "~2.8.5",
- "debug": "~4.3.2",
- "engine.io": "~6.6.0",
- "socket.io-adapter": "~2.5.2",
- "socket.io-parser": "~4.2.4"
- },
- "engines": {
- "node": ">=10.2.0"
- }
- },
- "node_modules/socket.io-adapter": {
- "version": "2.5.5",
- "resolved":
"https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
- "integrity":
"sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
- "license": "MIT",
- "dependencies": {
- "debug": "~4.3.4",
- "ws": "~8.17.1"
- }
- },
- "node_modules/socket.io-adapter/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity":
"sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/socket.io-parser": {
- "version": "4.2.4",
- "resolved":
"https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
- "integrity":
"sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
- "license": "MIT",
- "dependencies": {
- "@socket.io/component-emitter": "~3.1.0",
- "debug": "~4.3.1"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/socket.io-parser/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity":
"sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/socket.io/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity":
"sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved":
"https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -3994,12 +3750,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/undici-types": {
- "version": "7.16.0",
- "resolved":
"https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
- "integrity":
"sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
- "license": "MIT"
- },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -4010,15 +3760,6 @@
"punycode": "^2.1.0"
}
},
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity":
"sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -4134,9 +3875,9 @@
}
},
"node_modules/ws": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
- "integrity":
"sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity":
"sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
diff --git a/package.json b/package.json
index 7dbe851..4764ad9 100644
--- a/package.json
+++ b/package.json
@@ -37,10 +37,10 @@
"minimist": "^1.2.8",
"q": "^1.5.1",
"shelljs": "^0.10.0",
- "socket.io": "^4.8.1",
"tcp-port-used": "^1.0.2",
"tmp": "^0.2.5",
- "tree-kill": "^1.2.2"
+ "tree-kill": "^1.2.2",
+ "ws": "^8.18.3"
},
"devDependencies": {
"@cordova/eslint-config": "^6.0.0"
diff --git a/paramedic-plugin/JasmineParamedicProxy.js
b/paramedic-plugin/JasmineParamedicProxy.js
index 4b242b3..40aa9d7 100644
--- a/paramedic-plugin/JasmineParamedicProxy.js
+++ b/paramedic-plugin/JasmineParamedicProxy.js
@@ -29,34 +29,34 @@ function JasmineParamedicProxy(socket) {
this.specFailed = 0;
}
-JasmineParamedicProxy.prototype.jasmineStarted = function (o) {
- this.socket.emit('jasmineStarted', o);
+JasmineParamedicProxy.prototype.jasmineStarted = function (payload) {
+ this.socket.cdvSendEvent('jasmineStarted', payload);
};
-JasmineParamedicProxy.prototype.specStarted = function (o) {
- this.socket.emit('specStarted', o);
+JasmineParamedicProxy.prototype.specStarted = function (payload) {
+ this.socket.cdvSendEvent('specStarted', payload);
};
-JasmineParamedicProxy.prototype.specDone = function (o) {
- if (o.status !== 'disabled') {
+JasmineParamedicProxy.prototype.specDone = function (payload) {
+ if (payload.status !== 'disabled') {
this.specExecuted++;
}
- if (o.status === 'failed') {
+ if (payload.status === 'failed') {
this.specFailed++;
}
- this.socket.emit('specDone', o);
+ this.socket.cdvSendEvent('specDone', payload);
};
-JasmineParamedicProxy.prototype.suiteStarted = function (o) {
- this.socket.emit('suiteStarted', o);
+JasmineParamedicProxy.prototype.suiteStarted = function (payload) {
+ this.socket.cdvSendEvent('suiteStarted', payload);
};
-JasmineParamedicProxy.prototype.suiteDone = function (o) {
- this.socket.emit('suiteDone', o);
+JasmineParamedicProxy.prototype.suiteDone = function (payload) {
+ this.socket.cdvSendEvent('suiteDone', payload);
};
-JasmineParamedicProxy.prototype.jasmineDone = function (o) {
+JasmineParamedicProxy.prototype.jasmineDone = function (payload) {
var p = 'Desktop';
var devmodel = 'none';
var version = cordova.version;
@@ -66,22 +66,22 @@ JasmineParamedicProxy.prototype.jasmineDone = function (o) {
version = device.version.toLowerCase();
}
- o = o || {};
+ payload = payload || {};
// include platform info
- o.cordova = {
+ payload.cordova = {
platform: (platformMap.hasOwnProperty(p) ? platformMap[p] : p),
version: version,
model: devmodel
};
// include common spec results
- o.specResults = {
+ payload.specResults = {
specExecuted : this.specExecuted,
specFailed : this.specFailed
};
- this.socket.emit('jasmineDone', o);
+ this.socket.cdvSendEvent('jasmineDone', payload);
};
module.exports = JasmineParamedicProxy;
diff --git a/paramedic-plugin/paramedic.js b/paramedic-plugin/paramedic.js
index 460ddae..79bccfc 100644
--- a/paramedic-plugin/paramedic.js
+++ b/paramedic-plugin/paramedic.js
@@ -18,8 +18,6 @@
under the License.
*/
-var io = cordova.require('cordova-plugin-paramedic.socket.io.min');
-
var PARAMEDIC_SERVER_DEFAULT_URL = 'http://127.0.0.1:8008';
function Paramedic() {
@@ -29,13 +27,42 @@ function Paramedic() {
Paramedic.prototype.initialize = function() {
var me = this;
var connectionUri = me.loadParamedicServerUrl();
- this.socket = io(connectionUri);
- this.socket.on('connect', function () {
- console.log('Paramedic has been successfully connected to the server');
- if (typeof device != 'undefined') me.socket.emit('deviceInfo', device);
+ const socket = new WebSocket(connectionUri);
+ /**
+ * While the testing application is running, events may be generated
+ * before the socket connection is fully open. In this case, the events
+ * are stored in the eventQueue and will be sent once the connection
+ * has opened.
+ */
+ socket.cdvEventQueue = [];
+
+ socket.cdvSendEvent = function (eventName, payload) {
+ const message = JSON.stringify({ event: eventName, data: payload });
+
+ /**
+ * Sends the event immediately if the socket is open; otherwise,
+ * queues the event to be sent later when the connection opens.
+ */
+ if (socket.readyState === WebSocket.OPEN) {
+ socket.send(message);
+ } else {
+ socket.cdvEventQueue.push(message);
+ }
+ };
+
+ /**
+ * Sends all queued events once the socket connection is open.
+ */
+ socket.addEventListener('open', () => {
+ for (const msg of socket.cdvEventQueue) {
+ socket.send(msg);
+ }
+ socket.cdvEventQueue = [];
});
+ this.socket = socket;
+
this.overrideConsole();
this.injectJasmineReporter();
@@ -45,7 +72,6 @@ Paramedic.prototype.initialize = function() {
Paramedic.prototype.overrideConsole = function () {
-
var origConsole = window.console;
var me = this;
@@ -53,7 +79,7 @@ Paramedic.prototype.overrideConsole = function () {
return function () {
origConsole[type].apply(origConsole, arguments);
- me.socket.emit('deviceLog', { type: type, msg:
Array.prototype.slice.apply(arguments) });
+ me.socket.cdvSendEvent('deviceLog', { type: type, msg:
Array.prototype.slice.apply(arguments) });
};
}
window.console = {
diff --git a/paramedic-plugin/plugin.xml b/paramedic-plugin/plugin.xml
index 9d021d2..08b078d 100644
--- a/paramedic-plugin/plugin.xml
+++ b/paramedic-plugin/plugin.xml
@@ -27,7 +27,6 @@
<description>Cordova Paramedic Plugin</description>
<license>Apache 2.0</license>
- <js-module src="socket.io.min.js" name="socket.io.min" />
<js-module src="JasmineParamedicProxy.js" name="JasmineParamedicProxy" />
<js-module src="paramedic.js" name="paramedic">
@@ -37,6 +36,7 @@
<config-file target="config.xml" parent="/*">
<access origin="http://127.0.0.1:*/*" />
<access origin="http://10.0.2.2:*/*" />
+ <access origin="ws://127.0.0.1:*/*" />
<allow-navigation href="http://127.0.0.1:*/*" />
<allow-navigation href="http://10.0.2.2:*/*" />
diff --git a/paramedic-plugin/socket.io.min.js
b/paramedic-plugin/socket.io.min.js
deleted file mode 100644
index c700ce7..0000000
--- a/paramedic-plugin/socket.io.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * Socket.IO v4.6.2
- * (c) 2014-2023 Guillermo Rauch
- * Released under the MIT License.
- */
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof
module?module.exports=e():"function"==typeof
define&&define.amd?define(e):(t="undefined"!=typeof
globalThis?globalThis:t||self).io=e()}(this,(function(){"use strict";function
t(e){return t="function"==typeof Symbol&&"symbol"==typeof
Symbol.iterator?function(t){return typeof t}:function(t){return
t&&"function"==typeof
Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof
t},t(e)}function e(t,e){if(!(t instanceof e [...]
-//# sourceMappingURL=socket.io.min.js.map
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]