mirror of
https://github.com/Mahdi-zarei/nekoray.git
synced 2025-12-19 05:30:06 +08:00
add speedtest querier and ui view
This commit is contained in:
parent
bd1b1b1635
commit
a2c5efc31d
@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/Mahdi-zarei/speedtest-go/speedtest"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/metadata"
|
||||
"github.com/sagernet/sing/service"
|
||||
"nekobox_core/internal/boxbox"
|
||||
@ -206,14 +205,14 @@ func speedTestWithDialer(ctx context.Context, dialer func(ctx context.Context, n
|
||||
defer func() { close(done) }()
|
||||
if testDl {
|
||||
err = srv[0].DownloadTestContext(ctx)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
res.Error = err
|
||||
return
|
||||
}
|
||||
}
|
||||
if testUl {
|
||||
err = srv[0].UploadTestContext(ctx)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
res.Error = err
|
||||
return
|
||||
}
|
||||
@ -232,7 +231,7 @@ func speedTestWithDialer(ctx context.Context, dialer func(ctx context.Context, n
|
||||
SpTQuerier.storeResult(res)
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
return E.New("test cancelled")
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
res.DlSpeed = speedtest.ByteRate(srv[0].Context.GetEWMADownloadRate()).String()
|
||||
res.UlSpeed = speedtest.ByteRate(srv[0].Context.GetEWMAUploadRate()).String()
|
||||
|
||||
@ -42,7 +42,7 @@ namespace NekoGui_rpc {
|
||||
|
||||
libcore::SpeedTestResponse SpeedTest(bool *rpcOK, const libcore::SpeedTestRequest &request);
|
||||
|
||||
libcore::SpeedTestResult QueryCurrentSpeedTests(bool *rpcOK);
|
||||
libcore::QuerySpeedTestResponse QueryCurrentSpeedTests(bool *rpcOK);
|
||||
|
||||
private:
|
||||
std::function<std::unique_ptr<QtGrpc::Http2GrpcChannelPrivate>()> make_grpc_channel;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <core/server/gen/libcore.pb.h>
|
||||
|
||||
#include "include/global/NekoGui.hpp"
|
||||
#include "include/stats/connections/connectionLister.hpp"
|
||||
@ -86,6 +87,9 @@ public:
|
||||
|
||||
void UpdateConnectionListWithRecreate(const QList<NekoGui_traffic::ConnectionMetadata>& connections);
|
||||
|
||||
// TODO maybe use a more generalized way of passing data later, for now we only need it for speedtest data
|
||||
void UpdateDataView(const libcore::SpeedTestResult& result, const QString& profileName, bool clear);
|
||||
|
||||
signals:
|
||||
|
||||
void profile_selected(int id);
|
||||
|
||||
@ -165,23 +165,43 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="search">
|
||||
<property name="clearButtonEnabled">
|
||||
<widget class="QTextBrowser" name="data_view">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::FocusPolicy::NoFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ContextMenuPolicy::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Sunken</enum>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextInteractionFlag::LinksAccessibleByKeyboard|Qt::TextInteractionFlag::LinksAccessibleByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -536,7 +556,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>25</height>
|
||||
<height>17</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_program">
|
||||
|
||||
@ -421,10 +421,10 @@ namespace NekoGui_rpc {
|
||||
}
|
||||
}
|
||||
|
||||
libcore::SpeedTestResult Client::QueryCurrentSpeedTests(bool *rpcOK)
|
||||
libcore::QuerySpeedTestResponse Client::QueryCurrentSpeedTests(bool *rpcOK)
|
||||
{
|
||||
const libcore::EmptyReq req;
|
||||
libcore::SpeedTestResult reply;
|
||||
libcore::QuerySpeedTestResponse reply;
|
||||
auto status = make_grpc_channel()->Call("QuerySpeedTest", req, &reply);
|
||||
|
||||
if (status == QNetworkReply::NoError) {
|
||||
|
||||
@ -310,38 +310,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
ui->proxyListTable->setTabKeyNavigation(false);
|
||||
|
||||
// search box
|
||||
ui->search->setVisible(false);
|
||||
connect(shortcut_ctrl_f, &QShortcut::activated, this, [=] {
|
||||
ui->search->setVisible(true);
|
||||
ui->search->setFocus();
|
||||
});
|
||||
connect(shortcut_esc, &QShortcut::activated, this, [=] {
|
||||
if (ui->search->isVisible()) {
|
||||
ui->search->setText("");
|
||||
ui->search->textChanged("");
|
||||
ui->search->setVisible(false);
|
||||
}
|
||||
if (select_mode) {
|
||||
emit profile_selected(-1);
|
||||
select_mode = false;
|
||||
refresh_status();
|
||||
}
|
||||
});
|
||||
connect(ui->search, &QLineEdit::textChanged, this, [=](const QString &text) {
|
||||
if (text.isEmpty()) {
|
||||
for (int i = 0; i < ui->proxyListTable->rowCount(); i++) {
|
||||
ui->proxyListTable->setRowHidden(i, false);
|
||||
}
|
||||
} else {
|
||||
QList<QTableWidgetItem *> findItem = ui->proxyListTable->findItems(text, Qt::MatchContains);
|
||||
for (int i = 0; i < ui->proxyListTable->rowCount(); i++) {
|
||||
ui->proxyListTable->setRowHidden(i, true);
|
||||
}
|
||||
for (auto item: findItem) {
|
||||
if (item != nullptr) ui->proxyListTable->setRowHidden(item->row(), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// refresh
|
||||
this->refresh_groups();
|
||||
@ -953,6 +928,27 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
|
||||
if (NekoGui::dataStore->started_id >= 0) neko_start(NekoGui::dataStore->started_id);
|
||||
}
|
||||
|
||||
void MainWindow::UpdateDataView(const libcore::SpeedTestResult& result, const QString& profileName, bool clear)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
ui->data_view->clear();
|
||||
return;
|
||||
}
|
||||
QString html = QString(
|
||||
"<p style='text-align:center;margin:0;'>Running Speedtest: %1</p>"
|
||||
"<p style='text-align:center; color:#3299FF;margin:0;'>Dl↓ %2</p>"
|
||||
"<p style='text-align:center; color:#86C43F;margin:0;'>Ul↑ %3</p>"
|
||||
"<p style='text-align:center;margin:0;'>Server: %4, %5</p>"
|
||||
).arg(profileName,
|
||||
result.dl_speed().c_str(),
|
||||
result.ul_speed().c_str(),
|
||||
result.server_country().c_str(),
|
||||
result.server_name().c_str());
|
||||
ui->data_view->setHtml(html);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::setupConnectionList()
|
||||
{
|
||||
ui->connections->horizontalHeader()->setHighlightSections(false);
|
||||
|
||||
@ -223,8 +223,43 @@ void MainWindow::runSpeedTest(const QString& config, bool useDefault, const QStr
|
||||
req.set_test_download(speedtestConf == NekoGui::TestConfig::FULL || speedtestConf == NekoGui::TestConfig::DL);
|
||||
req.set_test_upload(speedtestConf == NekoGui::TestConfig::FULL || speedtestConf == NekoGui::TestConfig::UL);
|
||||
|
||||
// loop query result
|
||||
auto doneMu = new QMutex;
|
||||
doneMu->lock();
|
||||
runOnNewThread([=]
|
||||
{
|
||||
bool ok;
|
||||
while (true) {
|
||||
QThread::msleep(100);
|
||||
if (doneMu->tryLock())
|
||||
{
|
||||
break;
|
||||
}
|
||||
auto res = defaultClient->QueryCurrentSpeedTests(&ok);
|
||||
if (!ok || !res.is_running())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto profile = NekoGui::profileManager->GetProfile(tag2entID[res.result().outbound_tag().c_str()]);
|
||||
if (profile == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
runOnUiThread([=]
|
||||
{
|
||||
UpdateDataView(res.result(), profile->bean->name, false);
|
||||
});
|
||||
}
|
||||
runOnUiThread([=]
|
||||
{
|
||||
UpdateDataView({}, {}, true);
|
||||
});
|
||||
doneMu->unlock();
|
||||
delete doneMu;
|
||||
});
|
||||
bool rpcOK;
|
||||
auto result = defaultClient->SpeedTest(&rpcOK, req);
|
||||
doneMu->unlock();
|
||||
//
|
||||
if (!rpcOK) return;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user