From 0e2fe86ae5cb8393239bcc41696e7756a6448b50 Mon Sep 17 00:00:00 2001 From: wsk170 Date: Mon, 18 Nov 2024 09:25:43 +0800 Subject: [PATCH] add ethernet information looks like openwrt 23.05 (#340) * add ethernet information in luci overview * add ethernet information looks like openwrt 23.05 --- package/emortal/autocore/Makefile | 2 +- .../autocore/files/generic/21_ethinfo.js | 179 +++++++++++++----- 2 files changed, 136 insertions(+), 45 deletions(-) diff --git a/package/emortal/autocore/Makefile b/package/emortal/autocore/Makefile index 23c2f69573..8a0a444e7c 100644 --- a/package/emortal/autocore/Makefile +++ b/package/emortal/autocore/Makefile @@ -48,7 +48,7 @@ define Package/autocore/install/Default $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d $(CP) ./files/generic/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/ -ifeq ($(filter ipq% mediatek%, $(TARGETID)),) +ifeq ($(filter ipq%, $(TARGETID)),) $(INSTALL_BIN) ./files/generic/ethinfo $(1)/sbin/ $(INSTALL_DIR) $(1)/www/luci-static/resources/view/status/include diff --git a/package/emortal/autocore/files/generic/21_ethinfo.js b/package/emortal/autocore/files/generic/21_ethinfo.js index fa89c4a2fc..b9a377a956 100644 --- a/package/emortal/autocore/files/generic/21_ethinfo.js +++ b/package/emortal/autocore/files/generic/21_ethinfo.js @@ -1,60 +1,151 @@ 'use strict'; 'require baseclass'; 'require rpc'; +'require uci'; +'require network'; -var callLuciETHInfo = rpc.declare({ - object: 'luci', - method: 'getETHInfo', - expect: { '': {} } +var callSwconfigFeatures = rpc.declare({ + object: 'luci', + method: 'getSwconfigFeatures', + params: ['switch'], + expect: { '': {} } }); +var callSwconfigPortState = rpc.declare({ + object: 'luci', + method: 'getSwconfigPortState', + params: ['switch'], + expect: { result: [] } +}); + +var callLuciBoardJSON = rpc.declare({ + object: 'luci-rpc', + method: 'getBoardJSON', + expect: { '': {} } +}); + +var callLuciNetworkDevices = rpc.declare({ + object: 'luci-rpc', + method: 'getNetworkDevices', + expect: { '': {} } +}); + +function formatSpeed(speed) { + if (!speed) return '-'; + return speed < 1000 ? `${speed} M` : `${speed / 1000} GbE`; +} + +function getPortColor(link, duplex) { + if (!link) return 'background-color: whitesmoke;'; + const color = duplex == 'full' || duplex ? 'greenyellow' : 'darkorange'; + return 'background-color: ' + color; +} + +function getPortIcon(link) { + return L.resource(`icons/port_${link ? 'up' : 'down'}.png`); +} + return L.Class.extend({ - title: _('Ethernet Information'), + title: _('Ethernet Information'), - load: function() { - return Promise.all([ - L.resolveDefault(callLuciETHInfo(), {}) - ]); - }, + load: function () { + return network.getSwitchTopologies().then(function (topologies) { + let tasks = []; - render: function(data) { - var ethinfo = Array.isArray(data[0].ethinfo) ? data[0].ethinfo : []; + for (let switchName in topologies) { + tasks.push( + callSwconfigFeatures(switchName).then( + L.bind(function (features) { + this.features = features; + }, topologies[switchName]) + ) + ); + tasks.push( + callSwconfigPortState(switchName).then( + L.bind(function (ports) { + this.portstate = ports; + }, topologies[switchName]) + ) + ); + } - var table = E('table', { 'class': 'table' }, [ - E('tr', { 'class': 'tr table-titles' }, [ - E('th', { 'class': 'th' }, _('Ethernet Name')), - E('th', { 'class': 'th' }, _('Link Status')), - E('th', { 'class': 'th' }, _('Speed')), - E('th', { 'class': 'th' }, _('Duplex')) - ]) - ]); + return Promise.all([ + topologies, + L.resolveDefault(callLuciBoardJSON(), {}), + L.resolveDefault(callLuciNetworkDevices(), {}) + ]); + }); + }, - cbi_update_table(table, ethinfo.map(function(info) { - var exp1; - var exp2; + render: function (data) { + const topologies = data[0]; + const board = data[1]; + const netdevs = data[2]; - if (info.status == "yes") - exp1 = _('Link Up'); - else if (info.status == "no") - exp1 = _('Link Down'); + const boxStyle = 'max-width: 100px;'; + const boxHeadStyle = + 'border-radius: 7px 7px 0 0;' + + 'text-align: center;' + + 'font-weight:bold;'; + const boxbodyStyle = + 'border: 1px solid lightgrey;' + + 'border-radius: 0 0 7px 7px;' + + 'display:flex; flex-direction: column;' + + 'align-items: center; justify-content:center;'; + const iconStyle = 'margin: 5px; width: 40px;'; + const speedStyle = 'font-size:0.8rem; font-weight:bold;'; + const trafficStyle = + 'border-top: 1px solid lightgrey;' + 'font-size:0.8rem;'; - if (info.duplex == "Full") - exp2 = _('Full Duplex'); - else if (info.duplex == "Half") - exp2 = _('Half Duplex'); - else - exp2 = _('-'); + const ethPorts = []; + const wan = netdevs[board.network.wan.device]; + const { speed, duplex, carrier } = wan.link; + let portIcon = getPortIcon(carrier); + let portColor = getPortColor(carrier, duplex); + ethPorts.push( + E('div', { style: boxStyle }, [ + E('div', { style: boxHeadStyle + portColor }, 'WAN'), + E('div', { style: boxbodyStyle }, [ + E('img', { style: iconStyle, src: portIcon }), + E('div', { style: speedStyle }, formatSpeed(speed)), + E('div', { style: trafficStyle }, [ + '\u25b2\u202f%1024.1mB'.format(wan.stats.tx_bytes), + E('br'), + '\u25bc\u202f%1024.1mB'.format(wan.stats.rx_bytes) + ]) + ]) + ]) + ); - return [ - info.name, - exp1, - info.speed, - exp2 - ]; - })); + const switch0 = topologies.switch0; + for (const port of switch0.ports) { + if (!port.label.startsWith('LAN')) continue; + const { link, duplex, speed } = switch0.portstate[port.num]; + portIcon = getPortIcon(link); + portColor = getPortColor(link, duplex); + const txrx = { tx_bytes: 0, rx_bytes: 0 }; + const lanStats = netdevs['br-lan'].stats; + const { tx_bytes, rx_bytes } = link ? lanStats : txrx; + ethPorts.push( + E('div', { style: boxStyle }, [ + E('div', { style: boxHeadStyle + portColor }, port.label), + E('div', { style: boxbodyStyle }, [ + E('img', { style: iconStyle, src: portIcon }), + E('div', { style: speedStyle }, formatSpeed(speed)), + E('div', { style: trafficStyle }, [ + '\u25b2\u202f%1024.1mB'.format(tx_bytes), + E('br'), + '\u25bc\u202f%1024.1mB'.format(rx_bytes) + ]) + ]) + ]) + ); + } - return E([ - table - ]); - } + const gridStyle = + 'display:grid; grid-gap: 5px 5px;' + + 'grid-template-columns:repeat(auto-fit, minmax(70px, 1fr));' + + 'margin-bottom:1em'; + return E('div', { style: gridStyle }, ethPorts); + } });