Fix old Minecraft versions not having playtime resolved for servers (#3871)

* Fix old Minecraft versions not having playtime resolved for servers

* Revert and clean up get_server_worlds_in_profile a bit

* Add a semaphore to resolve_server_address in general to apply to all DNS queries

* Remove unused tokio-stream dependency from theseus
This commit is contained in:
Josiah Glosson
2025-06-30 17:36:38 -05:00
committed by GitHub
parent dd98a1316a
commit 3233e7fc54

View File

@@ -26,6 +26,8 @@ use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use tokio::io::AsyncWriteExt;
use tokio::sync::Semaphore;
use tokio::task::JoinSet;
use tokio_util::compat::FuturesAsyncWriteCompatExt;
use url::Url;
@@ -394,25 +396,27 @@ async fn get_server_worlds_in_profile(
.await
.ok();
let first_server_index = worlds.len();
for (index, server) in servers.into_iter().enumerate() {
if server.hidden {
// TODO: Figure out whether we want to hide or show direct connect servers
continue;
}
let icon = server.icon.and_then(|icon| {
Url::parse(&format!("data:image/png;base64,{icon}")).ok()
});
let last_played = join_log
.as_ref()
.and_then(|log| {
let address = parse_server_address(&server.ip).ok()?;
log.get(&(address.0.to_owned(), address.1))
})
.copied();
let world = World {
name: server.name,
last_played,
icon: icon.map(Either::Right),
last_played: join_log
.as_ref()
.and_then(|log| {
let (host, port) = parse_server_address(&server.ip).ok()?;
log.get(&(host.to_owned(), port))
})
.copied(),
icon: server
.icon
.and_then(|icon| {
Url::parse(&format!("data:image/png;base64,{icon}")).ok()
})
.map(Either::Right),
display_status: DisplayStatus::Normal,
details: WorldDetails::Server {
index,
@@ -423,6 +427,30 @@ async fn get_server_worlds_in_profile(
worlds.push(world);
}
if let Some(join_log) = join_log {
let mut futures = JoinSet::new();
for (index, world) in worlds.iter().enumerate().skip(first_server_index)
{
if world.last_played.is_some() {
continue;
}
if let WorldDetails::Server { address, .. } = &world.details
&& let Ok((host, port)) = parse_server_address(address)
{
let host = host.to_owned();
futures.spawn(async move {
resolve_server_address(&host, port)
.await
.ok()
.map(|x| (index, x))
});
}
}
for (index, address) in futures.join_all().await.into_iter().flatten() {
worlds[index].last_played = join_log.get(&address).copied();
}
}
Ok(())
}
@@ -943,9 +971,13 @@ async fn resolve_server_address(
host: &str,
port: u16,
) -> Result<(String, u16)> {
static SIMULTANEOUS_DNS_QUERIES: Semaphore = Semaphore::const_new(24);
if host.parse::<Ipv4Addr>().is_ok() || host.parse::<Ipv6Addr>().is_ok() {
return Ok((host.to_owned(), port));
}
let _permit = SIMULTANEOUS_DNS_QUERIES.acquire().await?;
let resolver = hickory_resolver::TokioResolver::builder_tokio()?.build();
Ok(
match resolver.srv_lookup(format!("_minecraft._tcp.{host}")).await {