mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-07-08 14:17:00 +00:00
Finished some building blocks on the new version
This commit is contained in:
parent
1e88491ca1
commit
ed3bb6429b
@ -344,7 +344,7 @@ def get_all_peers_data(config_name):
|
|||||||
"total_data": 0,
|
"total_data": 0,
|
||||||
"endpoint": "N/A",
|
"endpoint": "N/A",
|
||||||
"status": "stopped",
|
"status": "stopped",
|
||||||
"latest_handshake": "N/A",
|
"latest_handshake": "No Handshake",
|
||||||
"allowed_ip": "N/A",
|
"allowed_ip": "N/A",
|
||||||
"cumu_receive": 0,
|
"cumu_receive": 0,
|
||||||
"cumu_sent": 0,
|
"cumu_sent": 0,
|
||||||
|
@ -27,6 +27,8 @@ import pyotp
|
|||||||
from flask import Flask, request, render_template, redirect, url_for, session, jsonify, g
|
from flask import Flask, request, render_template, redirect, url_for, session, jsonify, g
|
||||||
from flask.json.provider import JSONProvider
|
from flask.json.provider import JSONProvider
|
||||||
from flask_qrcode import QRcode
|
from flask_qrcode import QRcode
|
||||||
|
from json import JSONEncoder
|
||||||
|
|
||||||
from icmplib import ping, traceroute
|
from icmplib import ping, traceroute
|
||||||
|
|
||||||
# Import other python files
|
# Import other python files
|
||||||
@ -35,6 +37,7 @@ import threading
|
|||||||
from sqlalchemy.orm import mapped_column, declarative_base, Session
|
from sqlalchemy.orm import mapped_column, declarative_base, Session
|
||||||
from sqlalchemy import FLOAT, INT, VARCHAR, select, MetaData, DATETIME
|
from sqlalchemy import FLOAT, INT, VARCHAR, select, MetaData, DATETIME
|
||||||
from sqlalchemy import create_engine, inspect
|
from sqlalchemy import create_engine, inspect
|
||||||
|
from flask.json.provider import DefaultJSONProvider
|
||||||
|
|
||||||
DASHBOARD_VERSION = 'v3.1'
|
DASHBOARD_VERSION = 'v3.1'
|
||||||
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
|
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
|
||||||
@ -55,20 +58,31 @@ app.secret_key = secrets.token_urlsafe(32)
|
|||||||
# Enable QR Code Generator
|
# Enable QR Code Generator
|
||||||
QRcode(app)
|
QRcode(app)
|
||||||
|
|
||||||
|
|
||||||
|
class ModelEncoder(JSONEncoder):
|
||||||
|
def default(self, o: Any) -> Any:
|
||||||
|
if hasattr(o, 'toJson'):
|
||||||
|
return o.toJson()
|
||||||
|
else:
|
||||||
|
return super(ModelEncoder, self).default(o)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Classes
|
Classes
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
# Base = declarative_base(class_registry=dict())
|
# Base = declarative_base(class_registry=dict())
|
||||||
|
|
||||||
|
|
||||||
class CustomJsonEncoder(JSONProvider):
|
class CustomJsonEncoder(DefaultJSONProvider):
|
||||||
def dumps(self, obj, **kwargs):
|
def __init__(self, app):
|
||||||
if type(obj) == WireguardConfiguration:
|
super().__init__(app)
|
||||||
return obj.toJSON()
|
|
||||||
return json.dumps(obj)
|
|
||||||
|
|
||||||
def loads(self, obj, **kwargs):
|
def default(self, o):
|
||||||
return json.loads(obj, **kwargs)
|
if isinstance(o, WireguardConfiguration) or isinstance(o, Peer):
|
||||||
|
return o.toJson()
|
||||||
|
return super().default(self, o)
|
||||||
|
|
||||||
|
|
||||||
app.json = CustomJsonEncoder(app)
|
app.json = CustomJsonEncoder(app)
|
||||||
@ -100,11 +114,10 @@ class Peer:
|
|||||||
self.preshared_key = tableData["preshared_key"]
|
self.preshared_key = tableData["preshared_key"]
|
||||||
|
|
||||||
def toJson(self):
|
def toJson(self):
|
||||||
return json.dumps(self, default=lambda o: o.__dict__,
|
return self.__dict__
|
||||||
sort_keys=True, indent=4)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.toJson()
|
return str(self.toJson())
|
||||||
|
|
||||||
|
|
||||||
class WireguardConfiguration:
|
class WireguardConfiguration:
|
||||||
@ -178,7 +191,7 @@ class WireguardConfiguration:
|
|||||||
|
|
||||||
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1],
|
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1],
|
||||||
f"{self.Name}.conf"), "w+") as configFile:
|
f"{self.Name}.conf"), "w+") as configFile:
|
||||||
print(self.__parser.sections())
|
# print(self.__parser.sections())
|
||||||
self.__parser.write(configFile)
|
self.__parser.write(configFile)
|
||||||
|
|
||||||
self.Peers = []
|
self.Peers = []
|
||||||
@ -189,7 +202,7 @@ class WireguardConfiguration:
|
|||||||
|
|
||||||
def __createDatabase(self):
|
def __createDatabase(self):
|
||||||
existingTables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
|
existingTables = cursor.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
|
||||||
existingTables = itertools.chain(*existingTables)
|
existingTables = [t['name'] for t in existingTables]
|
||||||
if self.Name not in existingTables:
|
if self.Name not in existingTables:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
@ -221,18 +234,32 @@ class WireguardConfiguration:
|
|||||||
""" % self.Name
|
""" % self.Name
|
||||||
)
|
)
|
||||||
sqldb.commit()
|
sqldb.commit()
|
||||||
|
|
||||||
if f'{self.Name}_transfer' not in existingTables:
|
if f'{self.Name}_transfer' not in existingTables:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
CREATE TABLE %s_transfer (
|
CREATE TABLE %s_transfer (
|
||||||
id VARCHAR NOT NULL, total_receive FLOAT NULL,
|
id VARCHAR NOT NULL, total_receive FLOAT NULL,
|
||||||
total_sent FLOAT NULL, total_data FLOAT NULL,
|
total_sent FLOAT NULL, total_data FLOAT NULL,
|
||||||
cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, time DATETIME
|
cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, time DATETIME
|
||||||
)
|
)
|
||||||
""" % self.Name
|
""" % self.Name
|
||||||
)
|
)
|
||||||
sqldb.commit()
|
sqldb.commit()
|
||||||
|
if f'{self.Name}_deleted' not in existingTables:
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE %s_deleted (
|
||||||
|
id VARCHAR NOT NULL, private_key VARCHAR NULL, DNS VARCHAR NULL,
|
||||||
|
endpoint_allowed_ip VARCHAR NULL, name VARCHAR NULL, total_receive FLOAT NULL,
|
||||||
|
total_sent FLOAT NULL, total_data FLOAT NULL, endpoint VARCHAR NULL,
|
||||||
|
status VARCHAR NULL, latest_handshake VARCHAR NULL, allowed_ip VARCHAR NULL,
|
||||||
|
cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, mtu INT NULL,
|
||||||
|
keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
""" % self.Name
|
||||||
|
)
|
||||||
|
sqldb.commit()
|
||||||
|
|
||||||
def __getPublicKey(self) -> str:
|
def __getPublicKey(self) -> str:
|
||||||
return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n')
|
return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n')
|
||||||
@ -242,6 +269,7 @@ class WireguardConfiguration:
|
|||||||
return self.Status
|
return self.Status
|
||||||
|
|
||||||
def __getPeers(self):
|
def __getPeers(self):
|
||||||
|
self.Peers = []
|
||||||
with open(os.path.join(WG_CONF_PATH, f'{self.Name}.conf'), 'r') as configFile:
|
with open(os.path.join(WG_CONF_PATH, f'{self.Name}.conf'), 'r') as configFile:
|
||||||
p = []
|
p = []
|
||||||
pCounter = -1
|
pCounter = -1
|
||||||
@ -277,7 +305,7 @@ class WireguardConfiguration:
|
|||||||
"endpoint": "N/A",
|
"endpoint": "N/A",
|
||||||
"status": "stopped",
|
"status": "stopped",
|
||||||
"latest_handshake": "N/A",
|
"latest_handshake": "N/A",
|
||||||
"allowed_ip": "N/A",
|
"allowed_ip": i.get("AllowedIPs", "N/A"),
|
||||||
"cumu_receive": 0,
|
"cumu_receive": 0,
|
||||||
"cumu_sent": 0,
|
"cumu_sent": 0,
|
||||||
"cumu_data": 0,
|
"cumu_data": 0,
|
||||||
@ -296,11 +324,117 @@ class WireguardConfiguration:
|
|||||||
""" % self.Name
|
""" % self.Name
|
||||||
, newPeer)
|
, newPeer)
|
||||||
sqldb.commit()
|
sqldb.commit()
|
||||||
|
self.Peers.append(Peer(newPeer))
|
||||||
else:
|
else:
|
||||||
|
cursor.execute("UPDATE %s SET allowed_ip = ? WHERE id = ?" % self.Name,
|
||||||
|
(i.get("AllowedIPs", "N/A"), i['PublicKey'],))
|
||||||
|
sqldb.commit()
|
||||||
self.Peers.append(Peer(checkIfExist))
|
self.Peers.append(Peer(checkIfExist))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
print(self.Peers)
|
|
||||||
|
def __savePeers(self):
|
||||||
|
for i in self.Peers:
|
||||||
|
d = i.toJson()
|
||||||
|
sqldb.execute(
|
||||||
|
'''
|
||||||
|
UPDATE %s SET private_key = :private_key,
|
||||||
|
DNS = :DNS, endpoint_allowed_ip = :endpoint_allowed_ip, name = :name,
|
||||||
|
total_receive = :total_receive, total_sent = :total_sent, total_data = :total_data,
|
||||||
|
endpoint = :endpoint, status = :status, latest_handshake = :latest_handshake,
|
||||||
|
allowed_ip = :allowed_ip, cumu_receive = :cumu_receive, cumu_sent = :cumu_sent,
|
||||||
|
cumu_data = :cumu_data, mtu = :mtu, keepalive = :keepalive,
|
||||||
|
remote_endpoint = :remote_endpoint, preshared_key = :preshared_key WHERE id = :id
|
||||||
|
''' % self.Name, d
|
||||||
|
)
|
||||||
|
sqldb.commit()
|
||||||
|
|
||||||
|
def getPeersLatestHandshake(self):
|
||||||
|
try:
|
||||||
|
latestHandshake = subprocess.check_output(f"wg show {self.Name} latest-handshakes",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return "stopped"
|
||||||
|
latestHandshake = latestHandshake.decode("UTF-8").split()
|
||||||
|
count = 0
|
||||||
|
now = datetime.now()
|
||||||
|
time_delta = timedelta(minutes=2)
|
||||||
|
for _ in range(int(len(latestHandshake) / 2)):
|
||||||
|
minus = now - datetime.fromtimestamp(int(latestHandshake[count + 1]))
|
||||||
|
if minus < time_delta:
|
||||||
|
status = "running"
|
||||||
|
else:
|
||||||
|
status = "stopped"
|
||||||
|
if int(latestHandshake[count + 1]) > 0:
|
||||||
|
sqldb.execute("UPDATE %s SET latest_handshake = ?, status = ? WHERE id= ?" % self.Name
|
||||||
|
, (str(minus).split(".", maxsplit=1)[0], status, latestHandshake[count],))
|
||||||
|
else:
|
||||||
|
sqldb.execute("UPDATE %s SET latest_handshake = 'No Handshake', status = ? WHERE id= ?" % self.Name
|
||||||
|
, (status, latestHandshake[count],))
|
||||||
|
sqldb.commit()
|
||||||
|
count += 2
|
||||||
|
|
||||||
|
def getPeersTransfer(self):
|
||||||
|
try:
|
||||||
|
data_usage = subprocess.check_output(f"wg show {self.Name} transfer",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
data_usage = data_usage.decode("UTF-8").split("\n")
|
||||||
|
data_usage = [p.split("\t") for p in data_usage]
|
||||||
|
for i in range(len(data_usage)):
|
||||||
|
if len(data_usage[i]) == 3:
|
||||||
|
cur_i = cursor.execute(
|
||||||
|
"SELECT total_receive, total_sent, cumu_receive, cumu_sent, status FROM %s WHERE id= ? "
|
||||||
|
% self.Name, (data_usage[i][0],)).fetchone()
|
||||||
|
if cur_i is not None:
|
||||||
|
total_sent = cur_i['total_sent']
|
||||||
|
total_receive = cur_i['total_receive']
|
||||||
|
cur_total_sent = round(int(data_usage[i][2]) / (1024 ** 3), 4)
|
||||||
|
cur_total_receive = round(int(data_usage[i][1]) / (1024 ** 3), 4)
|
||||||
|
cumulative_receive = cur_i['cumu_receive'] + total_receive
|
||||||
|
cumulative_sent = cur_i['cumu_sent'] + 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:
|
||||||
|
cursor.execute(
|
||||||
|
"UPDATE %s SET cumu_receive = ?, cumu_sent = ?, cumu_data = ? WHERE id = ?" %
|
||||||
|
self.Name, (round(cumulative_receive, 4), round(cumulative_sent, 4),
|
||||||
|
round(cumulative_sent + cumulative_receive, 4),
|
||||||
|
data_usage[i][0],))
|
||||||
|
total_sent = 0
|
||||||
|
total_receive = 0
|
||||||
|
cursor.execute(
|
||||||
|
"UPDATE %s SET total_receive = ?, total_sent = ?, total_data = ? WHERE id = ?"
|
||||||
|
% self.Name, (round(total_receive, 4), round(total_sent, 4),
|
||||||
|
round(total_receive + total_sent, 4), data_usage[i][0],))
|
||||||
|
now = datetime.now()
|
||||||
|
now_string = now.strftime("%d/%m/%Y %H:%M:%S")
|
||||||
|
cursor.execute(f'''
|
||||||
|
INSERT INTO %s_transfer
|
||||||
|
(id, total_receive, total_sent, total_data,
|
||||||
|
cumu_receive, cumu_sent, cumu_data, time)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
''' % self.Name, (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,))
|
||||||
|
sqldb.commit()
|
||||||
|
except Exception as e:
|
||||||
|
print("Error" + str(e))
|
||||||
|
|
||||||
|
def getPeersEndpoint(self):
|
||||||
|
try:
|
||||||
|
data_usage = subprocess.check_output(f"wg show {self.Name} endpoints",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return "stopped"
|
||||||
|
data_usage = data_usage.decode("UTF-8").split()
|
||||||
|
count = 0
|
||||||
|
for _ in range(int(len(data_usage) / 2)):
|
||||||
|
sqldb.execute("UPDATE %s SET endpoint = ? WHERE id = ?" % self.Name
|
||||||
|
, (data_usage[count + 1], data_usage[count],))
|
||||||
|
sqldb.commit()
|
||||||
|
count += 2
|
||||||
|
|
||||||
def toggleConfiguration(self) -> [bool, str]:
|
def toggleConfiguration(self) -> [bool, str]:
|
||||||
self.getStatus()
|
self.getStatus()
|
||||||
@ -320,7 +454,11 @@ class WireguardConfiguration:
|
|||||||
self.getStatus()
|
self.getStatus()
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
def toJSON(self):
|
def getPeers(self):
|
||||||
|
self.__getPeers()
|
||||||
|
return self.Peers
|
||||||
|
|
||||||
|
def toJson(self):
|
||||||
self.Status = self.getStatus()
|
self.Status = self.getStatus()
|
||||||
return {
|
return {
|
||||||
"Status": self.Status,
|
"Status": self.Status,
|
||||||
@ -478,7 +616,7 @@ class DashboardConfig:
|
|||||||
|
|
||||||
return True, self.__config[section][key]
|
return True, self.__config[section][key]
|
||||||
|
|
||||||
def toJSON(self) -> dict[str, dict[Any, Any]]:
|
def toJson(self) -> dict[str, dict[Any, Any]]:
|
||||||
the_dict = {}
|
the_dict = {}
|
||||||
|
|
||||||
for section in self.__config.sections():
|
for section in self.__config.sections():
|
||||||
@ -516,73 +654,6 @@ def _strToBool(value: str) -> bool:
|
|||||||
return value.lower() in ("yes", "true", "t", "1", 1)
|
return value.lower() in ("yes", "true", "t", "1", 1)
|
||||||
|
|
||||||
|
|
||||||
# def _createPeerModel(wgConfigName):
|
|
||||||
# return type(wgConfigName, (Base,), {
|
|
||||||
# "id": mapped_column(VARCHAR, primary_key=True),
|
|
||||||
# "private_key": mapped_column(VARCHAR),
|
|
||||||
# "DNS": mapped_column(VARCHAR),
|
|
||||||
# "endpoint_allowed_ip": mapped_column(VARCHAR),
|
|
||||||
# "name": mapped_column(VARCHAR),
|
|
||||||
# "total_receive": mapped_column(FLOAT),
|
|
||||||
# "total_sent": mapped_column(FLOAT),
|
|
||||||
# "total_data": mapped_column(FLOAT),
|
|
||||||
# "endpoint": mapped_column(VARCHAR),
|
|
||||||
# "status": mapped_column(VARCHAR),
|
|
||||||
# "latest_handshake": mapped_column(VARCHAR),
|
|
||||||
# "allowed_ip": mapped_column(VARCHAR),
|
|
||||||
# "cumu_receive": mapped_column(FLOAT),
|
|
||||||
# "cumu_sent": mapped_column(FLOAT),
|
|
||||||
# "cumu_data": mapped_column(FLOAT),
|
|
||||||
# "mtu": mapped_column(INT),
|
|
||||||
# "keepalive": mapped_column(INT),
|
|
||||||
# "remote_endpoint": mapped_column(VARCHAR),
|
|
||||||
# "preshared_key": mapped_column(VARCHAR),
|
|
||||||
# "__tablename__": wgConfigName,
|
|
||||||
# "__table_args__": {'extend_existing': True}
|
|
||||||
# })
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def _createRestrictedPeerModel(wgConfigName):
|
|
||||||
# return type(wgConfigName + "_restrict_access", (Base,), {
|
|
||||||
# "id": mapped_column(VARCHAR, primary_key=True),
|
|
||||||
# "private_key": mapped_column(VARCHAR),
|
|
||||||
# "DNS": mapped_column(VARCHAR),
|
|
||||||
# "endpoint_allowed_ip": mapped_column(VARCHAR),
|
|
||||||
# "name": mapped_column(VARCHAR),
|
|
||||||
# "total_receive": mapped_column(FLOAT),
|
|
||||||
# "total_sent": mapped_column(FLOAT),
|
|
||||||
# "total_data": mapped_column(FLOAT),
|
|
||||||
# "endpoint": mapped_column(VARCHAR),
|
|
||||||
# "status": mapped_column(VARCHAR),
|
|
||||||
# "latest_handshake": mapped_column(VARCHAR),
|
|
||||||
# "allowed_ip": mapped_column(VARCHAR),
|
|
||||||
# "cumu_receive": mapped_column(FLOAT),
|
|
||||||
# "cumu_sent": mapped_column(FLOAT),
|
|
||||||
# "cumu_data": mapped_column(FLOAT),
|
|
||||||
# "mtu": mapped_column(INT),
|
|
||||||
# "keepalive": mapped_column(INT),
|
|
||||||
# "remote_endpoint": mapped_column(VARCHAR),
|
|
||||||
# "preshared_key": mapped_column(VARCHAR),
|
|
||||||
# "__tablename__": wgConfigName,
|
|
||||||
# "__table_args__": {'extend_existing': True}
|
|
||||||
# })
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def _createPeerTransferModel(wgConfigName):
|
|
||||||
# return type(wgConfigName + "_transfer", (Base,), {
|
|
||||||
# "id": mapped_column(VARCHAR, primary_key=True),
|
|
||||||
# "total_receive": mapped_column(FLOAT),
|
|
||||||
# "total_sent": mapped_column(FLOAT),
|
|
||||||
# "total_data": mapped_column(FLOAT),
|
|
||||||
# "cumu_receive": mapped_column(FLOAT),
|
|
||||||
# "cumu_sent": mapped_column(FLOAT),
|
|
||||||
# "cumu_data": mapped_column(FLOAT),
|
|
||||||
# "time": mapped_column(DATETIME),
|
|
||||||
# "__tablename__": wgConfigName + "_transfer",
|
|
||||||
# "__table_args__": {'extend_existing': True},
|
|
||||||
# })
|
|
||||||
|
|
||||||
|
|
||||||
def _regexMatch(regex, text):
|
def _regexMatch(regex, text):
|
||||||
pattern = re.compile(regex)
|
pattern = re.compile(regex)
|
||||||
return pattern.search(text) is not None
|
return pattern.search(text) is not None
|
||||||
@ -667,7 +738,7 @@ def API_SignOut():
|
|||||||
@app.route('/api/getWireguardConfigurations', methods=["GET"])
|
@app.route('/api/getWireguardConfigurations', methods=["GET"])
|
||||||
def API_getWireguardConfigurations():
|
def API_getWireguardConfigurations():
|
||||||
WireguardConfigurations = _getConfigurationList()
|
WireguardConfigurations = _getConfigurationList()
|
||||||
return ResponseObject(data=[wc.toJSON() for wc in WireguardConfigurations.values()])
|
return ResponseObject(data=[wc for wc in WireguardConfigurations.values()])
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/addWireguardConfiguration', methods=["POST"])
|
@app.route('/api/addWireguardConfiguration', methods=["POST"])
|
||||||
@ -728,7 +799,7 @@ def API_toggleWireguardConfiguration():
|
|||||||
|
|
||||||
@app.route('/api/getDashboardConfiguration', methods=["GET"])
|
@app.route('/api/getDashboardConfiguration', methods=["GET"])
|
||||||
def API_getDashboardConfiguration():
|
def API_getDashboardConfiguration():
|
||||||
return ResponseObject(data=DashboardConfig.toJSON())
|
return ResponseObject(data=DashboardConfig.toJson())
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/updateDashboardConfiguration', methods=["POST"])
|
@app.route('/api/updateDashboardConfiguration', methods=["POST"])
|
||||||
@ -756,6 +827,17 @@ def API_updateDashboardConfigurationItem():
|
|||||||
return ResponseObject()
|
return ResponseObject()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/getWireguardConfigurationInfo', methods=["GET"])
|
||||||
|
def API_getConfigurationInfo():
|
||||||
|
configurationName = request.args.get("configurationName")
|
||||||
|
if not configurationName or configurationName not in WireguardConfigurations.keys():
|
||||||
|
return ResponseObject(False, "Please provide configuration name")
|
||||||
|
return ResponseObject(data={
|
||||||
|
"configurationInfo": WireguardConfigurations[configurationName],
|
||||||
|
"configurationPeers": WireguardConfigurations[configurationName].getPeers()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/getDashboardTheme')
|
@app.route('/api/getDashboardTheme')
|
||||||
def API_getDashboardTheme():
|
def API_getDashboardTheme():
|
||||||
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
|
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
|
||||||
@ -821,60 +903,20 @@ def index():
|
|||||||
|
|
||||||
|
|
||||||
def backGroundThread():
|
def backGroundThread():
|
||||||
print("Waiting 5 sec")
|
with app.app_context():
|
||||||
time.sleep(5)
|
print("Waiting 5 sec")
|
||||||
while True:
|
time.sleep(5)
|
||||||
for c in WireguardConfigurations.values():
|
while True:
|
||||||
if c.getStatus():
|
for c in WireguardConfigurations.values():
|
||||||
try:
|
if c.getStatus():
|
||||||
data_usage = subprocess.check_output(f"wg show {c.Name} transfer",
|
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
try:
|
||||||
data_usage = data_usage.decode("UTF-8").split("\n")
|
c.getPeersTransfer()
|
||||||
data_usage = [p.split("\t") for p in data_usage]
|
c.getPeersLatestHandshake()
|
||||||
for i in range(len(data_usage)):
|
c.getPeersEndpoint()
|
||||||
if len(data_usage[i]) == 3:
|
except Exception as e:
|
||||||
cur_i = cursor.execute(
|
print("Error: " + str(e))
|
||||||
"SELECT total_receive, total_sent, cumu_receive, cumu_sent, status FROM %s WHERE id= ? "
|
time.sleep(10)
|
||||||
% c.Name, (data_usage[i][0], )).fetchone()
|
|
||||||
if cur_i is not None:
|
|
||||||
total_sent = cur_i['total_sent']
|
|
||||||
total_receive = cur_i['total_receive']
|
|
||||||
cur_total_sent = round(int(data_usage[i][2]) / (1024 ** 3), 4)
|
|
||||||
cur_total_receive = round(int(data_usage[i][1]) / (1024 ** 3), 4)
|
|
||||||
cumulative_receive = cur_i['cumu_receive'] + total_receive
|
|
||||||
cumulative_sent = cur_i['cumu_sent'] + 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:
|
|
||||||
cursor.execute(
|
|
||||||
"UPDATE %s SET cumu_receive = ?, cumu_sent = ?, cumu_data = ? WHERE id = ?" %
|
|
||||||
c.Name, (round(cumulative_receive, 4), round(cumulative_sent, 4),
|
|
||||||
round(cumulative_sent + cumulative_receive, 4),
|
|
||||||
data_usage[i][0], ))
|
|
||||||
total_sent = 0
|
|
||||||
total_receive = 0
|
|
||||||
cursor.execute(
|
|
||||||
"UPDATE %s SET total_receive = ?, total_sent = ?, total_data = ? WHERE id = ?"
|
|
||||||
% c.Name, (round(total_receive, 4), round(total_sent, 4),
|
|
||||||
round(total_receive + total_sent, 4), data_usage[i][0], ))
|
|
||||||
now = datetime.now()
|
|
||||||
now_string = now.strftime("%d/%m/%Y %H:%M:%S")
|
|
||||||
cursor.execute(f'''
|
|
||||||
INSERT INTO %s_transfer
|
|
||||||
(id, total_receive, total_sent, total_data,
|
|
||||||
cumu_receive, cumu_sent, cumu_data, time)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
''' % c.Name, (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, ))
|
|
||||||
sqldb.commit()
|
|
||||||
print(data_usage)
|
|
||||||
pass
|
|
||||||
except Exception as e:
|
|
||||||
print(str(e))
|
|
||||||
time.sleep(30)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -891,4 +933,4 @@ if __name__ == "__main__":
|
|||||||
bgThread.daemon = True
|
bgThread.daemon = True
|
||||||
bgThread.start()
|
bgThread.start()
|
||||||
|
|
||||||
app.run(host=app_ip, debug=False, port=app_port)
|
app.run(host=app_ip, debug=True, port=app_port)
|
||||||
|
34
src/static/app/package-lock.json
generated
34
src/static/app/package-lock.json
generated
@ -11,10 +11,12 @@
|
|||||||
"bootstrap": "^5.3.2",
|
"bootstrap": "^5.3.2",
|
||||||
"bootstrap-icons": "^1.11.2",
|
"bootstrap-icons": "^1.11.2",
|
||||||
"cidr-tools": "^7.0.4",
|
"cidr-tools": "^7.0.4",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vue": "^3.3.11",
|
"vue": "^3.3.11",
|
||||||
|
"vue-chartjs": "^5.3.0",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -406,6 +408,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@popperjs/core": {
|
"node_modules/@popperjs/core": {
|
||||||
"version": "2.11.8",
|
"version": "2.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
@ -756,6 +764,18 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cidr-tools": {
|
"node_modules/cidr-tools": {
|
||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cidr-tools/-/cidr-tools-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cidr-tools/-/cidr-tools-7.0.4.tgz",
|
||||||
@ -798,6 +818,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
|
||||||
|
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
|
||||||
|
},
|
||||||
"node_modules/decamelize": {
|
"node_modules/decamelize": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||||
@ -1278,6 +1303,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-chartjs": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-8XqX0JU8vFZ+WA2/knz4z3ThClduni2Nm0BMe2u0mXgTfd9pXrmJ07QBI+WAij5P/aPmPMX54HCE1seWL37ZdQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": "^4.1.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-router": {
|
"node_modules/vue-router": {
|
||||||
"version": "4.2.5",
|
"version": "4.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",
|
||||||
|
@ -12,10 +12,12 @@
|
|||||||
"bootstrap": "^5.3.2",
|
"bootstrap": "^5.3.2",
|
||||||
"bootstrap-icons": "^1.11.2",
|
"bootstrap-icons": "^1.11.2",
|
||||||
"cidr-tools": "^7.0.4",
|
"cidr-tools": "^7.0.4",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vue": "^3.3.11",
|
"vue": "^3.3.11",
|
||||||
|
"vue-chartjs": "^5.3.0",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "peer",
|
||||||
|
props: {
|
||||||
|
Peer: Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="card shadow rounded-3">
|
||||||
|
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0">
|
||||||
|
<div class="dot ms-0" :class="{active: Peer.status === 'running'}"></div>
|
||||||
|
<div style="font-size: 0.8rem" class="ms-auto d-flex gap-2">
|
||||||
|
<span class="text-primary">
|
||||||
|
<i class="bi bi-arrow-down"></i><strong>
|
||||||
|
{{(Peer.cumu_receive + Peer.total_receive).toFixed(4)}}</strong> GB
|
||||||
|
</span>
|
||||||
|
<span class="text-success">
|
||||||
|
<i class="bi bi-arrow-up"></i><strong>
|
||||||
|
{{(Peer.cumu_sent + Peer.total_sent).toFixed(4)}}</strong> GB
|
||||||
|
</span>
|
||||||
|
<span class="text-secondary" v-if="Peer.latest_handshake !== 'No Handshake'">
|
||||||
|
<i class="bi bi-arrows-angle-contract"></i>
|
||||||
|
{{Peer.latest_handshake}} ago
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body pt-1" style="font-size: 0.9rem">
|
||||||
|
<h5>
|
||||||
|
{{Peer.name ? Peer.name : 'Untitled Peer'}}
|
||||||
|
</h5>
|
||||||
|
<div class="mb-2">
|
||||||
|
<small class="text-muted">Public Key</small>
|
||||||
|
<p class="mb-0"><samp>{{Peer.id}}</samp></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<small class="text-muted">Allowed IP</small>
|
||||||
|
<p class="mb-0"><samp>{{Peer.allowed_ip}}</samp></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,12 +1,368 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import {fetchGet} from "@/utilities/fetch.js";
|
||||||
|
import Peer from "@/components/configurationComponents/peer.vue";
|
||||||
|
import { Line, Bar } from 'vue-chartjs'
|
||||||
|
import {
|
||||||
|
Chart,
|
||||||
|
ArcElement,
|
||||||
|
LineElement,
|
||||||
|
BarElement,
|
||||||
|
PointElement,
|
||||||
|
BarController,
|
||||||
|
BubbleController,
|
||||||
|
DoughnutController,
|
||||||
|
LineController,
|
||||||
|
PieController,
|
||||||
|
PolarAreaController,
|
||||||
|
RadarController,
|
||||||
|
ScatterController,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
LogarithmicScale,
|
||||||
|
RadialLinearScale,
|
||||||
|
TimeScale,
|
||||||
|
TimeSeriesScale,
|
||||||
|
Decimation,
|
||||||
|
Filler,
|
||||||
|
Legend,
|
||||||
|
Title,
|
||||||
|
Tooltip
|
||||||
|
} from 'chart.js';
|
||||||
|
|
||||||
|
Chart.register(
|
||||||
|
ArcElement,
|
||||||
|
LineElement,
|
||||||
|
BarElement,
|
||||||
|
PointElement,
|
||||||
|
BarController,
|
||||||
|
BubbleController,
|
||||||
|
DoughnutController,
|
||||||
|
LineController,
|
||||||
|
PieController,
|
||||||
|
PolarAreaController,
|
||||||
|
RadarController,
|
||||||
|
ScatterController,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
LogarithmicScale,
|
||||||
|
RadialLinearScale,
|
||||||
|
TimeScale,
|
||||||
|
TimeSeriesScale,
|
||||||
|
Decimation,
|
||||||
|
Filler,
|
||||||
|
Legend,
|
||||||
|
Title,
|
||||||
|
Tooltip
|
||||||
|
);
|
||||||
|
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "configuration"
|
name: "configuration",
|
||||||
|
components: {Peer, Line, Bar},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
configurationInfo: [],
|
||||||
|
configurationPeers: [],
|
||||||
|
historyDataSentDifference: [],
|
||||||
|
historyDataReceivedDifference: [],
|
||||||
|
|
||||||
|
historySentData: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Data Sent',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
borderColor: '#198754',
|
||||||
|
tension: 0
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
historyReceiveData: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Data Received',
|
||||||
|
data: [],
|
||||||
|
fill: false,
|
||||||
|
borderColor: '#0d6efd',
|
||||||
|
tension: 0
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$route.params': {
|
||||||
|
immediate: true,
|
||||||
|
handler(){
|
||||||
|
clearInterval(this.interval)
|
||||||
|
this.loading = true;
|
||||||
|
let id = this.$route.params.id;
|
||||||
|
this.configurationInfo = [];
|
||||||
|
this.configurationPeers = [];
|
||||||
|
if (id){
|
||||||
|
this.getPeers(id)
|
||||||
|
this.interval = setInterval(() => {
|
||||||
|
this.getPeers(id)
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeRouteLeave(){
|
||||||
|
clearInterval(this.interval)
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
getPeers(id){
|
||||||
|
fetchGet("/api/getWireguardConfigurationInfo",
|
||||||
|
{
|
||||||
|
configurationName: id
|
||||||
|
}, (res) => {
|
||||||
|
this.configurationInfo = res.data.configurationInfo;
|
||||||
|
this.configurationPeers = res.data.configurationPeers;
|
||||||
|
this.loading = false;
|
||||||
|
if (this.configurationPeers.length > 0){
|
||||||
|
const sent = this.configurationPeers.map(x => x.total_sent + x.cumu_sent).reduce((x,y) => x + y).toFixed(4);
|
||||||
|
const receive = this.configurationPeers.map(x => x.total_receive + x.cumu_receive).reduce((x,y) => x + y).toFixed(4);
|
||||||
|
if (
|
||||||
|
this.historyDataSentDifference[this.historyDataSentDifference.length - 1] !== sent
|
||||||
|
){
|
||||||
|
if (this.historyDataSentDifference.length > 0){
|
||||||
|
this.historySentData = {
|
||||||
|
labels: [...this.historySentData.labels, dayjs().format("HH:mm:ss A")],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Data Sent',
|
||||||
|
data: [...this.historySentData.datasets[0].data,
|
||||||
|
((sent - this.historyDataSentDifference[this.historyDataSentDifference.length - 1])*1000).toFixed(4)],
|
||||||
|
fill: false,
|
||||||
|
borderColor: ' #198754',
|
||||||
|
tension: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.historyDataSentDifference.push(sent)
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.historyDataReceivedDifference[this.historyDataReceivedDifference.length - 1] !== receive
|
||||||
|
){
|
||||||
|
if (this.historyDataReceivedDifference.length > 0){
|
||||||
|
this.historyReceiveData = {
|
||||||
|
labels: [...this.historyReceiveData.labels, dayjs().format("HH:mm:ss A")],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Data Received',
|
||||||
|
data: [...this.historyReceiveData.datasets[0].data,
|
||||||
|
((receive - this.historyDataReceivedDifference[this.historyDataReceivedDifference.length - 1])*1000).toFixed(4)],
|
||||||
|
fill: false,
|
||||||
|
borderColor: '#0d6efd',
|
||||||
|
tension: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.historyDataReceivedDifference.push(receive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
configurationSummary(){
|
||||||
|
return {
|
||||||
|
connectedPeers: this.configurationPeers.filter(x => x.status === "running").length,
|
||||||
|
totalUsage: this.configurationPeers.length > 0 ? this.configurationPeers.map(x => x.total_data + x.cumu_data).reduce((a, b) => a + b) : 0,
|
||||||
|
totalReceive: this.configurationPeers.length > 0 ? this.configurationPeers.map(x => x.total_receive + x.cumu_receive).reduce((a, b) => a + b) : 0,
|
||||||
|
totalSent: this.configurationPeers.length > 0 ? this.configurationPeers.map(x => x.total_sent + x.cumu_sent).reduce((a, b) => a + b) : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
receiveData(){
|
||||||
|
return this.historyReceiveData
|
||||||
|
},
|
||||||
|
sentData(){
|
||||||
|
return this.historySentData
|
||||||
|
},
|
||||||
|
individualDataUsage(){
|
||||||
|
return {
|
||||||
|
labels: this.configurationPeers.map(x => {
|
||||||
|
if (x.name) return x.name
|
||||||
|
return `Untitled Peer - ${x.id}`
|
||||||
|
}),
|
||||||
|
datasets: [{
|
||||||
|
label: 'Total Data Usage',
|
||||||
|
data: this.configurationPeers.map(x => x.cumu_data + x.total_data),
|
||||||
|
backgroundColor: this.configurationPeers.map(x => `#0dcaf0`),
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: (tooltipItem) => {
|
||||||
|
console.log(tooltipItem)
|
||||||
|
return `${tooltipItem.formattedValue} GB`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
individualDataUsageChartOption(){
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
ticks: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y:{
|
||||||
|
ticks: {
|
||||||
|
callback: (val, index) => {
|
||||||
|
return `${val} GB`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chartOptions() {
|
||||||
|
return {
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: (tooltipItem) => {
|
||||||
|
console.log(tooltipItem)
|
||||||
|
return `${tooltipItem.formattedValue} MB/s`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
ticks: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y:{
|
||||||
|
ticks: {
|
||||||
|
callback: (val, index) => {
|
||||||
|
return `${val} MB/s`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="text-body">
|
<div class="mt-5 text-body" v-if="!loading">
|
||||||
hiiii
|
<div>
|
||||||
|
<small CLASS="text-muted">CONFIGURATION</small>
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<h1 class="mb-0"><samp>{{this.configurationInfo.Name}}</samp></h1>
|
||||||
|
<div class="dot active ms-0"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3 gy-2">
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<p class="mb-0 text-muted"><small>Address</small></p>
|
||||||
|
{{this.configurationInfo.Address}}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<p class="mb-0 text-muted"><small>Listen Port</small></p>
|
||||||
|
{{this.configurationInfo.ListenPort}}
|
||||||
|
</div>
|
||||||
|
<div style="word-break: break-all" class="col-sm-6">
|
||||||
|
<p class="mb-0 text-muted"><small>Public Key</small></p>
|
||||||
|
<samp>{{this.configurationInfo.PublicKey}}</samp>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<p class="mb-1 text-muted"><small>Connected Peers</small></p>
|
||||||
|
<i class="bi bi-ethernet me-2"></i><strong>{{configurationSummary.connectedPeers}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<p class="mb-0 text-muted"><small>Total Usage</small></p>
|
||||||
|
<i class="bi bi-arrow-down-up me-2"></i><strong>{{configurationSummary.totalUsage.toFixed(4)}}</strong> GB
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<p class="mb-0 text-muted"><small>Total Received</small></p>
|
||||||
|
<i class="bi bi-arrow-down me-2"></i><strong>{{configurationSummary.totalReceive.toFixed(4)}}</strong> GB
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<p class="mb-0 text-muted"><small>Total Sent</small></p>
|
||||||
|
<i class="bi bi-arrow-up me-2"></i><strong>{{configurationSummary.totalSent.toFixed(4)}}</strong> GB
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3 gx-2 gy-2 mb-2">
|
||||||
|
<div class="col-sm ">
|
||||||
|
<div class="card rounded-3 bg-transparent">
|
||||||
|
<div class="card-header bg-transparent border-0"><small>Peers Total Data Usage</small></div>
|
||||||
|
<div class="card-body pt-1">
|
||||||
|
<Bar
|
||||||
|
:data="individualDataUsage"
|
||||||
|
:options="individualDataUsageChartOption"
|
||||||
|
style="height: 150px; width: 100%"></Bar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm">
|
||||||
|
<div class="card rounded-3 bg-transparent">
|
||||||
|
<div class="card-header bg-transparent border-0"><small>Real Time Received Data Usage</small></div>
|
||||||
|
<div class="card-body pt-1">
|
||||||
|
<Line
|
||||||
|
:options="chartOptions"
|
||||||
|
:data="receiveData"
|
||||||
|
style="width: 100%; height: 150px"
|
||||||
|
></Line>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm">
|
||||||
|
<div class="card rounded-3 bg-transparent">
|
||||||
|
<div class="card-header bg-transparent border-0"><small>Real Time Sent Data Usage</small></div>
|
||||||
|
<div class="card-body pt-1">
|
||||||
|
<Line
|
||||||
|
:options="chartOptions"
|
||||||
|
:data="sentData"
|
||||||
|
style="width: 100%; height: 150px"
|
||||||
|
></Line>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="row gx-2 gy-2">
|
||||||
|
<div class="col-12 col-lg-6 col-xl-4" v-for="peer in this.configurationPeers">
|
||||||
|
<Peer :Peer="peer"></Peer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user