aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/network.lua
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/network.lua')
-rw-r--r--widgets/network.lua181
1 files changed, 0 insertions, 181 deletions
diff --git a/widgets/network.lua b/widgets/network.lua
deleted file mode 100644
index 20b0573..0000000
--- a/widgets/network.lua
+++ /dev/null
@@ -1,181 +0,0 @@
--- Network: throughput as two lines on one chart, with the LAN and public
--- addresses.
---
--- The rates come from the interface's own byte counters, read every draw: two
--- file reads, no subprocess. The public address comes from a cache file,
--- because a network call in the draw hook would freeze the dashboard when it
--- hung.
-
-local card = require 'lib.card'
-local data = require 'lib.data'
-
-local M = {}
-
--- The interface to graph. br0 is this host's bridge, matching the old text
--- config.
---
--- Note what this means: a bridge carries VM-to-host traffic that never reaches
--- the router, so a local copy spikes the graph. That was true of the old
--- config too and is accepted; this constant is the one edit that changes it.
-local IFACE = 'br0'
-
-local CACHE = (os.getenv('XDG_CACHE_HOME') or (os.getenv('HOME') .. '/.cache'))
- .. '/udt/pubip.txt'
-
--- A public address older than this is not shown. Eight sampling intervals: by
--- then the sampler has failed repeatedly, and an address that may no longer be
--- yours displayed with confidence is worse than '--'.
-local STALE_AFTER = 4 * 3600
-
-local STAT = '/sys/class/net/' .. IFACE .. '/statistics/'
-
--- Module state: the history outlives the frame, which is the whole point.
--- It does not outlive a conky restart, so the chart starts empty and fills
--- left to right.
-local rx_counter, tx_counter
-local rx_hist, tx_hist = {}, {}
-local hist_len = 0
-local lan_addr = nil
-
--- Sampled every ~2s whatever the draw rate, so the chart keeps one point per
--- sample rather than per draw. 1.9 not 2: draws jitter by a few ms.
-local gate = data.new_gate(1.9)
-local down, up = nil, nil
-
--- Append to a fixed-length history, dropping the oldest. A plain array with
--- table.remove(1) rather than a circular buffer with an index: the lengths
--- here are a few hundred at most and the draw is every two seconds, so the
--- O(n) shift is free and the array is already in draw order.
-local function push(hist, v, len)
- hist[#hist + 1] = v
- while #hist > len do table.remove(hist, 1) end
-end
-
-local function read_counter(file)
- local s = data.slurp(STAT .. file)
- if not s then return nil end
- return tonumber(s:match('^%s*(%d+)'))
-end
-
--- Bytes per second to a short string. Deliberately not card.human: a rate
--- wants a '/s' and one decimal at most, and reusing card.human would put a
--- suffix meant for capacity onto a speed.
-local function rate_str(bps)
- if not bps then return '--' end
- local units = { 'B', 'K', 'M', 'G' }
- local n, i = bps, 1
- while n >= 1024 and i < #units do n = n / 1024; i = i + 1 end
- if i == 1 then return string.format('%d%s/s', math.floor(n), units[i]) end
- if n >= 100 then return string.format('%.0f%s/s', n, units[i]) end
- return string.format('%.1f%s/s', n, units[i])
-end
-
-function M.draw(cr, rect, colors)
- local inner = card.card(cr, rect, colors)
- local function clamp(v, lo, hi) return math.max(lo, math.min(hi, v)) end
-
- local interval = (conky_info and conky_info.update_interval) or 2
- rx_counter = rx_counter or data.new_rate_counter(interval)
- tx_counter = tx_counter or data.new_rate_counter(interval)
-
- local sampled, now = gate()
- if sampled then
- down = rx_counter:sample(read_counter('rx_bytes'), now)
- up = tx_counter:sample(read_counter('tx_bytes'), now)
- end
-
- -- Fluid type, as every other card does: one base size S drives everything,
- -- taken as the smaller of a height budget and a measured width fit.
- local LABEL_F, BIG_F, ROW_F = 0.30, 1.0, 0.30
- local groups = {
- { { card.title_str(card.ICON.network, 'NET'), card.FONT_MONO, LABEL_F },
- { '888.8M/s', card.FONT_HEAVY, BIG_F } },
- { { '\u{F0318} 192.000.000.000', card.FONT_MONO, ROW_F } },
- { { '\u{F01DA} 888.8M/s', card.FONT_MONO, ROW_F },
- { '\u{F0552} 888.8M/s', card.FONT_MONO, ROW_F } },
- }
- local fixed_units = 1.0 + ROW_F * 2.2 * 3
- local S = clamp(math.min(inner.h * 0.96 / (fixed_units + 1.2),
- card.fit_unit(cr, inner.w * 0.96, groups, 100)), 10, 72)
- local label_size = S * LABEL_F
- local row_size = S * ROW_F
-
- -- Header: the label left, the download rate as the big value at the right.
- -- Download is the headline because it is the number that moves.
- card.font(cr, card.FONT_HEAVY, S * BIG_F, false)
- card.rgba(cr, colors.body)
- card.text_right(cr, inner.x + inner.w, inner.y + S * BIG_F, rate_str(down))
-
- card.font(cr, card.FONT_MONO, label_size, false)
- card.title(cr, inner.x, inner.y + label_size, card.ICON.network, 'NET', colors)
-
- local ey = inner.y + S * BIG_F + row_size * 1.4
- local step = row_size * 2.2
-
- -- The addresses. LAN is memoized on first success and retried while nil: a
- -- bridge may not be up when conky starts.
- lan_addr = lan_addr or data.iface_addr(IFACE)
- card.font(cr, card.FONT_MONO, row_size, false)
- card.rgba(cr, colors.label)
- card.text(cr, inner.x, ey, '\u{F0318}') -- LAN
- card.rgba(cr, colors.value)
- card.text_right(cr, inner.x + inner.w, ey, lan_addr or '--')
- ey = ey + step
-
- local pub = data.kv_parse(data.slurp(CACHE) or '')
- local fetched = tonumber(pub.fetched)
- local pub_txt = '--'
- if pub.ip and fetched and (os.time() - fetched) < STALE_AFTER then
- pub_txt = pub.ip
- end
- card.rgba(cr, colors.label)
- card.text(cr, inner.x, ey, '\u{F059F}') -- globe
- card.rgba(cr, pub_txt == '--' and colors.label or colors.value)
- card.text_right(cr, inner.x + inner.w, ey, pub_txt)
- ey = ey + step * 1.1
-
- -- The chart takes the room left between the addresses and the rate row.
- local rate_row_h = row_size * 2.4
- local chart_top = ey
- local chart_h = (inner.y + inner.h) - chart_top - rate_row_h
- if chart_h > 12 then
- -- One sample per pixel column, so the chart never interpolates. The
- -- buffer is resized when the card is, keeping what it can: a moved card
- -- should not clear the history.
- local want = math.max(8, math.floor(inner.w))
- if want ~= hist_len then
- hist_len = want
- while #rx_hist > hist_len do table.remove(rx_hist, 1) end
- while #tx_hist > hist_len do table.remove(tx_hist, 1) end
- end
- if sampled and down then push(rx_hist, down, hist_len) end
- if sampled and up then push(tx_hist, up, hist_len) end
-
- -- One ceiling for both series. Scaled independently they would lie about
- -- their relative size, which is the entire reason to draw them together.
- local peak = 0
- for _, v in ipairs(rx_hist) do if v > peak then peak = v end end
- for _, v in ipairs(tx_hist) do if v > peak then peak = v end end
-
- card.plot(cr, inner.x, chart_top, inner.w, chart_h, {
- { values = rx_hist, colour = colors.ok },
- { values = tx_hist, colour = colors.highlight },
- }, peak, colors)
-
- -- The peak, so a full-height line means something in absolute terms.
- card.font(cr, card.FONT_MONO, row_size * 0.85, false)
- card.rgba(cr, colors.label)
- card.text(cr, inner.x, chart_top + row_size * 0.85, rate_str(peak))
- end
-
- -- The live rates, each in its series colour so the line and the number are
- -- unmistakably the same thing.
- local ry = inner.y + inner.h - row_size * 0.4
- card.font(cr, card.FONT_MONO, row_size, false)
- card.rgba(cr, colors.ok)
- card.text(cr, inner.x, ry, '\u{F01DA} ' .. rate_str(down))
- card.rgba(cr, colors.highlight)
- card.text_right(cr, inner.x + inner.w, ry, '\u{F0552} ' .. rate_str(up))
-end
-
-return M