1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 07:10:09 +01:00

Finished some building blocks on the new version

This commit is contained in:
Donald Zou 2024-02-26 10:22:33 -05:00
parent 1e88491ca1
commit ed3bb6429b
6 changed files with 627 additions and 146 deletions

View File

@ -344,7 +344,7 @@ def get_all_peers_data(config_name):
"total_data": 0,
"endpoint": "N/A",
"status": "stopped",
"latest_handshake": "N/A",
"latest_handshake": "No Handshake",
"allowed_ip": "N/A",
"cumu_receive": 0,
"cumu_sent": 0,

View File

@ -27,6 +27,8 @@ import pyotp
from flask import Flask, request, render_template, redirect, url_for, session, jsonify, g
from flask.json.provider import JSONProvider
from flask_qrcode import QRcode
from json import JSONEncoder
from icmplib import ping, traceroute
# Import other python files
@ -35,6 +37,7 @@ import threading
from sqlalchemy.orm import mapped_column, declarative_base, Session
from sqlalchemy import FLOAT, INT, VARCHAR, select, MetaData, DATETIME
from sqlalchemy import create_engine, inspect
from flask.json.provider import DefaultJSONProvider
DASHBOARD_VERSION = 'v3.1'
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
@ -55,20 +58,31 @@ app.secret_key = secrets.token_urlsafe(32)
# Enable QR Code Generator
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
'''
# Base = declarative_base(class_registry=dict())
class CustomJsonEncoder(JSONProvider):
def dumps(self, obj, **kwargs):
if type(obj) == WireguardConfiguration:
return obj.toJSON()
return json.dumps(obj)
class CustomJsonEncoder(DefaultJSONProvider):
def __init__(self, app):
super().__init__(app)
def loads(self, obj, **kwargs):
return json.loads(obj, **kwargs)
def default(self, o):
if isinstance(o, WireguardConfiguration) or isinstance(o, Peer):
return o.toJson()
return super().default(self, o)
app.json = CustomJsonEncoder(app)
@ -100,11 +114,10 @@ class Peer:
self.preshared_key = tableData["preshared_key"]
def toJson(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)
return self.__dict__
def __repr__(self):
return self.toJson()
return str(self.toJson())
class WireguardConfiguration:
@ -178,7 +191,7 @@ class WireguardConfiguration:
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1],
f"{self.Name}.conf"), "w+") as configFile:
print(self.__parser.sections())
# print(self.__parser.sections())
self.__parser.write(configFile)
self.Peers = []
@ -189,7 +202,7 @@ class WireguardConfiguration:
def __createDatabase(self):
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:
cursor.execute(
"""
@ -221,18 +234,32 @@ class WireguardConfiguration:
""" % self.Name
)
sqldb.commit()
if f'{self.Name}_transfer' not in existingTables:
cursor.execute(
"""
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,
cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, time DATETIME
)
""" % self.Name
)
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:
return subprocess.check_output(['wg', 'pubkey'], input=self.PrivateKey.encode()).decode().strip('\n')
@ -242,6 +269,7 @@ class WireguardConfiguration:
return self.Status
def __getPeers(self):
self.Peers = []
with open(os.path.join(WG_CONF_PATH, f'{self.Name}.conf'), 'r') as configFile:
p = []
pCounter = -1
@ -277,7 +305,7 @@ class WireguardConfiguration:
"endpoint": "N/A",
"status": "stopped",
"latest_handshake": "N/A",
"allowed_ip": "N/A",
"allowed_ip": i.get("AllowedIPs", "N/A"),
"cumu_receive": 0,
"cumu_sent": 0,
"cumu_data": 0,
@ -296,11 +324,117 @@ class WireguardConfiguration:
""" % self.Name
, newPeer)
sqldb.commit()
self.Peers.append(Peer(newPeer))
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))
except ValueError:
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]:
self.getStatus()
@ -320,7 +454,11 @@ class WireguardConfiguration:
self.getStatus()
return True, None
def toJSON(self):
def getPeers(self):
self.__getPeers()
return self.Peers
def toJson(self):
self.Status = self.getStatus()
return {
"Status": self.Status,
@ -478,7 +616,7 @@ class DashboardConfig:
return True, self.__config[section][key]
def toJSON(self) -> dict[str, dict[Any, Any]]:
def toJson(self) -> dict[str, dict[Any, Any]]:
the_dict = {}
for section in self.__config.sections():
@ -516,73 +654,6 @@ def _strToBool(value: str) -> bool:
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):
pattern = re.compile(regex)
return pattern.search(text) is not None
@ -667,7 +738,7 @@ def API_SignOut():
@app.route('/api/getWireguardConfigurations', methods=["GET"])
def API_getWireguardConfigurations():
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"])
@ -728,7 +799,7 @@ def API_toggleWireguardConfiguration():
@app.route('/api/getDashboardConfiguration', methods=["GET"])
def API_getDashboardConfiguration():
return ResponseObject(data=DashboardConfig.toJSON())
return ResponseObject(data=DashboardConfig.toJson())
@app.route('/api/updateDashboardConfiguration', methods=["POST"])
@ -756,6 +827,17 @@ def API_updateDashboardConfigurationItem():
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')
def API_getDashboardTheme():
return ResponseObject(data=DashboardConfig.GetConfig("Server", "dashboard_theme")[1])
@ -821,60 +903,20 @@ def index():
def backGroundThread():
print("Waiting 5 sec")
time.sleep(5)
while True:
for c in WireguardConfigurations.values():
if c.getStatus():
try:
data_usage = subprocess.check_output(f"wg show {c.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= ? "
% 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)
with app.app_context():
print("Waiting 5 sec")
time.sleep(5)
while True:
for c in WireguardConfigurations.values():
if c.getStatus():
try:
c.getPeersTransfer()
c.getPeersLatestHandshake()
c.getPeersEndpoint()
except Exception as e:
print("Error: " + str(e))
time.sleep(10)
if __name__ == "__main__":
@ -891,4 +933,4 @@ if __name__ == "__main__":
bgThread.daemon = True
bgThread.start()
app.run(host=app_ip, debug=False, port=app_port)
app.run(host=app_ip, debug=True, port=app_port)

View File

@ -11,10 +11,12 @@
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.10",
"pinia": "^2.1.7",
"qrcode": "^1.5.3",
"uuid": "^9.0.1",
"vue": "^3.3.11",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.2.5"
},
"devDependencies": {
@ -406,6 +408,12 @@
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"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": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@ -756,6 +764,18 @@
"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": {
"version": "7.0.4",
"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",
"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": {
"version": "1.2.0",
"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": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",

View File

@ -12,10 +12,12 @@
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"cidr-tools": "^7.0.4",
"dayjs": "^1.11.10",
"pinia": "^2.1.7",
"qrcode": "^1.5.3",
"uuid": "^9.0.1",
"vue": "^3.3.11",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.2.5"
},
"devDependencies": {

View File

@ -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>

View File

@ -1,12 +1,368 @@
<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 {
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>
<template>
<div class="text-body">
hiiii
<div class="mt-5 text-body" v-if="!loading">
<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>
</template>