From 179da2ac05ed1f3f73db66c9b68d29768efbc1c3 Mon Sep 17 00:00:00 2001 From: Donald Cheng Hong Zou Date: Wed, 6 Apr 2022 20:59:23 -0400 Subject: [PATCH] Finished peer data usage chart --- src/api.py | 25 + src/dashboard.py | 37 +- src/static/css/dashboard.css | 35 +- src/static/js/configuration.js | 1101 ++++------------------ src/static/js/configurationTool.js | 880 +++++++++++++++++ src/static/js/configurationsTools.js | 0 src/static/js/configurationsTools.min.js | 0 src/templates/configuration.html | 43 +- 8 files changed, 1190 insertions(+), 931 deletions(-) create mode 100644 src/static/js/configurationTool.js delete mode 100644 src/static/js/configurationsTools.js delete mode 100644 src/static/js/configurationsTools.min.js diff --git a/src/api.py b/src/api.py index 1ab4493..0acc8d1 100644 --- a/src/api.py +++ b/src/api.py @@ -1,4 +1,6 @@ import ipaddress, subprocess, datetime, os, util + +from flask import jsonify from util import * notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."} @@ -41,6 +43,29 @@ def togglePeerAccess(data, g): return {"status": False, "reason": str(exc.output.strip())} return good +class managePeer: + def getPeerDataUsage(self, data, cur): + interval = { + "30min": (60 * 30) / 30, + "1h": (60 * 60) / 30, + "6h": (60 * 60 * 6) / 30, + "24h": (60 * 60 * 24) / 30, + "all": "" + } + if data['interval'] not in interval.keys(): + return {"status": False, "reason": "Invalid interval."} + intv = "" + if data['interval'] != "all": + intv = f" LIMIT {int(interval[data['interval']])}" + timeData = cur.execute(f"SELECT total_receive, total_sent, time FROM wg0_transfer WHERE id='{data['peerID']}' ORDER BY time DESC{intv};") + chartData = [] + for i in timeData: + chartData.append({ + "total_receive": i[0], + "total_sent": i[1], + "time": i[2] + }) + return {"status": True, "reason": "", "data": chartData} class addConfiguration: def AddressCheck(self, data): diff --git a/src/dashboard.py b/src/dashboard.py index 8fcfd6b..0f6f6ac 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -1569,6 +1569,16 @@ def switch_display_mode(mode): # APIs import api +@app.route('/api/getPeerDataUsage', methods=['POST']) +def getPeerDataUsage(): + data = request.get_json() + returnData = {"status": True, "reason": ""} + required = ['peerID', 'config', 'interval'] + if checkJSONAllParameter(required, data): + returnData = api.managePeer.getPeerDataUsage(api.managePeer, data, g.cur) + else: + return jsonify(api.notEnoughParameter) + return jsonify(returnData) @app.route('/api/togglePeerAccess', methods=['POST']) def togglePeerAccess(): @@ -1751,7 +1761,7 @@ def goodbye(): global bgThread stop_thread = True - print("Exiting Python Script!") + print("Stopping background thread") def get_all_transfer_thread(): print("waiting 15 sec ") @@ -1762,8 +1772,9 @@ def get_all_transfer_thread(): db = connect_db() cur = db.cursor() while True: - if stop_thread: - break + print(stop_thread) + # if stop_thread: + # break conf = [] for i in os.listdir(WG_CONF_PATH): if regex_match("^(.{1,}).(conf)$", i): @@ -1809,10 +1820,6 @@ def get_all_transfer_thread(): conf.append(temp) if len(conf) > 0: conf = sorted(conf, key=itemgetter('conf')) - - - print("adding...........") - # l = get_conf_list() for i in conf: print(i['conf']) config_name = i['conf'] @@ -1833,15 +1840,12 @@ def get_all_transfer_thread(): total_receive = cur_i[0][0] cur_total_sent = round(int(data_usage[i][2]) / (1024 ** 3), 4) cur_total_receive = round(int(data_usage[i][1]) / (1024 ** 3), 4) - # if cur_i[0][4] == "running": cumulative_receive = cur_i[0][2] + total_receive cumulative_sent = cur_i[0][3] + total_sent if total_sent <= cur_total_sent and total_receive <= cur_total_receive: total_sent = cur_total_sent total_receive = cur_total_receive else: - # cumulative_receive = cur_i[0][2] + total_receive - # cumulative_sent = cur_i[0][3] + total_sent cur.execute("UPDATE %s SET cumu_receive = %f, cumu_sent = %f, cumu_data = %f WHERE id = '%s'" % (config_name, round(cumulative_receive, 4), round(cumulative_sent, 4), round(cumulative_sent + cumulative_receive, 4), data_usage[i][0])) @@ -1857,11 +1861,10 @@ def get_all_transfer_thread(): VALUES ('{data_usage[i][0]}', {round(total_receive, 4)}, {round(total_sent, 4)}, {round(total_receive + total_sent, 4)},{round(cumulative_receive, 4)}, {round(cumulative_sent, 4)}, {round(cumulative_sent + cumulative_receive, 4)}, '{now_string}') ''') - # get_transfer(i['conf']) db.commit() except subprocess.CalledProcessError: - print(i['conf'] + " stopped") - time.sleep(15) + pass + time.sleep(30) except KeyboardInterrupt: return True """ @@ -1973,8 +1976,6 @@ def run_dashboard(): """ Get host and port for web-server """ - - def get_host_bind(): init_dashboard() config = configparser.ConfigParser(strict=False) @@ -1983,7 +1984,6 @@ def get_host_bind(): app_port = config.get("Server", "app_port") return app_ip, app_port - if __name__ == "__main__": init_dashboard() UPDATE = check_update() @@ -1998,7 +1998,8 @@ if __name__ == "__main__": global bgThread global stop_thread stop_thread = False - bgThread = threading.Thread(target=get_all_transfer_thread) + bgThread.daemon = True bgThread.start() - app.run(host=app_ip, debug=False, port=app_port) + + app.run(host=app_ip, debug=False, port=app_port) \ No newline at end of file diff --git a/src/static/css/dashboard.css b/src/static/css/dashboard.css index 9341d27..7bb61b5 100644 --- a/src/static/css/dashboard.css +++ b/src/static/css/dashboard.css @@ -169,7 +169,8 @@ body { .btn-control { border: none !important; - padding: 0 1rem 0 0; + padding: 0; + margin: 0 1rem 0 0; } .btn-control:active, @@ -221,10 +222,14 @@ body { color: #6c757d } -.btn-setting-peer:hover { +.btn-control.btn-outline-primary:hover{ color: #007bff } +/* .btn-setting-peer:hover { + color: #007bff +} */ + .btn-download-peer:hover { color: #17a2b8; } @@ -799,4 +804,28 @@ pre.index-alert { /*.conf_card .card-body .row .card-col{*/ /* margin-bottom: 0.5rem;*/ -/*}*/ \ No newline at end of file +/*}*/ + +.peerDataUsageChartContainer{ + min-height: 50vh; + width: 100%; +} + +.peerDataUsageChartControl{ + display: block !important; + margin: 0; +} + +.peerDataUsageChartControl .switchUnit{ + width: 33.3%; +} + +.peerDataUsageChartControl .switchTimePeriod{ + width: 25%; +} + +@media (min-width: 1200px){ + #peerDataUsage .modal-xl { + max-width: 95vw; + } +} diff --git a/src/static/js/configuration.js b/src/static/js/configuration.js index 4c60d70..7854fe9 100644 --- a/src/static/js/configuration.js +++ b/src/static/js/configuration.js @@ -4,10 +4,10 @@ */ let peers = []; -(function() { +(function () { /** * Definitions - */ + */ let configuration_name; let configuration_interval; let configuration_timeout = window.localStorage.getItem("configurationTimeout"); @@ -37,6 +37,7 @@ let peers = []; let settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), bootstrapModalConfig); let deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), bootstrapModalConfig); let configurationDeleteModal = new bootstrap.Modal(document.getElementById('configuration_delete_modal'), bootstrapModalConfig); + let peerDataUsageModal = new bootstrap.Modal(document.getElementById('peerDataUsage'), bootstrapModalConfig); $("[data-toggle='tooltip']").tooltip(); $("[data-toggle='popover']").popover(); @@ -62,21 +63,27 @@ let peers = []; data: { labels: [], datasets: [{ - label: 'Data Sent', - data: [], - stroke: '#FFFFFF', - borderColor: '#28a745', - tension: 0.1, - borderWidth: 2 - }, - { - label: 'Data Received', - data: [], - stroke: '#FFFFFF', - borderColor: '#007bff', - tension: 0.1, - borderWidth: 2 - } + label: 'Data Sent', + data: [], + stroke: '#FFFFFF', + borderColor: '#28a745', + backgroundColor: '#28a7452b', + pointRadius: 1, + fill: {target: 'origin'}, + tension: 0, + borderWidth: 1 + }, + { + label: 'Data Received', + data: [], + stroke: '#FFFFFF', + borderColor: '#007bff', + backgroundColor: '#007bff2b', + pointRadius: 1, + fill: {target: 'origin'}, + tension: 0, + borderWidth: 1 + } ] }, options: { @@ -88,7 +95,7 @@ let peers = []; min: 0, ticks: { min: 0, - callback: function(value, index, ticks) { + callback: function (value, index, ticks) { return `${value} ${chartUnit}`; } } @@ -97,7 +104,7 @@ let peers = []; plugins: { tooltip: { callbacks: { - label: function(context) { + label: function (context) { return `${context.dataset.label}: ${context.parsed.y} ${chartUnit}`; } } @@ -110,11 +117,11 @@ let peers = []; $totalDataUsageChartObj.css("width", "100%"); totalDataUsageChartObj.width = $totalDataUsageChartObj.parent().width(); totalDataUsageChartObj.resize(); - $(window).on("resize", function() { + $(window).on("resize", function () { totalDataUsageChartObj.resize(); }); - $(".fullScreen").on("click", function() { + $(".fullScreen").on("click", function () { let $chartContainer = $(".chartContainer"); if ($chartContainer.hasClass("fullScreen")) { $(this).children().removeClass("bi-fullscreen-exit").addClass("bi-fullscreen"); @@ -127,9 +134,9 @@ let peers = []; }); let mul = 1; - $(".switchUnit").on("click", function() { + $(".switchUnit").on("click", function () { $(".switchUnit").removeClass("active"); - $(this).addClass("active"); + $(`.switchUnit[data-unit=${$(this).data('unit')}]`).addClass("active"); if ($(this).data('unit') !== chartUnit) { switch ($(this).data('unit')) { case "GB": @@ -164,9 +171,99 @@ let peers = []; totalDataUsageChartObj.data.datasets[0].data = totalDataUsageChartObj.data.datasets[0].data.map(x => x * mul); totalDataUsageChartObj.data.datasets[1].data = totalDataUsageChartObj.data.datasets[1].data.map(x => x * mul); totalDataUsageChartObj.update(); + + peerDataUsageChartObj.data.datasets[0].data = peerDataUsageChartObj.data.datasets[0].data.map(x => x * mul); + peerDataUsageChartObj.data.datasets[1].data = peerDataUsageChartObj.data.datasets[1].data.map(x => x * mul); + peerDataUsageChartObj.update(); } }); + /** + * Peer Chart + * @param {Any} response + */ + let peerTimePeriod = window.localStorage.peerTimePeriod; + let peerTimePeriodAvailable = ["30min", "1h", "6h", "24h", "all"]; + + if (peerTimePeriod === null || !peerTimePeriodAvailable.includes(peerTimePeriod)) { + window.localStorage.setItem("peerTimePeriod", "30min"); + $('.switchTimePeriod[data-time="30min"]').addClass("active"); + } else { + $(`.switchTimePeriod[data-time="${peerTimePeriod}"]`).addClass("active"); + } + peerTimePeriod = window.localStorage.getItem("peerTimePeriod"); + + + const peerDataUsageChart = document.getElementById('peerDataUsageChartObj').getContext('2d'); + const peerDataUsageChartObj = new Chart(peerDataUsageChart, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Data Sent', + data: [], + stroke: '#FFFFFF', + borderColor: '#28a745', + backgroundColor: '#28a7452b', + pointRadius: 0, + fill: {target: 'origin'}, + tension: 0, + borderWidth: 1 + }, + { + label: 'Data Received', + data: [], + stroke: '#FFFFFF', + borderColor: '#007bff', + backgroundColor: '#007bff2b', + pointRadius: 0, + fill: {target: 'origin'}, + tension: 0, + borderWidth: 1 + } + ] + }, + options: { + interaction: { + mode: 'nearest' + }, + // showLine: false, + maintainAspectRatio: false, + showScale: false, + responsive: false, + scales: { + y: { + min: 0, + ticks: { + min: 0, + callback: function (value, index, ticks) { + return `${value} ${chartUnit}`; + } + } + }, + x: { + display: false + } + }, + plugins: { + tooltip: { + callbacks: { + label: function (context) { + return `${context.dataset.label}: ${context.parsed.y} ${chartUnit}`; + } + } + } + } + } + }); + + let $peerDataUsageChartObj = $("#peerDataUsageChartObj"); + $peerDataUsageChartObj.css("width", "100%"); + peerDataUsageChartObj.width = $peerDataUsageChartObj.parent().width(); + peerDataUsageChartObj.resize(); + $(window).on("resize", function () { + peerDataUsageChartObj.resize(); + }); /** * To show alert on the configuration page @@ -197,7 +294,7 @@ let peers = []; } let firstLoading = true; - $(".nav-conf-link").on("click", function(e) { + $(".nav-conf-link").on("click", function (e) { e.preventDefault(); if (configuration_name !== $(this).data("conf-id")) { firstLoading = true; @@ -225,7 +322,7 @@ let peers = []; if (response.checked === "checked") { $conf_status_btn.prop("checked", true) - }else{ + } else { $conf_status_btn.prop("checked", false) } $conf_status_btn.data("conf-id", configuration_name) @@ -281,8 +378,8 @@ let peers = []; document.querySelector("#conf_address").innerHTML = response.conf_address; let delay = 0; let h6 = $(".info h6"); - for (let i = 0; i < h6.length; i++){ - setTimeout(function(){ + for (let i = 0; i < h6.length; i++) { + setTimeout(function () { $(h6[i]).removeClass("info_loading"); }, delay) delay += 40 @@ -298,13 +395,13 @@ let peers = []; document.querySelector(".peer_list").innerHTML = `

Oops! No peers found ‘︿’

`; } else { let mode = display_mode === "list" ? "col-12" : "col-sm-6 col-lg-4"; - response.peer_data.forEach(function(peer) { + response.peer_data.forEach(function (peer) { let total_r = 0; let total_s = 0; total_r += peer.cumu_receive; total_s += peer.cumu_sent; - - + + let spliter = '
'; let peer_name = `
@@ -322,7 +419,7 @@ let peers = []; ${roundN(peer.total_sent + total_s, 4)} GB

`; - let peer_key = + let peer_key = `
PEER @@ -337,12 +434,12 @@ let peers = [];
${peer.allowed_ip}
`; - let peer_latest_handshake = + let peer_latest_handshake = `
LATEST HANDSHAKE
${peer.latest_handshake}
`; - let peer_endpoint = + let peer_endpoint = `
END POINT
${peer.endpoint}
@@ -354,14 +451,18 @@ let peers = []; + + `; if (peer.private_key !== "") { - peer_control += + peer_control += ``; } peer_control += '
'; - let html = + let html = `
` + - peer_name + - spliter + - peer_transfer + - peer_key + - peer_allowed_ip + - peer_latest_handshake + - spliter + - peer_endpoint + - spliter + - peer_control + + peer_name + + spliter + + peer_transfer + + peer_key + + peer_allowed_ip + + peer_latest_handshake + + spliter + + peer_endpoint + + spliter + + peer_control + `
`; result += html; }); - response.lock_access_peers.forEach(function(peer) { + response.lock_access_peers.forEach(function (peer) { let total_r = 0; let total_s = 0; total_r += peer.cumu_receive; @@ -408,24 +509,24 @@ let peers = []; ${roundN(peer.total_sent + total_s, 4)} GB

`; - let peer_key = + let peer_key = `
PEERCLICK TO COPY
${peer.id}/samp>
`; - let peer_allowed_ip = + let peer_allowed_ip = `
ALLOWED IP
${peer.allowed_ip}
`; - let peer_latest_handshake = + let peer_latest_handshake = `
LATEST HANDSHAKE
${peer.latest_handshake}
`; - let peer_endpoint = + let peer_endpoint = `
END POINT
${peer.endpoint}
@@ -474,9 +575,9 @@ let peers = []; $add_peer.setAttribute("disabled", "disabled"); $add_peer.innerHTML = `Adding ${$new_add_amount.val()} peers...`; let $new_add_DNS = $("#new_add_DNS"); - $new_add_DNS.val(window.configurations.cleanIp($new_add_DNS.val())); + $new_add_DNS.val(configurations.cleanIp($new_add_DNS.val())); let $new_add_endpoint_allowed_ip = $("#new_add_endpoint_allowed_ip"); - $new_add_endpoint_allowed_ip.val(window.configurations.cleanIp($new_add_endpoint_allowed_ip.val())); + $new_add_endpoint_allowed_ip.val(configurations.cleanIp($new_add_endpoint_allowed_ip.val())); let $new_add_MTU = $("#new_add_MTU"); let $new_add_keep_alive = $("#new_add_keep_alive"); let $enable_preshare_key = $("#enable_preshare_key"); @@ -503,20 +604,20 @@ let peers = []; "keys": keys, "amount": $new_add_amount.val() }), - success: function(response) { + success: function (response) { if (response !== "true") { $("#add_peer_alert").html(response).removeClass("d-none"); data_list.forEach((ele) => ele.removeAttr("disabled")); $add_peer.removeAttribute("disabled"); $add_peer.innerHTML = "Save"; } else { - window.configurations.loadPeers(""); + configurations.loadPeers(""); data_list.forEach((ele) => ele.removeAttr("disabled")); $("#add_peer_form").trigger("reset"); $add_peer.removeAttribute("disabled"); $add_peer.innerHTML = "Save"; - window.configurations.showToast($new_add_amount.val() + " peers added successful!"); - window.configurations.addModal().toggle(); + configurations.showToast($new_add_amount.val() + " peers added successful!"); + configurations.addModal().toggle(); } } }); @@ -544,31 +645,31 @@ let peers = []; "Content-Type": "application/json" }, data: JSON.stringify({ "action": "delete", "peer_ids": peer_ids }), - success: function(response) { + success: function (response) { if (response !== "true") { - if (window.configurations.deleteModal()._isShown) { + if (configurations.deleteModal()._isShown) { $("#remove_peer_alert").html(response + $("#add_peer_alert").html()) .removeClass("d-none"); $("#delete_peer").removeAttr("disabled").html("Delete"); } - if (window.configurations.deleteBulkModal()._isShown) { + if (configurations.deleteBulkModal()._isShown) { let $bulk_remove_peer_alert = $("#bulk_remove_peer_alert"); $bulk_remove_peer_alert.html(response + $bulk_remove_peer_alert.html()) .removeClass("d-none"); $("#confirm_delete_bulk_peers").removeAttr("disabled").html("Delete"); } } else { - if (window.configurations.deleteModal()._isShown) { - window.configurations.deleteModal().toggle(); + if (configurations.deleteModal()._isShown) { + configurations.deleteModal().toggle(); } - if (window.configurations.deleteBulkModal()._isShown) { + if (configurations.deleteBulkModal()._isShown) { $("#confirm_delete_bulk_peers").removeAttr("disabled").html("Delete"); $("#selected_peer_list").html(''); $(".delete-bulk-peer-item.active").removeClass('active'); - window.configurations.deleteBulkModal().toggle(); + configurations.deleteBulkModal().toggle(); } - window.configurations.loadPeers($('#search_peer_textbox').val()); - window.configurations.showToast(`Deleted ${peer_ids.length} peers`) + configurations.loadPeers($('#search_peer_textbox').val()); + configurations.showToast(`Deleted ${peer_ids.length} peers`) $("#delete_peer").removeAttr("disabled").html("Delete"); } } @@ -580,7 +681,7 @@ let peers = []; */ function noResponding(message = "Opps!
I can't connect to the server.") { document.querySelectorAll(".no-response").forEach(ele => ele.classList.add("active")); - setTimeout(function() { + setTimeout(function () { document.querySelectorAll(".no-response").forEach(ele => ele.classList.add("show")); document.querySelector("#right_body").classList.add("no-responding"); document.querySelector(".navbar").classList.add("no-responding"); @@ -595,7 +696,7 @@ let peers = []; document.querySelectorAll(".no-response").forEach(ele => ele.classList.remove("show")); document.querySelector("#right_body").classList.remove("no-responding"); document.querySelector(".navbar").classList.remove("no-responding"); - setTimeout(function() { + setTimeout(function () { document.querySelectorAll(".no-response").forEach(ele => ele.classList.remove("active")); }, 1010); } @@ -604,7 +705,7 @@ let peers = []; * Set configuration refresh Interval */ function setConfigurationInterval() { - configuration_interval = setInterval(function() { + configuration_interval = setInterval(function () { loadPeers($('#search_peer_textbox').val()); }, configuration_timeout); } @@ -626,7 +727,7 @@ let peers = []; .css("background", "linear-gradient(145deg, rgba(255,69,69,1) 0%, rgba(0,115,186,1) 100%)") .css("width", "25%"); - setTimeout(function() { + setTimeout(function () { stillLoadingProgressBar(); }, 300); } @@ -643,7 +744,7 @@ let peers = []; */ function endProgressBar() { $progress_bar.css("transition", "0.3s ease-in-out").css("width", "100%"); - setTimeout(function() { + setTimeout(function () { $progress_bar.css("opacity", "0"); }, 250); } @@ -674,10 +775,10 @@ let peers = []; method: "GET", url: `/get_config/${configuration_name}?search=${encodeURIComponent(searchString)}`, headers: { "Content-Type": "application/json" } - }).done(function(response) { + }).done(function (response) { console.log(response); parsePeers(response); - }).fail(function() { + }).fail(function () { noResponding(); good = false; }); @@ -691,14 +792,14 @@ let peers = []; let seconds = (d2 - d1); time += seconds; count += 1; - window.console.log(`Average time: ${time/count}ms`); + window.console.log(`Average time: ${time / count}ms`); $("#peer_loading_time").html(`Peer Loading Time: ${seconds}ms`); removeNoResponding(); peers = response.data.peer_data; configurationAlert(response.data); configurationHeader(response.data); configurationPeers(response.data); - + $(".dot.dot-running").attr("title", "Peer Connected").tooltip(); $(".dot.dot-stopped").attr("title", "Peer Disconnected").tooltip(); $("i[data-toggle='tooltip']").tooltip(); @@ -713,20 +814,20 @@ let peers = []; } } - function removeAllTooltips(){ + function removeAllTooltips() { $(".tooltip").remove(); } - function toggleAccess(peerID){ + function toggleAccess(peerID) { $.ajax({ url: "/api/togglePeerAccess", method: "POST", - headers: {"Content-Type": "application/json"}, - data: JSON.stringify({"peerID": peerID, "config": configuration_name}) - }).done(function(res){ - if(res.status){ + headers: { "Content-Type": "application/json" }, + data: JSON.stringify({ "peerID": peerID, "config": configuration_name }) + }).done(function (res) { + if (res.status) { loadPeers($('#search_peer_textbox').val()); - }else{ + } else { showToast(res.reason); } }); @@ -751,7 +852,7 @@ let peers = []; let numberToast = 0; function showToast(msg) { $(".toastContainer").append( - `
- +
Delete Peers @@ -154,6 +154,46 @@
+