add country emoji to speed test and its result

This commit is contained in:
Nova 2025-10-03 16:19:14 +03:30
parent f98c77eb1e
commit 10e0b3158d
11 changed files with 80 additions and 32 deletions

View File

@ -111,6 +111,7 @@ message SpeedTestResult {
optional string server_name = 6 [default = ""]; optional string server_name = 6 [default = ""];
optional string server_country = 7 [default = ""]; optional string server_country = 7 [default = ""];
optional bool cancelled = 8 [default = false]; optional bool cancelled = 8 [default = false];
optional string server_country_emoji = 9 [default = ""];
} }
message SpeedTestResponse { message SpeedTestResponse {

View File

@ -30,6 +30,7 @@ require (
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
github.com/andybalholm/brotli v1.1.0 // indirect github.com/andybalholm/brotli v1.1.0 // indirect
github.com/anytls/sing-anytls v0.0.8 // indirect github.com/anytls/sing-anytls v0.0.8 // indirect
github.com/biter777/countries v1.7.5 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/caddyserver/certmagic v0.23.0 // indirect github.com/caddyserver/certmagic v0.23.0 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect

View File

@ -12,6 +12,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/anytls/sing-anytls v0.0.8 h1:1u/fnH1HoeeMV5mX7/eUOjLBvPdkd1UJRmXiRi6Vymc= github.com/anytls/sing-anytls v0.0.8 h1:1u/fnH1HoeeMV5mX7/eUOjLBvPdkd1UJRmXiRi6Vymc=
github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/biter777/countries v1.7.5 h1:MJ+n3+rSxWQdqVJU8eBy9RqcdH6ePPn4PJHocVWUa+Q=
github.com/biter777/countries v1.7.5/go.mod h1:1HSpZ526mYqKJcpT5Ti1kcGQ0L0SrXWIaptUWjFfv2E=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=

View File

@ -0,0 +1,25 @@
package internal
import "github.com/biter777/countries"
var countryMap map[string]*countries.Country
func init() {
countryMap = make(map[string]*countries.Country)
allCountries := countries.AllInfo()
for _, country := range allCountries {
countryMap[country.Name] = country
}
}
func GetCountryByName(name string) *countries.Country {
return countryMap[name]
}
func GetCountryEmojiByName(name string) string {
country, ok := countryMap[name]
if !ok {
return ""
}
return country.Emoji
}

View File

@ -348,14 +348,15 @@ func (s *server) SpeedTest(in *gen.SpeedTestRequest, out *gen.SpeedTestResponse)
errStr = data.Error.Error() errStr = data.Error.Error()
} }
res = append(res, &gen.SpeedTestResult{ res = append(res, &gen.SpeedTestResult{
DlSpeed: To(data.DlSpeed), DlSpeed: To(data.DlSpeed),
UlSpeed: To(data.UlSpeed), UlSpeed: To(data.UlSpeed),
Latency: To(data.Latency), Latency: To(data.Latency),
OutboundTag: To(data.Tag), OutboundTag: To(data.Tag),
Error: To(errStr), Error: To(errStr),
ServerName: To(data.ServerName), ServerName: To(data.ServerName),
ServerCountry: To(data.ServerCountry), ServerCountry: To(data.ServerCountry),
Cancelled: To(data.Cancelled), ServerCountryEmoji: To(data.ServerCountryEmoji),
Cancelled: To(data.Cancelled),
}) })
} }
@ -370,14 +371,15 @@ func (s *server) QuerySpeedTest(in *gen.EmptyReq, out *gen.QuerySpeedTestRespons
errStr = res.Error.Error() errStr = res.Error.Error()
} }
out.Result = &gen.SpeedTestResult{ out.Result = &gen.SpeedTestResult{
DlSpeed: To(res.DlSpeed), DlSpeed: To(res.DlSpeed),
UlSpeed: To(res.UlSpeed), UlSpeed: To(res.UlSpeed),
Latency: To(res.Latency), Latency: To(res.Latency),
OutboundTag: To(res.Tag), OutboundTag: To(res.Tag),
Error: To(errStr), Error: To(errStr),
ServerName: To(res.ServerName), ServerName: To(res.ServerName),
ServerCountry: To(res.ServerCountry), ServerCountry: To(res.ServerCountry),
Cancelled: To(res.Cancelled), ServerCountryEmoji: To(res.ServerCountryEmoji),
Cancelled: To(res.Cancelled),
} }
out.IsRunning = To(isRunning) out.IsRunning = To(isRunning)
return nil return nil

View File

@ -53,14 +53,15 @@ func (u *URLTestReporter) Results() []*URLTestResult {
} }
type SpeedTestResult struct { type SpeedTestResult struct {
Tag string Tag string
DlSpeed string DlSpeed string
UlSpeed string UlSpeed string
Latency int32 Latency int32
ServerName string ServerName string
ServerCountry string ServerCountry string
Error error ServerCountryEmoji string
Cancelled bool Error error
Cancelled bool
} }
type SpeedTestResultQuerier struct { type SpeedTestResultQuerier struct {
@ -295,6 +296,12 @@ func speedTestWithDialer(ctx context.Context, dialer func(ctx context.Context, n
} }
res.ServerName = srv[0].Name res.ServerName = srv[0].Name
res.ServerCountry = srv[0].Country res.ServerCountry = srv[0].Country
countryEmoji := internal.GetCountryEmojiByName(srv[0].Country)
if countryEmoji == "" {
fmt.Println("Failed to get country emoji for", srv[0].Name)
} else {
res.ServerCountryEmoji = countryEmoji
}
done := make(chan struct{}) done := make(chan struct{})

View File

@ -41,6 +41,7 @@ namespace Configs {
int latency = 0; int latency = 0;
QString dl_speed; QString dl_speed;
QString ul_speed; QString ul_speed;
QString test_country_emoji;
std::shared_ptr<Configs::AbstractBean> bean; std::shared_ptr<Configs::AbstractBean> bean;
std::shared_ptr<Stats::TrafficData> traffic_data = std::make_shared<Stats::TrafficData>(""); std::shared_ptr<Stats::TrafficData> traffic_data = std::make_shared<Stats::TrafficData>("");

View File

@ -100,7 +100,7 @@ namespace Configs {
bool enable_stats = true; bool enable_stats = true;
int stats_tab = 0; // either connection or log int stats_tab = 0; // either connection or log
int speed_test_mode = TestConfig::FULL; int speed_test_mode = TestConfig::FULL;
int speed_test_timeout_ms = 3000; int speed_test_timeout_ms = 5000;
QString simple_dl_url = "http://cachefly.cachefly.net/1mb.test"; QString simple_dl_url = "http://cachefly.cachefly.net/1mb.test";
bool allow_beta_update = false; bool allow_beta_update = false;

View File

@ -12,6 +12,7 @@ namespace Configs
_add(new configItem("dl", &dl_speed, itemType::string)); _add(new configItem("dl", &dl_speed, itemType::string));
_add(new configItem("ul", &ul_speed, itemType::string)); _add(new configItem("ul", &ul_speed, itemType::string));
_add(new configItem("report", &full_test_report, itemType::string)); _add(new configItem("report", &full_test_report, itemType::string));
_add(new configItem("country_emoji", &test_country_emoji, itemType::string));
if (bean != nullptr) { if (bean != nullptr) {
this->bean = std::shared_ptr<Configs::AbstractBean>(bean); this->bean = std::shared_ptr<Configs::AbstractBean>(bean);
@ -25,21 +26,25 @@ namespace Configs
if (latency < 0) { if (latency < 0) {
result = "Unavailable"; result = "Unavailable";
} else if (latency > 0) { } else if (latency > 0) {
result = UNICODE_LRO + QString("%1 ms").arg(latency); if (!test_country_emoji.isEmpty()) result += UNICODE_LRO + test_country_emoji + " ";
result += QString("%1 ms").arg(latency);
} }
if (!dl_speed.isEmpty()) result += "" + dl_speed; if (!dl_speed.isEmpty() && dl_speed != "N/A") result += "" + dl_speed;
if (!ul_speed.isEmpty()) result += "" + ul_speed; if (!ul_speed.isEmpty() && ul_speed != "N/A") result += "" + ul_speed;
return result; return result;
} }
QColor ProxyEntity::DisplayLatencyColor() const { QColor ProxyEntity::DisplayLatencyColor() const {
if (latency < 0) { if (latency < 0) {
return Qt::red; return Qt::darkGray;
} else if (latency > 0) { } else if (latency > 0) {
if (latency <= 200) { if (latency <= 100) {
return Qt::darkGreen; return Qt::darkGreen;
} else { } else if (latency <= 300)
{
return Qt::darkYellow; return Qt::darkYellow;
} else {
return Qt::red;
} }
} else { } else {
return {}; return {};

View File

@ -1080,10 +1080,11 @@ void MainWindow::UpdateDataView(bool force)
"<span style='color: #3299FF;'>Dl↓ %2</span> " "<span style='color: #3299FF;'>Dl↓ %2</span> "
"<span style='color: #86C43F;'>Ul↑ %3</span>" "<span style='color: #86C43F;'>Ul↑ %3</span>"
"</div>" "</div>"
"<p style='text-align:center;margin:0;'>Server: %4, %5</p>" "<p style='text-align:center;margin:0;'>Server: %4%5, %6</p>"
).arg(currentSptProfileName, ).arg(currentSptProfileName,
currentTestResult.dl_speed.value().c_str(), currentTestResult.dl_speed.value().c_str(),
currentTestResult.ul_speed.value().c_str(), currentTestResult.ul_speed.value().c_str(),
currentTestResult.server_country_emoji.value().c_str(),
currentTestResult.server_country.value().c_str(), currentTestResult.server_country.value().c_str(),
currentTestResult.server_name.value().c_str()); currentTestResult.server_name.value().c_str());
} }

View File

@ -323,6 +323,7 @@ void MainWindow::runSpeedTest(const QString& config, bool useDefault, bool testC
if (!res.result.value().dl_speed.value().empty()) profile->dl_speed = QString::fromStdString(res.result.value().dl_speed.value()); if (!res.result.value().dl_speed.value().empty()) profile->dl_speed = QString::fromStdString(res.result.value().dl_speed.value());
if (!res.result.value().ul_speed.value().empty()) profile->ul_speed = QString::fromStdString(res.result.value().ul_speed.value()); if (!res.result.value().ul_speed.value().empty()) profile->ul_speed = QString::fromStdString(res.result.value().ul_speed.value());
if (profile->latency <= 0 && res.result.value().latency.value() > 0) profile->latency = res.result.value().latency.value(); if (profile->latency <= 0 && res.result.value().latency.value() > 0) profile->latency = res.result.value().latency.value();
if (!res.result->server_country_emoji.value().empty()) profile->test_country_emoji = QString::fromStdString(res.result.value().server_country_emoji.value());
refresh_proxy_list(profile->id); refresh_proxy_list(profile->id);
lastProxyListUpdate = QDateTime::currentDateTime(); lastProxyListUpdate = QDateTime::currentDateTime();
} }
@ -364,10 +365,12 @@ void MainWindow::runSpeedTest(const QString& config, bool useDefault, bool testC
ent->dl_speed = QString::fromStdString(res.dl_speed.value()); ent->dl_speed = QString::fromStdString(res.dl_speed.value());
ent->ul_speed = QString::fromStdString(res.ul_speed.value()); ent->ul_speed = QString::fromStdString(res.ul_speed.value());
if (ent->latency <= 0 && res.latency.value() > 0) ent->latency = res.latency.value(); if (ent->latency <= 0 && res.latency.value() > 0) ent->latency = res.latency.value();
if (!res.server_country_emoji.value().empty()) ent->test_country_emoji = QString::fromStdString(res.server_country_emoji.value());
} else { } else {
ent->dl_speed = "N/A"; ent->dl_speed = "N/A";
ent->ul_speed = "N/A"; ent->ul_speed = "N/A";
ent->latency = -1; ent->latency = -1;
ent->test_country_emoji = "";
MW_show_log(tr("[%1] speed test error: %2").arg(ent->bean->DisplayTypeAndName(), QString::fromStdString(res.error.value()))); MW_show_log(tr("[%1] speed test error: %2").arg(ent->bean->DisplayTypeAndName(), QString::fromStdString(res.error.value())));
} }
ent->Save(); ent->Save();