diff --git a/backend/app.js b/backend/app.js index 2569b46..6e5a3dd 100644 --- a/backend/app.js +++ b/backend/app.js @@ -23,11 +23,15 @@ app.use(express.urlencoded({ extended: false })); if (process.env.ZU_DISABLE_AUTH !== "true") { app.use( bearerToken({ - headerKey: "Bearer", + headerKey: "token", }) ); } +if (process.env.NODE_ENV === "production") { + console.debug = function () {}; +} + if ( process.env.NODE_ENV === "production" && process.env.ZU_SECURE_HEADERS !== "false" @@ -56,6 +60,18 @@ initAdmin().then(function (admin) { db.defaults({ users: [admin], networks: [] }).write(); }); +if (process.env.ZU_LAST_SEEN_FETCH !== "false") { + let schedule = process.env.ZU_LAST_SEEN_SCHEDULE || "*/5 * * * *"; + cron.schedule(schedule, () => { + console.debug("Running scheduled job"); + const networks = db.get("networks").value(); + networks.forEach((network) => { + console.debug("Processing " + network.id); + pingAll(network); + }); + }); +} + const routerAPI = express.Router(); const routerController = express.Router(); @@ -76,13 +92,4 @@ app.use(async function (err, req, res) { res.status(500).json({ error: "500 Internal server error" }); }); -// ping all networks every 5 minutes -cron.schedule('5 * * * *', () => { - const networks = db.get('networks').value(); - networks.forEach((network) => { - pingAll(network); - }) -}); - - module.exports = app; diff --git a/backend/services/member.js b/backend/services/member.js index 26e4a32..bbdb18e 100644 --- a/backend/services/member.js +++ b/backend/services/member.js @@ -25,13 +25,14 @@ async function getMemberAdditionalData(data) { network.defaults({ members: [] }).get("members").write(); // END MIGRATION SECTION - const additionalData = db + const member = db .get("networks") .find({ id: data.nwid }) .get("members") - .find({ id: data.id }) - .get("additionalConfig") - .value(); + .find({ id: data.id }); + + const additionalData = member.get("additionalConfig").value(); + const lastOnline = member.get("lastOnline").value() || 0; const peer = await getPeer(data.id); let peerData = {}; @@ -57,11 +58,11 @@ async function getMemberAdditionalData(data) { return { id: data.nwid + "-" + data.id, - type: "Member", - clock: Math.floor(new Date().getTime() / 1000), + clock: new Date().getTime(), networkId: data.nwid, nodeId: data.id, controllerId: ZT_ADDRESS, + lastOnline: lastOnline, ...additionalData, ...peerData, config: data, diff --git a/backend/services/network.js b/backend/services/network.js index 91234ca..568efef 100644 --- a/backend/services/network.js +++ b/backend/services/network.js @@ -23,8 +23,7 @@ async function getNetworkAdditionalData(data) { return { id: data.id, - type: "Network", - clock: Math.floor(new Date().getTime() / 1000), + clock: new Date().getTime(), ...additionalData.value(), config: data, }; diff --git a/backend/utils/ping.js b/backend/utils/ping.js index ae3b675..0f37589 100644 --- a/backend/utils/ping.js +++ b/backend/utils/ping.js @@ -1,22 +1,29 @@ const api = require("./controller-api"); const db = require("./db"); -export default pingAll; -async function pingAll (network) { - await Promise.all(network.members.map((async (member) => { - try { - await api.get("peer/" + member.id); - // write lastOnelineTime field in db - db.get("networks") - .filter({ id: network.id }) - .map("members") - .first() - .filter({ id: member.id }) - .first() - .set("lastOnlineTime", new Date().getTime()) - .write(); - } catch (err) { - return; - } - }))); -}; +async function pingAll(network) { + await Promise.all( + network.members.map(async (member) => { + console.debug("Processing " + member.id); + api + .get("peer/" + member.id) + .then(async function () { + // write lastOneline field in db + db.get("networks") + .filter({ id: network.id }) + .map("members") + .first() + .filter({ id: member.id }) + .first() + .set("lastOnline", new Date().getTime()) + .write(); + }) + .catch(function (err) { + console.debug("Couldn't fetch", member.id); + return; + }); + }) + ); +} + +module.exports = pingAll; diff --git a/backend/utils/zt-address.js b/backend/utils/zt-address.js index fcadafc..c91b052 100644 --- a/backend/utils/zt-address.js +++ b/backend/utils/zt-address.js @@ -5,6 +5,8 @@ module.exports = async function () { const res = await api.get("status"); return res.data.address; } catch (err) { - console.error(err); + console.error( + "Couldn't connect to the controller on " + err.config.baseURL + ); } }; diff --git a/frontend/package.json b/frontend/package.json index 9d29971..d8c06bf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,6 +9,7 @@ "@uiw/react-codemirror": "^3.1.0", "axios": "^0.27.2", "codemirror": "^5.62.3", + "date-fns": "^2.29.2", "history": "^5.3.0", "ipaddr.js": "^2.0.1", "lodash": "^4.17.21", diff --git a/frontend/src/components/NetworkMembers/NetworkMembers.jsx b/frontend/src/components/NetworkMembers/NetworkMembers.jsx index 0219a93..6a0097a 100644 --- a/frontend/src/components/NetworkMembers/NetworkMembers.jsx +++ b/frontend/src/components/NetworkMembers/NetworkMembers.jsx @@ -14,6 +14,7 @@ import DataTable from "react-data-table-component"; import { useParams } from "react-router-dom"; import API from "utils/API"; import { parseValue, replaceValue, setValue } from "utils/ChangeHelper"; +import { formatDistance } from "date-fns"; import AddMember from "./components/AddMember"; import DeleteMember from "./components/DeleteMember"; import ManagedIP from "./components/ManagedIP"; @@ -98,40 +99,40 @@ function NetworkMembers({ network }) { }, { id: "status", - name: "Peer status", + name: "Last seen", minWidth: "100px", cell: (row) => - row.online === 0 ? ( - OFFLINE - ) : row.online === 1 ? ( - - {"ONLINE (v" + - row.config.vMajor + - "." + - row.config.vMinor + - "." + - row.config.vRev + - ")"} + row.online === 1 ? ( + {"ONLINE"} + ) : row.controllerId === row.config.address ? ( + {"CONTROLLER"} + ) : row.online === 0 ? ( + + {row.lastOnline !== 0 + ? formatDistance(row.lastOnline, row.clock, { + includeSeconds: false, + addSuffix: true, + }) + : "OFFLINE"} ) : ( - - {"RELAYED (v" + - row.config.vMajor + - "." + - row.config.vMinor + - "." + - row.config.vRev + - ")"} - + {"RELAYED"} ), }, { id: "physicalip", - name: "Physical IP / Latency", + name: "Version / Physical IP / Latency", minWidth: "220px", cell: (row) => row.online === 1 ? (

+ {"v" + + row.config.vMajor + + "." + + row.config.vMinor + + "." + + row.config.vRev} +
{row.physicalAddress + "/" + row.physicalPort}
{"(" + row.latency + " ms)"} @@ -181,7 +182,7 @@ function NetworkMembers({ network }) { spacing={0} direction="column" alignItems="center" - justify="center" + justifyContent="center" style={{ minHeight: "50vh", }} diff --git a/frontend/src/components/NetworkSettings/NetworkSettings.jsx b/frontend/src/components/NetworkSettings/NetworkSettings.jsx index aef274f..c45a6e8 100644 --- a/frontend/src/components/NetworkSettings/NetworkSettings.jsx +++ b/frontend/src/components/NetworkSettings/NetworkSettings.jsx @@ -69,8 +69,8 @@ function NetworkSettings({ network, setNetwork }) { value={network["description"]} onChange={handleChange("description")} multiline - rows={2} - rowsMax={Infinity} + minRows={2} + maxRows={Infinity} label="Description" variant="filled" InputLabelProps={{ diff --git a/frontend/src/utils/API.js b/frontend/src/utils/API.js index 847d940..bcdf6af 100644 --- a/frontend/src/utils/API.js +++ b/frontend/src/utils/API.js @@ -10,6 +10,6 @@ export default axios.create({ localStorage.getItem("disableAuth") === "true" ? {} : { - Authorization: `Bearer ${JSON.parse(localStorage.getItem("token"))}`, + Authorization: `token ${JSON.parse(localStorage.getItem("token"))}`, }, });