aboutsummaryrefslogtreecommitdiff
path: root/ifstat.lua
blob: b01b2cdf0cc87ce6ca5948ce1aa44d91b3e681fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env luajit

require "ubus"
require "uloop"

local filter_prev_value = {}
local printed_lines_count = 0

function replace_char(str, pos, r)
  return str:sub(1, pos-1) .. r .. str:sub(pos+1)
end

function print_line(line)
  io.stdout:write("\27[K")
  print(line)
  printed_lines_count = printed_lines_count + 1
end

function clear_screen()
  if printed_lines_count > 0 then
    io.stdout:write("\27[" .. tostring( printed_lines_count ) .. "A")
    printed_lines_count = 0
  end
end

function fit_value_in_column(value, width)
  local value_str = string.format("%d", value)
  if #value_str > width then
    return string.format("%." .. tostring(width-6) .."e ", value)
  else
    return string.format("%" .. tostring(width) .."s ", value_str)
  end
end

function print_ifstat_data(data)
  local filter_stat = {}
  local filter_data_columns = {
    {key="filter_num",     title="#",         width=1},
    {key="pkts_64",        title="<= 64",     width=7},
    {key="pkts_65_127",    title="65-127",    width=7},
    {key="pkts_128_255",   title="128-255",   width=7},
    {key="pkts_256_511",   title="256-511",   width=7},
    {key="pkts_512_1023",  title="512-1023",  width=8},
    {key="pkts_1024_1512", title="1024-1512", width=8},
    {key="pkts_1513",      title=">= 1513",   width=7},
    {key="pkts_bytes",     title="Bytes",     width=10},
    {key="pkts_cnt",       title="Packets",   width=8}
  }

  for filter_name, filter_data in pairs(data) do
    local filter_num = filter_name:gsub("filter","")

    -- В Lua массивы индексируются с единицы, а приходящие от демона
    -- фильтры индексируются с 0
    filter_num = tonumber(filter_num) + 1

    if filter_prev_value[filter_num] == nil then
      filter_prev_value[filter_num] = {}
    end

    -- Отображать в таблице нужно настоящие индексы фильтров, а не
    -- увеличенные на 1
    filter_data["filter_num"] = filter_num - 1
    filter_stat[filter_num] = { absolute = '', relative = '' }

    for idx, column in ipairs(filter_data_columns) do
      local value = tonumber(filter_data[column.key])
      local delta = value - (filter_prev_value[filter_num][column.key] or 0)

      filter_prev_value[filter_num][column.key] = value
      filter_stat[filter_num].absolute = filter_stat[filter_num].absolute .. fit_value_in_column(value, column.width)
      filter_stat[filter_num].relative = filter_stat[filter_num].relative .. fit_value_in_column(delta, column.width)

      if column.key == 'filter_num' then
        filter_stat[filter_num].relative = string.format("%" .. column.width+1 .. "s ", 'Δ')
      end
    end
  end

  clear_screen()

  local header = ''
  for idx, column in ipairs(filter_data_columns) do
    local title = string.format("%" .. tostring(column.width) .. "s ", column.title)
    title = replace_char(title:sub(1, column.width), column.width+1, ' ')
    header = header .. title
  end
  header = header:sub(1, #header-1)

  local frame = ''
  for i=1,#header do
    frame = frame .. '-'
  end
  print_line(frame)
  print_line(header)
  print_line(frame)

  for idx, stat in ipairs(filter_stat) do
    print_line(stat.absolute)
    print_line(stat.relative)
    print_line(frame)
  end
end

function main()
  uloop.init()

  local conn = ubus.connect(os.getenv("UBUS_SOCK"))
  if not conn then
    error("Failed to connect to ubus")
  end

  local sub = {
    notify = function( msg, name )
      print_ifstat_data(msg)
    end,
  }

  conn:subscribe("ifstat", sub)
  uloop.run()
end

main()