diff options
6 files changed, 356 insertions, 0 deletions
diff --git a/applications/luci-app-vnstat2/Makefile b/applications/luci-app-vnstat2/Makefile new file mode 100644 index 0000000000..420bf548a4 --- /dev/null +++ b/applications/luci-app-vnstat2/Makefile @@ -0,0 +1,13 @@ +# This is free software, licensed under the Apache License, Version 2.0 + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI Support for vnStat 2 +LUCI_DEPENDS:=+luci-lib-jsonc +vnstat2 +vnstati2 + +PKG_LICENSE:=Apache-2.0 +PKG_MAINTAINER:=Jan Hoffmann <jan@3e8.eu> + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js b/applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js new file mode 100644 index 0000000000..0b01239799 --- /dev/null +++ b/applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js @@ -0,0 +1,109 @@ +// This is free software, licensed under the Apache License, Version 2.0 + +'use strict'; +'require fs'; +'require ui'; +'require uci'; +'require form'; +'require tools.widgets as widgets'; + +return L.view.extend({ + handleDeleteModal: function(m, iface, ev) { + L.showModal(_('Delete interface <em>%h</em>').format(iface), [ + E('p', _('The interface will be removed from the database permanently. This cannot be undone.')), + E('div', { 'class': 'right' }, [ + E('div', { + 'class': 'btn', + 'click': L.hideModal + }, _('Cancel')), + ' ', + E('div', { + 'class': 'btn cbi-button-negative', + 'click': ui.createHandlerFn(this, 'handleDelete', m, iface) + }, _('Delete')) + ]) + ]); + }, + + handleDelete: function(m, iface, ev) { + return fs.exec('/usr/bin/vnstat', ['--remove', '-i', iface, '--force']) + .then(L.bind(m.render, m)) + .catch(function(e) { + ui.addNotification(null, E('p', e.message)); + }) + .finally(L.hideModal); + }, + + render: function() { + var m, s, o; + + m = new form.Map('vnstat', _('vnStat'), _('vnStat is a network traffic monitor for Linux that keeps a log of network traffic for the selected interface(s).')); + + s = m.section(form.TypedSection, 'vnstat', _('Interfaces')); + s.anonymous = true; + s.addremove = false; + + o = s.option(widgets.DeviceSelect, 'interface', _('Monitor interfaces'), _('The selected interfaces are automatically added to the vnStat database upon startup.')); + o.rmempty = true; + o.multiple = true; + o.noaliases = true; + o.nobridges = false; + o.noinactive = false; + o.nocreate = false; + + + o = s.option(form.DummyValue, '_database'); + + o.load = function(section_id) { + return fs.exec('/usr/bin/vnstat', ['--json', 'f', '1']).then(L.bind(function(result) { + var databaseInterfaces = []; + if (result.code == 0) { + var vnstatData = JSON.parse(result.stdout); + for (var i = 0; i < vnstatData.interfaces.length; i++) { + databaseInterfaces.push(vnstatData.interfaces[i].name); + } + } + + var configInterfaces = uci.get_first('vnstat', 'vnstat', 'interface') || []; + + this.interfaces = databaseInterfaces.filter(function(iface) { + return configInterfaces.indexOf(iface) == -1; + }); + }, this)); + }; + + o.render = L.bind(function(view, section_id) { + var table = E('div', { 'class': 'table' }, [ + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th' }, _('Interface')), + E('div', { 'class': 'th right' }, _('Delete')) + ]) + ]); + + var rows = []; + + for (var i = 0; i < this.interfaces.length; i++) { + rows.push([ + this.interfaces[i], + E('button', { + 'class': 'btn cbi-button-remove', + 'click': ui.createHandlerFn(view, 'handleDeleteModal', m, this.interfaces[i]) + }, [ _('Delete…') ]) + ]); + } + + cbi_update_table(table, rows, E('em', _('No unconfigured interfaces found in database.'))); + + return E([], [ + E('h3', _('Unconfigured interfaces')), + E('div', { 'class': 'cbi-section-descr' }, + _('These interfaces are present in the vnStat database, but are not configured above.')), + table + ]); + }, o, this); + + + return m.render(); + } +}); + diff --git a/applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua b/applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua new file mode 100644 index 0000000000..139c1f4991 --- /dev/null +++ b/applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua @@ -0,0 +1,50 @@ +module("luci.controller.vnstat2", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/vnstat") then + return + end + + entry({"admin", "status", "vnstat2"}, alias("admin", "status", "vnstat2", "graphs"), _("vnStat Traffic Monitor"), 90) + entry({"admin", "status", "vnstat2", "graphs"}, template("vnstat2/graphs"), _("Graphs"), 1) + entry({"admin", "status", "vnstat2", "config"}, view("vnstat2/config"), _("Configuration"), 2) + entry({"admin", "status", "vnstat2", "graph"}, call("action_graph"), nil, 3) +end + +function action_graph() + local util = require "luci.util" + + local param = luci.http.formvalue + + local iface = param("iface") + local style = param("style") + + if not iface or not style then + luci.http.status(404, "Not Found") + return + end + + local style_valid = false + for _, v in ipairs({"s", "t", "5", "h", "d", "m", "y"}) do + if v == style then + style_valid = true + break + end + end + + if not style_valid then + luci.http.status(404, "Not Found") + return + end + + luci.http.prepare_content("image/png") + + local cmd = "vnstati -i %s -%s -o -" % { + util.shellquote(iface), + util.shellquote(style) + } + + local image = io.popen(cmd) + luci.http.write(image:read("*a")) + image:close() +end diff --git a/applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm b/applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm new file mode 100644 index 0000000000..318611a9d6 --- /dev/null +++ b/applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm @@ -0,0 +1,55 @@ +<%# + This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%- + +local util = require "luci.util" +local json = require "luci.jsonc" + + +local ifaces = {} + +local data = util.exec("vnstat --json f 1 2>/dev/null") +local content = json.parse(data) +if type(content) == "table" then + for _, iface in pairs(content["interfaces"]) do + table.insert(ifaces, iface["name"]) + end +end + + +local function render_section(style, title) + %><div class="cbi-section" data-tab="<%=style%>" data-tab-title="<%=title%>"><% + + for _, iface in ipairs(ifaces) do + %><p><img src="<%=url("admin/status/vnstat2/graph")%>?iface=<%=iface%>&style=<%=style%>" alt="" style="max-width:100%" /></p><% + end + + %></div><% +end + + +-%> + +<%+header%> + +<h2 name="content"><%:vnStat Graphs%></h2> + +<div> + <% + if #ifaces == 0 then + %><p><em><%:No monitored interfaces have been found. Go to the configuration to enable monitoring for one or more interfaces.%></em></p><% + else + render_section("s", translate("Summary")) + render_section("t", translate("Top")) + render_section("5", translate("5 Minute")) + render_section("h", translate("Hourly")) + render_section("d", translate("Daily")) + render_section("m", translate("Monthly")) + render_section("y", translate("Yearly")) + end + %> +</div> + +<%+footer%> diff --git a/applications/luci-app-vnstat2/po/templates/vnstat2.pot b/applications/luci-app-vnstat2/po/templates/vnstat2.pot new file mode 100644 index 0000000000..f178b9e451 --- /dev/null +++ b/applications/luci-app-vnstat2/po/templates/vnstat2.pot @@ -0,0 +1,117 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:46 +msgid "5 Minute" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:18 +msgid "Cancel" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua:10 +msgid "Configuration" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:48 +msgid "Daily" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:23 +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:80 +msgid "Delete" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:12 +msgid "Delete interface <em>%h</em>" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:92 +msgid "Delete…" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua:9 +msgid "Graphs" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:47 +msgid "Hourly" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:79 +msgid "Interface" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:43 +msgid "Interfaces" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:47 +msgid "Monitor interfaces" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:49 +msgid "Monthly" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:42 +msgid "" +"No monitored interfaces have been found. Go to the configuration to enable " +"monitoring for one or more interfaces." +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:96 +msgid "No unconfigured interfaces found in database." +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:44 +msgid "Summary" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:13 +msgid "" +"The interface will be removed from the database permanently. This cannot be " +"undone." +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:47 +msgid "" +"The selected interfaces are automatically added to the vnStat database upon " +"startup." +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:101 +msgid "" +"These interfaces are present in the vnStat database, but are not configured " +"above." +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:45 +msgid "Top" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:99 +msgid "Unconfigured interfaces" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:50 +msgid "Yearly" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:41 +msgid "vnStat" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/view/vnstat2/graphs.htm:37 +msgid "vnStat Graphs" +msgstr "" + +#: applications/luci-app-vnstat2/luasrc/controller/vnstat2.lua:8 +msgid "vnStat Traffic Monitor" +msgstr "" + +#: applications/luci-app-vnstat2/htdocs/luci-static/resources/view/vnstat2/config.js:41 +msgid "" +"vnStat is a network traffic monitor for Linux that keeps a log of network " +"traffic for the selected interface(s)." +msgstr "" diff --git a/applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json b/applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json new file mode 100644 index 0000000000..58a2aa50c6 --- /dev/null +++ b/applications/luci-app-vnstat2/root/usr/share/rpcd/acl.d/luci-app-vnstat2.json @@ -0,0 +1,12 @@ +{ + "luci-app-vnstat2": { + "description": "Grant access to LuCI app vnstat2", + "write": { + "file": { + "/usr/bin/vnstat": [ "exec" ] + }, + "uci": [ "vnstat" ] + } + } +} + |