Merging dev into main #49
126
package-lock.json
generated
126
package-lock.json
generated
@@ -1967,6 +1967,12 @@
|
||||
"@tybys/wasm-util": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@neodrag/react": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@neodrag/react/-/react-2.3.1.tgz",
|
||||
"integrity": "sha512-mOVefo3mFmaVLs9PB5F5wMXnnclG81qjOaPHyf8YZUnw/Ciz0pAqyJDwDJk0nPTIK5I2x1JdjXSchGNdCxZNRQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -3769,6 +3775,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/classcat": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz",
|
||||
"integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
@@ -3951,6 +3963,111 @@
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-dispatch": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
|
||||
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-drag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
|
||||
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-selection": "3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-ease": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-selection": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-timer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-transition": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
|
||||
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3",
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-ease": "1 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-timer": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"d3-selection": "2 - 3"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-zoom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
|
||||
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-drag": "2 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-selection": "2 - 3",
|
||||
"d3-transition": "2 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/data-urls": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
|
||||
@@ -7591,6 +7708,15 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-to-istanbul": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
|
||||
|
||||
@@ -1,178 +1,38 @@
|
||||
import { useEffect } from 'react'
|
||||
import Logging from '../Logging/Logging';
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
// Define the robot type
|
||||
type Robot = {
|
||||
id: string;
|
||||
name: string;
|
||||
port: number;
|
||||
};
|
||||
|
||||
// Define the expected arguments
|
||||
type ConnectedRobotsProps = {
|
||||
connectedRobots: Robot[];
|
||||
setConnectedRobots: React.Dispatch<React.SetStateAction<Robot[]>>;
|
||||
};
|
||||
|
||||
export default function ConnectedRobots({
|
||||
connectedRobots, setConnectedRobots }: ConnectedRobotsProps) {
|
||||
export default function ConnectedRobots() {
|
||||
|
||||
const [connected, setConnected] = useState<boolean | null>(null);
|
||||
useEffect(() => {
|
||||
const eventSource = new EventSource("http://localhost:8000/sse");
|
||||
// We're excepting a stream of data like that looks like this: `data = False` or `data = True`
|
||||
const eventSource = new EventSource("http://localhost:8000/robot/ping_stream");
|
||||
eventSource.onmessage = (event) => {
|
||||
|
||||
// Receive message and parse
|
||||
console.log("received message:", event.data);
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
// Example: data = { event: "robot_connected", id: "pepper_robot1", name: "Pepper", port: 1234 }
|
||||
if (data.event === "robot_connected") {
|
||||
|
||||
// Safeguard id in request.
|
||||
if (data.id === null || data.id === undefined) {
|
||||
console.log(`Missing robot id in connection request.
|
||||
Use format: 'data: {event = 'robot_connected', id = <id>, (optional) name = <name>, (optional) port = <port>}'.`)
|
||||
return () => eventSource.close();
|
||||
}
|
||||
|
||||
// Safeguard duplicates
|
||||
if (connectedRobots.some(robot => robot.id === data.id))
|
||||
console.log("connection request was sent for id: ", data.id,
|
||||
" however this id was already present at current time");
|
||||
|
||||
// Add to connected robots while checking name and port for undefineds.
|
||||
else {
|
||||
const name = data.name ?? "no given name";
|
||||
const port = typeof data.port === "number" ? data.port : -1;
|
||||
setConnectedRobots(robots => [...robots, { id: data.id, name: name, port: port }]);
|
||||
}
|
||||
// Set connected to value.
|
||||
try {
|
||||
setConnected(data)
|
||||
}
|
||||
if (data.event === "robot_disconnected") {
|
||||
// Safeguard id in request.
|
||||
if (data.id === null || data.id === undefined) {
|
||||
console.log("Missing robot id in connection request. Use format: 'data: {event = 'robot_disconnected', id = <id>}'.");
|
||||
return () => eventSource.close();
|
||||
}
|
||||
|
||||
// Filter out same ids (should only be one)
|
||||
setConnectedRobots(robots => robots.filter(robot => robot.id !== data.id));
|
||||
}
|
||||
if (data.event === "robot_list") {
|
||||
if (data.list === null || data.list === undefined) {
|
||||
console.log("Missing list in robot_list request. Use format: 'data: {event = 'robot_list', list = <list>}'.");
|
||||
return () => eventSource.close();
|
||||
}
|
||||
|
||||
// Set the robot list to the one found in CB
|
||||
setConnectedRobots(data.list);
|
||||
catch {
|
||||
console.log("couldnt extract connected from incoming ping data")
|
||||
}
|
||||
|
||||
} catch {
|
||||
console.log("Unparsable SSE message:", event.data);
|
||||
console.log("Ping message not in correct format:", event.data);
|
||||
}
|
||||
};
|
||||
return () => eventSource.close();
|
||||
}, [connectedRobots]);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Robots Connected</h1>
|
||||
<h1>Is robot currently connected?</h1>
|
||||
<div>
|
||||
<h2>Connected Robots</h2>
|
||||
<ul>
|
||||
{connectedRobots.map(robot =>
|
||||
// Map all the robots in an unordered list
|
||||
<li key={robot.id}>
|
||||
<strong>{robot.name}</strong> (ID: {robot.id}, Port: {robot.port === -1 ? "No given port" : robot.port})
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={"flex-col gap-lg"}>
|
||||
<div className={"flex-row gap-md justify-center"}>
|
||||
<button onClick={() => {
|
||||
// Let's test the reload function.
|
||||
const example_list = [{ id: "pepper_robot1", name: "Pepper1", port: 1234 },
|
||||
{ id: "pepper_robot2", name: "Pepper2", port: 1235 },
|
||||
{ id: "pepper_robot3", name: "Pepper3", port: 1236 },
|
||||
{ id: "pepper_robot4", name: "Pepper4", port: 1237 }]
|
||||
|
||||
const example_event = `{
|
||||
"event": "robot_list", "list":
|
||||
[{ "id": "pepper_robot1",
|
||||
"name": "Pepper1",
|
||||
"port": 1234 },{
|
||||
|
||||
"id": "pepper_robot2",
|
||||
"name": "Pepper2",
|
||||
"port": 1235 },{
|
||||
|
||||
"id": "pepper_robot3",
|
||||
"name": "Pepper3",
|
||||
"port": 1236 }, {
|
||||
|
||||
"id": "pepper_robot4",
|
||||
"name": "Pepper4",
|
||||
"port": 1237 }]}`
|
||||
|
||||
// Now let's put it through the same steps as the event would do. :)
|
||||
try {
|
||||
const data = JSON.parse(example_event);
|
||||
if (data.event === "robot_list") {
|
||||
if (data.list === null || data.list === undefined) {
|
||||
console.log("Missing list in robot_list request. Use format: 'data: {event = 'robot_list', list = <list>}'.");
|
||||
return;
|
||||
}
|
||||
// Check if it is as expected.
|
||||
if (JSON.stringify(data.list) !== JSON.stringify(example_list)) {
|
||||
console.log("Dummy reload failed: list don't match.")
|
||||
}
|
||||
else {
|
||||
console.log("Dummy reload succes!!")
|
||||
}
|
||||
} else {
|
||||
console.log("Dummy reload failed, didn't parse to 'data.event === 'robot_list'.'")
|
||||
}
|
||||
} catch {
|
||||
console.log("Dummy reload failed: didnt parse correctly.")
|
||||
}
|
||||
}}>Dummy Reload from CB</button>
|
||||
<button onClick={() => {
|
||||
// Example dummy robots
|
||||
const connection_dummies: Robot[] = [
|
||||
{ id: "pepper_robot1", name: "Pepper One", port: 8001 },
|
||||
{ id: "pepper_robot2", name: "Pepper Two", port: 8002 },
|
||||
{ id: "naoqi_robot1", name: "Naoqi One", port: 9001 },
|
||||
{ id: "naoqi_robot2", name: "Naoqi Two", port: 9002 },
|
||||
{ id: "noport1", name: "I dont have a port in my request >:)", port: -1 },
|
||||
{ id: "noname1", name: "no given name", port: 2001 }
|
||||
];
|
||||
const randomIndex = Math.floor(Math.random() * connection_dummies.length);
|
||||
const randomConnectionDummy = connection_dummies[randomIndex];
|
||||
|
||||
if (connectedRobots.some(robot => robot.id === randomConnectionDummy.id))
|
||||
console.log("connection request was sent for id: ", randomConnectionDummy.id,
|
||||
" however this id was already present at current time");
|
||||
else
|
||||
setConnectedRobots(robots => [...robots, randomConnectionDummy]);
|
||||
}}>'Sent connected event'</button>
|
||||
<button onClick={() => {
|
||||
// Example disconnection bots
|
||||
const disconnection_dummies = [
|
||||
{ id: "pepper_robot1" },
|
||||
{ id: "pepper_robot2" },
|
||||
{ id: "naoqi_robot1" },
|
||||
{ id: "naoqi_robot2" },
|
||||
{ id: "noport1", name: "I dont have a port in my request >:)", port: -1 },
|
||||
{ id: "noname1", name: "no given name", port: 2001 }
|
||||
];
|
||||
const randomIndex = Math.floor(Math.random() * disconnection_dummies.length);
|
||||
const randomDisconnectionDummy = disconnection_dummies[randomIndex];
|
||||
|
||||
setConnectedRobots(robots => robots.filter(robot => robot.id !== randomDisconnectionDummy.id));
|
||||
}}>'Sent disconnected event'</button>
|
||||
<button onClick={() => {
|
||||
setConnectedRobots([]);
|
||||
}}>Reset</button>
|
||||
</div>
|
||||
<h2>Robot is currently: {connected == null ? "checking..." : (connected ? "connected! 🟢" : "not connected... 🔴")} </h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user