parent
5211cdd4c0
commit
cf8a0efd0d
3 changed files with 165 additions and 4 deletions
|
@ -17,6 +17,9 @@ namespace
|
||||||
constexpr char container[] = "container";
|
constexpr char container[] = "container";
|
||||||
constexpr char userData[] = "userData";
|
constexpr char userData[] = "userData";
|
||||||
constexpr char creationDate[] = "creationDate";
|
constexpr char creationDate[] = "creationDate";
|
||||||
|
constexpr char latestHandshake[] = "latestHandshake";
|
||||||
|
constexpr char dataReceived[] = "dataReceived";
|
||||||
|
constexpr char dataSent[] = "dataSent";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +46,9 @@ QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case ClientNameRole: return userData.value(configKey::clientName).toString();
|
case ClientNameRole: return userData.value(configKey::clientName).toString();
|
||||||
case CreationDateRole: return userData.value(configKey::creationDate).toString();
|
case CreationDateRole: return userData.value(configKey::creationDate).toString();
|
||||||
|
case LatestHandshakeRole: return userData.value(configKey::latestHandshake).toString();
|
||||||
|
case DataReceivedRole: return userData.value(configKey::dataReceived).toString();
|
||||||
|
case DataSentRole: return userData.value(configKey::dataSent).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
@ -112,6 +118,38 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<WgShowData> data;
|
||||||
|
wgShow(container, credentials, serverController, data);
|
||||||
|
|
||||||
|
for (const auto &client : data) {
|
||||||
|
int i = 0;
|
||||||
|
for (const auto &it : std::as_const(m_clientsTable)) {
|
||||||
|
if (it.isObject()) {
|
||||||
|
QJsonObject obj = it.toObject();
|
||||||
|
if (obj.contains(configKey::clientId) && obj[configKey::clientId].toString() == client.clientId) {
|
||||||
|
QJsonObject userData = obj[configKey::userData].toObject();
|
||||||
|
|
||||||
|
if (!client.latestHandshake.isEmpty()) {
|
||||||
|
userData[configKey::latestHandshake] = client.latestHandshake;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client.dataReceived.isEmpty()) {
|
||||||
|
userData[configKey::dataReceived] = client.dataReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client.dataSent.isEmpty()) {
|
||||||
|
userData[configKey::dataSent] = client.dataSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[configKey::userData] = userData;
|
||||||
|
m_clientsTable.replace(i, obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -195,6 +233,71 @@ ErrorCode ClientManagementModel::getWireGuardClients(const DockerContainer conta
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
|
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data)
|
||||||
|
{
|
||||||
|
if (container != DockerContainer::WireGuard && container != DockerContainer::Awg) {
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorCode error = ErrorCode::NoError;
|
||||||
|
QString stdOut;
|
||||||
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
|
stdOut += data + "\n";
|
||||||
|
return ErrorCode::NoError;
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString command = QString("sudo docker exec -i $CONTAINER_NAME bash -c '%1'").arg("wg show all");
|
||||||
|
|
||||||
|
QString script = serverController->replaceVars(command, serverController->genVarsForScript(credentials, container));
|
||||||
|
error = serverController->runScript(credentials, script, cbReadStdOut);
|
||||||
|
if (error != ErrorCode::NoError) {
|
||||||
|
logger.error() << "Failed to execute wg show command";
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdOut.isEmpty()) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto getStrValue = [](const auto str) { return str.mid(str.indexOf(":") + 1).trimmed(); };
|
||||||
|
|
||||||
|
const auto parts = stdOut.split('\n');
|
||||||
|
const auto peerList = parts.filter("peer:");
|
||||||
|
const auto latestHandshakeList = parts.filter("latest handshake:");
|
||||||
|
const auto transferredDataList = parts.filter("transfer:");
|
||||||
|
|
||||||
|
if (latestHandshakeList.isEmpty() || transferredDataList.isEmpty() || peerList.isEmpty()) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto changeHandshakeFormat = [](QString &latestHandshake) {
|
||||||
|
const std::vector<std::pair<QString, QString>> replaceMap = { { " days", "d" }, { " hours", "h" }, { " minutes", "m" },
|
||||||
|
{ " seconds", "s" }, { " day", "d" }, { " hour", "h" },
|
||||||
|
{ " minute", "m" }, { " second", "s" } };
|
||||||
|
|
||||||
|
for (const auto &item : replaceMap) {
|
||||||
|
latestHandshake.replace(item.first, item.second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < peerList.size() && i < transferredDataList.size(); ++i) {
|
||||||
|
const auto transferredData = getStrValue(transferredDataList[i]).split(",");
|
||||||
|
auto latestHandshake = getStrValue(latestHandshakeList[i]);
|
||||||
|
auto bytesReceived = transferredData.front().trimmed();
|
||||||
|
auto bytesSent = transferredData.back().trimmed();
|
||||||
|
|
||||||
|
changeHandshakeFormat(latestHandshake);
|
||||||
|
|
||||||
|
bytesReceived.chop(QStringLiteral(" received").length());
|
||||||
|
bytesSent.chop(QStringLiteral(" sent").length());
|
||||||
|
|
||||||
|
data.push_back({ getStrValue(peerList[i]), latestHandshake, bytesReceived, bytesSent });
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
bool ClientManagementModel::isClientExists(const QString &clientId)
|
bool ClientManagementModel::isClientExists(const QString &clientId)
|
||||||
{
|
{
|
||||||
for (const QJsonValue &value : std::as_const(m_clientsTable)) {
|
for (const QJsonValue &value : std::as_const(m_clientsTable)) {
|
||||||
|
@ -486,5 +589,8 @@ QHash<int, QByteArray> ClientManagementModel::roleNames() const
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
roles[ClientNameRole] = "clientName";
|
roles[ClientNameRole] = "clientName";
|
||||||
roles[CreationDateRole] = "creationDate";
|
roles[CreationDateRole] = "creationDate";
|
||||||
|
roles[LatestHandshakeRole] = "latestHandshake";
|
||||||
|
roles[DataReceivedRole] = "dataReceived";
|
||||||
|
roles[DataSentRole] = "dataSent";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,18 @@ class ClientManagementModel : public QAbstractListModel
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
ClientNameRole = Qt::UserRole + 1,
|
ClientNameRole = Qt::UserRole + 1,
|
||||||
CreationDateRole
|
CreationDateRole,
|
||||||
|
LatestHandshakeRole,
|
||||||
|
DataReceivedRole,
|
||||||
|
DataSentRole
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WgShowData
|
||||||
|
{
|
||||||
|
QString clientId;
|
||||||
|
QString latestHandshake;
|
||||||
|
QString dataReceived;
|
||||||
|
QString dataSent;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||||
|
@ -57,6 +68,9 @@ private:
|
||||||
ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QSharedPointer<ServerController> &serverController, int &count);
|
const QSharedPointer<ServerController> &serverController, int &count);
|
||||||
|
|
||||||
|
ErrorCode wgShow(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
|
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data);
|
||||||
|
|
||||||
QJsonArray m_clientsTable;
|
QJsonArray m_clientsTable;
|
||||||
|
|
||||||
std::shared_ptr<Settings> m_settings;
|
std::shared_ptr<Settings> m_settings;
|
||||||
|
|
|
@ -766,9 +766,9 @@ PageType {
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
expandedHeight: root.height * 0.5
|
|
||||||
|
|
||||||
expandedContent: ColumnLayout {
|
expandedContent: ColumnLayout {
|
||||||
|
id: expandedContent
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
@ -778,6 +778,10 @@ PageType {
|
||||||
|
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
|
onImplicitHeightChanged: {
|
||||||
|
clientInfoDrawer.expandedHeight = expandedContent.implicitHeight + 32
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: clientInfoDrawer
|
target: clientInfoDrawer
|
||||||
enabled: !GC.isMobile()
|
enabled: !GC.isMobile()
|
||||||
|
@ -788,10 +792,47 @@ PageType {
|
||||||
|
|
||||||
Header2Type {
|
Header2Type {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.bottomMargin: 24
|
|
||||||
|
|
||||||
headerText: clientName
|
headerText: clientName
|
||||||
descriptionText: qsTr("Creation date: ") + creationDate
|
}
|
||||||
|
|
||||||
|
ColumnLayout
|
||||||
|
{
|
||||||
|
id: textColumn
|
||||||
|
property string textColor: "#878B91"
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
color: textColumn.textColor
|
||||||
|
visible: creationDate
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Creation date: %1").arg(creationDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
color: textColumn.textColor
|
||||||
|
visible: latestHandshake
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Latest handshake: %1").arg(latestHandshake)
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
color: textColumn.textColor
|
||||||
|
visible: dataReceived
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Data received: %1").arg(dataReceived)
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
color: textColumn.textColor
|
||||||
|
visible: dataSent
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Data sent: %1").arg(dataSent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue