223 lines
9.6 KiB
C++
223 lines
9.6 KiB
C++
#include "dedicatedserverinfowidget.h"
|
||
#include "ui_dedicatedserverinfowidget.h"
|
||
#include <QTimer>
|
||
#include <QNetworkRequest>
|
||
#include <QJsonArray>
|
||
#include <QJsonDocument>
|
||
#include <QJsonObject>
|
||
#include <QUrl>
|
||
#include <QUrlQuery>
|
||
#include <QDate>
|
||
#include <QDebug>
|
||
#include <QDesktopServices>
|
||
#include <QMessageBox>
|
||
#include <QInputDialog>
|
||
|
||
#include <ranges>
|
||
#include "ovhapi.h"
|
||
|
||
const auto ten_years = 87600h;
|
||
|
||
// Translated QString, stored there for easy single translation...
|
||
QString monitoringWithIntervention, monitoringWithoutIntervention, noMonitoring;
|
||
|
||
DedicatedServerInfoWidget::DedicatedServerInfoWidget(OvhApi *api, const QString &serverName, QWidget *parent) :
|
||
QWidget(parent),
|
||
api(api),
|
||
_serverName(serverName),
|
||
ui(new Ui::DedicatedServerInfoWidget)
|
||
{
|
||
ui->setupUi(this);
|
||
QTimer::singleShot(0, this, &DedicatedServerInfoWidget::fetchOvhServerInfo);
|
||
|
||
if (monitoringWithIntervention.isEmpty()) {
|
||
monitoringWithIntervention = tr("Enabled with intervention");
|
||
monitoringWithoutIntervention = tr("Enabled without intervention");
|
||
noMonitoring = tr("Disabled");
|
||
}
|
||
}
|
||
|
||
DedicatedServerInfoWidget::~DedicatedServerInfoWidget()
|
||
{
|
||
delete ui;
|
||
}
|
||
|
||
QCoro::Task<> DedicatedServerInfoWidget::fetchOvhServerInfo()
|
||
{
|
||
auto serverInfo = (co_await api->get("/dedicated/server/" + _serverName, 1h)).object();
|
||
qDebug() << serverInfo;
|
||
ui->serverName->setText(serverInfo["name"].toString());
|
||
ui->datacenter->setText(serverInfo["datacenter"].toString());
|
||
ui->rack->setText(serverInfo["rack"].toString());
|
||
if (serverInfo["monitoring"].toBool()) {
|
||
if (serverInfo["noIntervention"].toBool())
|
||
ui->ovhMonitoring->setText(monitoringWithoutIntervention);
|
||
else
|
||
ui->ovhMonitoring->setText(monitoringWithIntervention);
|
||
} else {
|
||
ui->ovhMonitoring->setText(noMonitoring);
|
||
}
|
||
|
||
auto serviceInfo = (co_await api->get(QString("/dedicated/server/%1/serviceInfos").arg(_serverName), 1h)).object();
|
||
auto serviceId = serviceInfo["serviceId"].toInt();
|
||
auto servicesData = (co_await api->get(QString("/services/%1").arg(serviceId), 6h)).object();
|
||
auto billingData = servicesData["billing"].toObject();
|
||
auto pricingData = billingData["pricing"].toObject();
|
||
qDebug() << serviceInfo;
|
||
QDate creationDate = QDate::fromString(serviceInfo["creation"].toString(), Qt::ISODate);
|
||
QDate expirationDate = QDate::fromString(serviceInfo["expiration"].toString(), Qt::ISODate);
|
||
QString serverDates = QString{"%1 - %2"}.arg(creationDate.toString()).arg(expirationDate.toString());
|
||
ui->serverDates->setText(serverDates);
|
||
|
||
if (!billingData["engagement"].isNull()) {
|
||
// Now figure out the mess here.
|
||
auto engagementConfiguration = pricingData["engagementConfiguration"].toObject();
|
||
auto engagementInfo = billingData["engagement"].toObject();
|
||
QDate engageDate = QDate::fromString(engagementInfo["endDate"].toString(), Qt::ISODate);
|
||
QString strategy = engagementInfo["endRule"].toObject()["strategy"].toString();
|
||
QString engagementLine1, engagementLine2;
|
||
if (strategy == "REACTIVATE_ENGAGEMENT") {
|
||
engagementLine1 = tr("Until %1, <b>automatic reactivation</b>").arg(engageDate.toString());
|
||
} else if (strategy == "STOP_ENGAGEMENT_FALLBACK_DEFAULT_PRICE") {
|
||
engagementLine1 = tr("Until %1, stopping engagement after").arg(engageDate.toString());
|
||
} else {
|
||
engagementLine1 = tr("Until %1, unknown strategy %2").arg(engageDate.toString()).arg(strategy);
|
||
}
|
||
int periodDuration = -1;
|
||
QRegularExpression engagementDurationRegex{"^P(\\d+)M"};
|
||
auto match = engagementDurationRegex.match(engagementConfiguration["duration"].toString());
|
||
if (match.hasMatch()) {
|
||
periodDuration = match.captured(1).toInt();
|
||
} else {
|
||
qDebug() << "No match for " << engagementConfiguration["duration"].toString();
|
||
}
|
||
auto type = engagementConfiguration["type"].toString();
|
||
if (type == "upfront") {
|
||
engagementLine2 = tr("<b>Upfront payment for %1 months at once</b>").arg(periodDuration);
|
||
} else if (type == "periodic") {
|
||
engagementLine2 = tr("Periodic payment, engage for %1 months at once").arg(periodDuration);
|
||
} else {
|
||
engagementLine2 = tr("Unknown type %1 for %2 months at once").arg(type).arg(periodDuration);
|
||
}
|
||
ui->engagement->setText(engagementLine1 + "<br />" + engagementLine2);
|
||
} else {
|
||
ui->engagement->setText(tr("No engagement"));
|
||
}
|
||
|
||
auto networkInfo = (co_await api->get(QString("/dedicated/server/%1/specifications/network").arg(_serverName), 240h)).object();
|
||
qDebug() << networkInfo;
|
||
auto routingInfo = networkInfo["routing"].toObject();
|
||
auto v4Info = routingInfo["ipv4"].toObject();
|
||
ui->ipv4->setText(v4Info["ip"].toString());
|
||
ui->ipv4gateway->setText(v4Info["gateway"].toString());
|
||
auto v6Info = routingInfo["ipv6"].toObject();
|
||
ui->ipv6->setText(v6Info["ip"].toString());
|
||
ui->ipv6gateway->setText(v6Info["gateway"].toString());
|
||
|
||
auto hardwareInfo = (co_await api->get(QString("/dedicated/server/%1/specifications/hardware").arg(_serverName), 240h)).object();
|
||
qDebug() << hardwareInfo;
|
||
ui->description->setText(hardwareInfo["description"].toString());
|
||
ui->cpu->setText(QString("%1 × %2").arg(hardwareInfo["numberOfProcessors"].toInt()).arg(hardwareInfo["processorName"].toString()));
|
||
auto memoryInfo = hardwareInfo["memorySize"].toObject();
|
||
ui->ram->setText(QString("%1 %2").arg(memoryInfo["value"].toInt()).arg(memoryInfo["unit"].toString()));
|
||
QStringList storages;
|
||
for (auto storage: hardwareInfo["diskGroups"].toArray()) {
|
||
storages.append(storage.toObject()["description"].toString());
|
||
}
|
||
ui->storage->setText(storages.join("\n"));
|
||
|
||
// Check KVM support on IPMI, HTML5 only so far.
|
||
|
||
auto ipmiInfo = (co_await api->get(QString("/dedicated/server/%1/features/ipmi").arg(_serverName), 24h)).object();
|
||
qDebug() << ipmiInfo;
|
||
if (!ipmiInfo["activated"].toBool()) {
|
||
ui->kvmButton->setEnabled(false);
|
||
ui->kvmButton->setText(tr("IPMI disabled, no KVM"));
|
||
}
|
||
if (!ipmiInfo["supportedFeatures"].toObject()["kvmipHtml5URL"].toBool()
|
||
&&
|
||
!ipmiInfo["supportedFeatures"].toObject()["kvmipJnlp"].toBool()) {
|
||
ui->kvmButton->setEnabled(false);
|
||
ui->kvmButton->setText(tr("No KVM available"));
|
||
}
|
||
|
||
// Calculate monthly cost, using the /services API
|
||
double totalCost = pricingData["price"].toObject()["value"].toDouble();
|
||
totalCost = totalCost / pricingData["interval"].toInt();
|
||
QString currency = pricingData["price"].toObject()["currency"].toString();
|
||
ui->monthlyCost->setText(QString("%1 %2").arg(totalCost).arg(currency));
|
||
}
|
||
|
||
QCoro::Task<> DedicatedServerInfoWidget::on_findLastBill_clicked()
|
||
{
|
||
ui->findLastBill->setEnabled(false);
|
||
auto textBackup = ui->findLastBill->text();
|
||
ui->findLastBill->setText(tr("Searching"));
|
||
|
||
// Let the pain begin
|
||
auto billList = (co_await api->get("/me/bill/", 12h)).array();
|
||
for (int i = billList.size() - 1 ; i >= 0 ; i--) {
|
||
auto billId = billList[i].toString();
|
||
qDebug() << "Checking bill " << billId;
|
||
auto billItems = (co_await api->get(QString("/me/bill/%1/details").arg(billId), ten_years)).array();
|
||
for (auto billItemId: billItems) {
|
||
qDebug() << "Checking bill " << billId << " item " << billItemId.toString();
|
||
auto billItem = (co_await api->get(QString("/me/bill/%1/details/%2").arg(billId).arg(billItemId.toString()), ten_years)).object();
|
||
qDebug() << billItem["domain"].toString() << " vs " << _serverName;
|
||
if (billItem["domain"].toString().startsWith(_serverName)) {
|
||
qDebug() << "EUREKA !";
|
||
auto billInfo = (co_await api->get(QString("/me/bill/%1").arg(billId), ten_years)).object();
|
||
QDesktopServices::openUrl(billInfo["url"].toString());
|
||
ui->findLastBill->setText(textBackup);
|
||
ui->findLastBill->setEnabled(true);
|
||
co_return;
|
||
}
|
||
}
|
||
}
|
||
|
||
ui->findLastBill->setText(textBackup);
|
||
ui->findLastBill->setEnabled(true);
|
||
}
|
||
|
||
|
||
void DedicatedServerInfoWidget::on_kvmButton_clicked()
|
||
{
|
||
emit kvmRequested();
|
||
}
|
||
|
||
|
||
void DedicatedServerInfoWidget::on_renewCgi_clicked()
|
||
{
|
||
// best OVH page ever. trust me I know.
|
||
QUrl renewCgiUrl{"https://www.ovh.com/fr/cgi-bin/order/renew.cgi"};
|
||
QUrlQuery renewQuery{{"domainChooser", _serverName}};
|
||
renewCgiUrl.setQuery(renewQuery);
|
||
QDesktopServices::openUrl(renewCgiUrl);
|
||
}
|
||
|
||
QCoro::Task<> DedicatedServerInfoWidget::on_changeMonitoringButton_clicked()
|
||
{
|
||
QStringList monitoringStatus = {monitoringWithIntervention, monitoringWithoutIntervention, noMonitoring};
|
||
int currentStatus = monitoringStatus.indexOf(ui->ovhMonitoring->text());
|
||
bool ok;
|
||
auto newMode = QInputDialog::getItem(this, tr("New monitoring mode"), tr("What status do you want for OVH monitoring"), monitoringStatus, currentStatus, false, &ok);
|
||
if (ok && newMode != ui->ovhMonitoring->text()) {
|
||
// Build change data
|
||
QJsonObject data;
|
||
if (newMode == noMonitoring)
|
||
data.insert("monitoring", false);
|
||
else {
|
||
data.insert("monitoring", true);
|
||
if (newMode == monitoringWithIntervention)
|
||
data.insert("noIntervention", false);
|
||
else
|
||
data.insert("noIntervention", true);
|
||
}
|
||
// Put and refresh
|
||
co_await api->put("/dedicated/server/" + _serverName, QJsonDocument(data).toJson());
|
||
co_await api->get("/dedicated/server/" + _serverName, 1h, true);
|
||
fetchOvhServerInfo();
|
||
}
|
||
}
|
||
|