mirror of
https://github.com/gethomepage/homepage.git
synced 2026-04-04 01:01:22 -07:00
Enhancement: fallback for missing si network stats (#6367)
This commit is contained in:
@@ -90,17 +90,74 @@ describe("pages/api/widgets/resources", () => {
|
||||
});
|
||||
|
||||
it("returns 404 when requested network interface does not exist", async () => {
|
||||
si.networkStats.mockResolvedValueOnce([{ iface: "en0" }]);
|
||||
si.networkStats.mockResolvedValueOnce([{ iface: "en0" }]).mockResolvedValueOnce([
|
||||
{
|
||||
iface: "missing",
|
||||
operstate: "unknown",
|
||||
rx_bytes: 0,
|
||||
rx_dropped: 0,
|
||||
rx_errors: 0,
|
||||
tx_bytes: 0,
|
||||
tx_dropped: 0,
|
||||
tx_errors: 0,
|
||||
rx_sec: null,
|
||||
tx_sec: null,
|
||||
ms: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
const req = { query: { type: "network", interfaceName: "missing" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(si.networkStats).toHaveBeenNthCalledWith(1, "*");
|
||||
expect(si.networkStats).toHaveBeenNthCalledWith(2, "missing");
|
||||
expect(res.statusCode).toBe(404);
|
||||
expect(res.body).toEqual({ error: "Interface not found" });
|
||||
});
|
||||
|
||||
it("falls back to direct named interface query when wildcard enumeration misses it", async () => {
|
||||
si.networkStats.mockResolvedValueOnce([{ iface: "eth0", rx_bytes: 1 }]).mockResolvedValueOnce([
|
||||
{
|
||||
iface: "eno1",
|
||||
operstate: "up",
|
||||
rx_bytes: 1000,
|
||||
rx_dropped: 0,
|
||||
rx_errors: 0,
|
||||
tx_bytes: 500,
|
||||
tx_dropped: 0,
|
||||
tx_errors: 0,
|
||||
rx_sec: null,
|
||||
tx_sec: null,
|
||||
ms: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
const req = { query: { type: "network", interfaceName: "eno1" } };
|
||||
const res = createMockRes();
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(si.networkStats).toHaveBeenNthCalledWith(1, "*");
|
||||
expect(si.networkStats).toHaveBeenNthCalledWith(2, "eno1");
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body.interface).toBe("eno1");
|
||||
expect(res.body.network).toEqual({
|
||||
iface: "eno1",
|
||||
operstate: "up",
|
||||
rx_bytes: 1000,
|
||||
rx_dropped: 0,
|
||||
rx_errors: 0,
|
||||
tx_bytes: 500,
|
||||
tx_dropped: 0,
|
||||
tx_errors: 0,
|
||||
rx_sec: null,
|
||||
tx_sec: null,
|
||||
ms: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns default interface network stats", async () => {
|
||||
si.networkStats.mockResolvedValueOnce([{ iface: "en0", rx_bytes: 1 }]);
|
||||
si.networkInterfaceDefault.mockResolvedValueOnce("en0");
|
||||
|
||||
@@ -4,6 +4,21 @@ import createLogger from "utils/logger";
|
||||
|
||||
const logger = createLogger("resources");
|
||||
|
||||
function isMissingNetworkStat(networkData, interfaceName) {
|
||||
return (
|
||||
networkData.operstate === "unknown" &&
|
||||
networkData.rx_bytes === 0 &&
|
||||
networkData.rx_dropped === 0 &&
|
||||
networkData.rx_errors === 0 &&
|
||||
networkData.tx_bytes === 0 &&
|
||||
networkData.tx_dropped === 0 &&
|
||||
networkData.tx_errors === 0 &&
|
||||
networkData.rx_sec === null &&
|
||||
networkData.tx_sec === null &&
|
||||
networkData.ms === 0
|
||||
);
|
||||
}
|
||||
|
||||
export default async function handler(req, res) {
|
||||
const { type, target, interfaceName = "default" } = req.query;
|
||||
|
||||
@@ -64,6 +79,17 @@ export default async function handler(req, res) {
|
||||
logger.debug("networkData:", JSON.stringify(networkData));
|
||||
if (interfaceName && interfaceName !== "default") {
|
||||
networkData = networkData.filter((network) => network.iface === interfaceName).at(0);
|
||||
if (!networkData) {
|
||||
// Fallback for e.g. docker where networkStats("*") may not return stats for host interfaces
|
||||
const directNetworkData = await si.networkStats(interfaceName);
|
||||
logger.debug("directNetworkData:", JSON.stringify(directNetworkData));
|
||||
networkData = Array.isArray(directNetworkData) ? directNetworkData.at(0) : null;
|
||||
|
||||
// si returns unknown + zeroes when interface truly does not exist
|
||||
if (!networkData || isMissingNetworkStat(networkData, interfaceName)) {
|
||||
networkData = null;
|
||||
}
|
||||
}
|
||||
if (!networkData) {
|
||||
return res.status(404).json({
|
||||
error: "Interface not found",
|
||||
|
||||
Reference in New Issue
Block a user