Tweak search sorting (#5464)

* Tweak search sorting

* Tweak search sorting

* fix ping impl

* remove port field, add server regions

* fix compile

* fix tests

* update frontend banner upload size limit

* feat: use server project region instead of country

* remove java and bedrock port in frontend

* add helper text

* allow filtering by if server is online

* add server status online offline filter

* use region in instance

* pre-collapse status in app discovery

* pnpm prepr

* remove server discovery flag

* add servers into mobile nav tabs

* parse port from address if present

---------

Co-authored-by: tdgao <mr.trumgao@gmail.com>
This commit is contained in:
aecsocket
2026-03-03 22:20:48 +00:00
committed by GitHub
parent e1ee9c364b
commit 155f4091a6
27 changed files with 280 additions and 442 deletions

View File

@@ -666,6 +666,7 @@ previousFilterState.value = JSON.stringify({
'server_category_minecraft_server_meta',
'server_category_minecraft_server_community',
'server_game_version',
'server_status',
].includes(filterType.id)
"
>
@@ -810,7 +811,7 @@ previousFilterState.value = JSON.stringify({
:tags="project.categories"
:link="`/project/${project.slug ?? project.project_id}`"
:server-online-players="project.minecraft_java_server?.ping?.data?.players_online ?? 0"
:server-region-code="project.minecraft_server?.country"
:server-region="project.minecraft_server?.region"
:server-recent-plays="project.minecraft_java_server?.verified_plays_4w ?? 0"
:server-modpack-content="getServerModpackContent(project)"
:server-ping="serverPings[project.project_id]"

View File

@@ -58,16 +58,16 @@
<ServerOnlinePlayers :online="playersOnline ?? 0" :status-online="statusOnline" />
<div
v-if="playersOnline !== undefined && (minecraftServer?.country || ping)"
v-if="playersOnline !== undefined && (minecraftServer?.region || ping)"
class="w-1.5 h-1.5 rounded-full bg-surface-5"
></div>
<ServerRegion v-if="minecraftServer?.country" :region="minecraftServer?.country" />
<ServerRegion v-if="minecraftServer?.region" :region="minecraftServer?.region" />
<ServerPing v-if="ping" :ping="ping" />
<div
v-if="minecraftServer?.country || ping"
v-if="minecraftServer?.region || ping"
class="w-1.5 h-1.5 rounded-full bg-surface-5"
></div>

View File

@@ -417,11 +417,9 @@ async function createProject() {
},
minecraft_java_server: {
address: '',
port: 25565,
},
minecraft_bedrock_server: {
address: '',
port: 19132,
},
})
createdProjectId = result.id

View File

@@ -38,7 +38,6 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
newProjectGeneralSettings: false,
newProjectEnvironmentSettings: true,
hideRussiaCensorshipBanner: false,
serverDiscovery: true,
disablePrettyProjectUrlRedirects: false,
hidePreviewBanner: false,
i18nDebug: false,

View File

@@ -184,7 +184,6 @@
{
id: 'servers',
action: '/discover/servers',
shown: flags.serverDiscovery,
},
]"
hoverable
@@ -1002,6 +1001,10 @@ const navRoutes = computed(() => [
label: formatMessage(getProjectTypeMessage('modpack', true)),
href: '/discover/modpacks',
},
{
label: formatMessage(getProjectTypeMessage('server', true)),
href: '/discover/servers',
},
])
const userMenuOptions = computed(() => {

View File

@@ -1188,7 +1188,7 @@ const serverProject = computed(() => ({
numPlayers: projectV3.value?.minecraft_java_server?.ping?.data?.players_online,
icon: project.value.icon_url,
statusOnline: !!projectV3.value?.minecraft_java_server?.ping?.data,
region: projectV3.value?.minecraft_server?.country,
region: projectV3.value?.minecraft_server?.region,
}))
function handlePlayServerProject() {
@@ -2528,8 +2528,6 @@ const navLinks = computed(() => {
? project.value.gallery.filter((item) => item.name === '__mc_server_banner__').length
: project.value.gallery.length
console.log('galleryCount', galleryCount, !!currentMember.value)
return [
{
label: formatMessage(messages.descriptionTab),

View File

@@ -146,7 +146,9 @@
(e) => {
const input = e.target
if (input.files?.length) {
if (fileIsValid(input.files[0], { maxSize: 524288, alertOnInvalid: true }))
if (
fileIsValid(input.files[0], { maxSize: 524288000, alertOnInvalid: true })
)
showBannerPreview(Array.from(input.files))
}
}

View File

@@ -4,17 +4,17 @@
<div class="flex flex-col gap-6">
<div class="text-2xl font-semibold text-contrast">Server details</div>
<!-- Country -->
<!-- Region -->
<div class="max-w-[600px]">
<label for="server-country">
<span class="label__title">Country</span>
<label for="server-region">
<span class="label__title">Region</span>
</label>
<Combobox
id="server-country"
v-model="country"
:options="countryOptions"
id="server-region"
v-model="region"
:options="regionOptions"
searchable
placeholder="Select country"
placeholder="Select region"
:disabled="!hasPermission"
/>
</div>
@@ -48,7 +48,7 @@
</label>
</div>
<div
class="mt-2 flex items-center gap-2"
class="mt-2 flex items-center gap-2 text-sm"
@focusout="
() => {
if (!lastPingAddressChanged && javaPingResult) return
@@ -64,16 +64,6 @@
wrapper-class="flex-grow"
autocomplete="off"
/>
<StyledInput
v-model="javaPort"
type="number"
:min="1"
:max="65535"
:disabled="!hasPermission"
wrapper-class="w-24"
input-class="text-center"
autocomplete="off"
/>
</div>
<div
v-if="javaAddress"
@@ -121,6 +111,17 @@
>.
</div>
</div>
<div v-else class="mt-2 text-sm">
If you have [SRV records]
<InfoIcon
v-tooltip="{
content:
'The address you enter here may have DNS SRV records _minecraft._tcp.{your domain} which point to your Minecraft server address and port.',
popperClass: 'max-w-xs',
}"
/>, you do not need to add a port. Otherwise if you have a port which isn't 25565, you
can include it as :12345
</div>
</div>
<!-- Bedrock Address -->
@@ -140,16 +141,6 @@
wrapper-class="flex-grow"
autocomplete="off"
/>
<StyledInput
v-model="bedrockPort"
type="number"
:min="1"
:max="65535"
:disabled="!hasPermission"
wrapper-class="w-24"
input-class="text-center"
autocomplete="off"
/>
</div>
</div>
@@ -168,7 +159,7 @@
</template>
<script setup>
import { RefreshCwIcon, SpinnerIcon } from '@modrinth/assets'
import { InfoIcon, RefreshCwIcon, SpinnerIcon } from '@modrinth/assets'
import {
ButtonStyled,
Combobox,
@@ -189,27 +180,23 @@ const { addNotification } = injectNotificationManager()
const { projectV3, currentMember, patchProjectV3 } = injectProjectPageContext()
const javaAddress = ref('')
const javaPort = ref(25565)
const bedrockAddress = ref('')
const bedrockPort = ref(19132)
const country = ref('')
const region = ref('')
const languages = ref([])
const javaPingLoading = ref(false)
const javaPingResult = ref(null)
const lastPingedAddress = ref({ address: '', port: null })
const lastPingedAddress = ref('')
const lastPingAddressChanged = computed(() => {
return (
javaAddress.value.trim() !== lastPingedAddress.value.address ||
javaPort.value !== lastPingedAddress.value.port
)
return javaAddress.value.trim() !== lastPingedAddress.value
})
let pingDebounceTimer = null
watch([javaAddress, javaPort], () => {
watch(javaAddress, () => {
clearTimeout(pingDebounceTimer)
pingDebounceTimer = setTimeout(() => {
pingJavaServer()
@@ -231,13 +218,11 @@ async function pingJavaServer() {
javaPingLoading.value = true
javaPingResult.value = null
const port = javaPort.value || 25565
try {
await Promise.race([
client.labrinth.server_ping_internal.pingMinecraftJava({
address,
port,
timeout_ms: PING_TIMEOUT_MS,
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Ping timed out')), PING_TIMEOUT_MS),
@@ -248,17 +233,16 @@ async function pingJavaServer() {
javaPingResult.value = { online: false, latency: null }
} finally {
javaPingLoading.value = false
lastPingedAddress.value = { address, port }
lastPingedAddress.value = address
}
}
function initFromProjectV3(v3) {
if (!v3) return
javaAddress.value = v3.minecraft_java_server?.address ?? ''
javaPort.value = v3.minecraft_java_server?.port ?? 25565
bedrockAddress.value = v3.minecraft_bedrock_server?.address ?? ''
bedrockPort.value = v3.minecraft_bedrock_server?.port ?? 19132
country.value = v3.minecraft_server?.country ?? ''
region.value = v3.minecraft_server?.region ?? ''
languages.value = v3.minecraft_server?.languages ?? []
pingJavaServer()
@@ -278,78 +262,15 @@ if (projectV3.value) {
)
}
const countryOptions = [
{ value: 'US', label: 'United States' },
{ value: 'CA', label: 'Canada' },
{
value: 'EU',
label: 'Europe',
searchTerms: [
'Germany',
'France',
'Netherlands',
'Finland',
'Sweden',
'Denmark',
'Poland',
'Czech Republic',
'Romania',
'Austria',
'Belgium',
'Ireland',
'Spain',
'Italy',
'Portugal',
'Lithuania',
'Latvia',
'Estonia',
'Bulgaria',
'Croatia',
'Hungary',
'Slovakia',
'Greece',
'Luxembourg',
'Malta',
'Cyprus',
'Slovenia',
'Great Britain',
'United Kingdom',
],
},
{ value: 'NO', label: 'Norway' },
{ value: 'CH', label: 'Switzerland' },
{ value: 'RU', label: 'Russia' },
{ value: 'UA', label: 'Ukraine' },
{ value: 'RS', label: 'Serbia' },
{ value: 'TR', label: 'Turkey' },
{ value: 'IL', label: 'Israel' },
{ value: 'AE', label: 'United Arab Emirates' },
{ value: 'SA', label: 'Saudi Arabia' },
{ value: 'IN', label: 'India' },
{ value: 'SG', label: 'Singapore' },
{ value: 'JP', label: 'Japan' },
{ value: 'KR', label: 'South Korea' },
{ value: 'CN', label: 'China' },
{ value: 'HK', label: 'Hong Kong' },
{ value: 'TW', label: 'Taiwan' },
{ value: 'AU', label: 'Australia' },
{ value: 'NZ', label: 'New Zealand' },
{ value: 'BR', label: 'Brazil' },
{ value: 'AR', label: 'Argentina' },
{ value: 'CL', label: 'Chile' },
{ value: 'CO', label: 'Colombia' },
{ value: 'MX', label: 'Mexico' },
{ value: 'ZA', label: 'South Africa' },
{ value: 'NG', label: 'Nigeria' },
{ value: 'KE', label: 'Kenya' },
{ value: 'EG', label: 'Egypt' },
{ value: 'MY', label: 'Malaysia' },
{ value: 'TH', label: 'Thailand' },
{ value: 'VN', label: 'Vietnam' },
{ value: 'PH', label: 'Philippines' },
{ value: 'ID', label: 'Indonesia' },
{ value: 'PK', label: 'Pakistan' },
{ value: 'BD', label: 'Bangladesh' },
const regionOptions = [
{ value: 'us_east', label: 'US East' },
{ value: 'us_west', label: 'US West' },
{ value: 'europe', label: 'Europe' },
{ value: 'asia', label: 'Asia' },
{ value: 'australia', label: 'Australia' },
{ value: 'south_america', label: 'South America' },
{ value: 'middle_east', label: 'Middle East' },
{ value: 'russia', label: 'Russia' },
]
const languageOptions = [
@@ -396,12 +317,10 @@ const languageOptions = [
const javaServerPatchData = computed(() => {
const addressChanged =
javaAddress.value.trim() !== (projectV3.value?.minecraft_java_server?.address ?? '') ||
javaPort.value !== (projectV3.value?.minecraft_java_server?.port ?? 25565)
javaAddress.value.trim() !== (projectV3.value?.minecraft_java_server?.address ?? '')
if (addressChanged) {
return {
address: javaAddress.value.trim(),
port: javaPort.value,
}
}
@@ -410,13 +329,9 @@ const javaServerPatchData = computed(() => {
const bedrockServerPatchData = computed(() => {
const origBedrock = projectV3.value?.minecraft_bedrock_server
if (
bedrockAddress.value !== (origBedrock?.address ?? '') ||
bedrockPort.value !== (origBedrock?.port ?? 19132)
) {
if (bedrockAddress.value !== (origBedrock?.address ?? '')) {
return {
address: bedrockAddress.value.trim(),
port: bedrockPort.value,
}
}
@@ -425,15 +340,15 @@ const bedrockServerPatchData = computed(() => {
const serverPatchData = computed(() => {
const origServer = projectV3.value?.minecraft_server
const countryChanged = country.value && country.value !== origServer?.country
const regionChanged = region.value && region.value !== origServer?.region
const languagesChanged =
JSON.stringify([...languages.value].sort()) !==
JSON.stringify([...(origServer?.languages ?? [])].sort())
if (countryChanged || languagesChanged) {
if (regionChanged || languagesChanged) {
return {
...origServer,
...(countryChanged ? { country: country.value } : {}),
...(regionChanged ? { region: region.value } : {}),
...(languagesChanged ? { languages: languages.value } : {}),
}
}
@@ -459,28 +374,25 @@ const saving = ref(false)
const original = computed(() => ({
javaAddress: projectV3.value?.minecraft_java_server?.address ?? '',
javaPort: projectV3.value?.minecraft_java_server?.port ?? 25565,
bedrockAddress: projectV3.value?.minecraft_bedrock_server?.address ?? '',
bedrockPort: projectV3.value?.minecraft_bedrock_server?.port ?? 19132,
country: projectV3.value?.minecraft_server?.country ?? '',
region: projectV3.value?.minecraft_server?.region ?? '',
languages: projectV3.value?.minecraft_server?.languages ?? [],
}))
const modified = computed(() => ({
javaAddress: javaAddress.value,
javaPort: javaPort.value,
bedrockAddress: bedrockAddress.value,
bedrockPort: bedrockPort.value,
country: country.value,
region: region.value,
languages: languages.value,
}))
function resetChanges() {
javaAddress.value = projectV3.value?.minecraft_java_server?.address ?? ''
javaPort.value = projectV3.value?.minecraft_java_server?.port ?? 25565
bedrockAddress.value = projectV3.value?.minecraft_bedrock_server?.address ?? ''
bedrockPort.value = projectV3.value?.minecraft_bedrock_server?.port ?? 19132
country.value = projectV3.value?.minecraft_server?.country ?? ''
region.value = projectV3.value?.minecraft_server?.region ?? ''
languages.value = projectV3.value?.minecraft_server?.languages ?? []
}

View File

@@ -46,7 +46,6 @@ const selectableProjectTypes = [
label: formatMessage(commonProjectTypeCategoryMessages.server),
href: `/discover/servers`,
type: 'servers',
shown: flags.value.serverDiscovery,
},
]
</script>

View File

@@ -642,6 +642,7 @@ const getServerModpackContent = (hit: Labrinth.Search.v3.ResultSearchProject) =>
'server_category_minecraft_server_meta',
'server_category_minecraft_server_community',
'server_game_version',
'server_status',
].includes(filterType.id)
"
>
@@ -800,7 +801,7 @@ const getServerModpackContent = (hit: Labrinth.Search.v3.ResultSearchProject) =>
project.minecraft_java_server?.ping?.data?.players_online ?? 0
"
:server-recent-plays="project.minecraft_java_server?.verified_plays_2w ?? 0"
:server-region-code="project.minecraft_server?.country"
:server-region="project.minecraft_server?.region"
:server-status-online="!!project.minecraft_java_server?.ping?.data"
:server-modpack-content="getServerModpackContent(project)"
:layout="

View File

@@ -21,7 +21,7 @@ actix-ws = { workspace = true }
arc-swap = { workspace = true }
argon2 = { workspace = true }
ariadne = { workspace = true }
async-minecraft-ping = { workspace = true }
async-minecraft-ping = { workspace = true, features = ["srv"] }
async-stripe = { workspace = true, features = [
"billing",
"checkout",
@@ -44,7 +44,6 @@ deadpool-redis.workspace = true
derive_more = { workspace = true, features = ["deref", "deref_mut"] }
dotenvy = { workspace = true }
either = { workspace = true }
elytra-ping = { workspace = true }
eyre = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }

View File

@@ -172,7 +172,6 @@ pub async fn init_client_with_database(
recorded DateTime64(4),
project_id UInt64,
address String,
port UInt16,
online Bool,
latency_ms Nullable(UInt32),
description Nullable(String),
@@ -219,5 +218,15 @@ pub async fn init_client_with_database(
.execute()
.await?;
client
.query(&format!(
"
ALTER TABLE {database}.{MINECRAFT_JAVA_SERVER_PINGS} {cluster_line}
DROP COLUMN IF EXISTS port
"
))
.execute()
.await?;
Ok(client.with_database(database))
}

View File

@@ -32,6 +32,7 @@ mod tests {
minecraft_server: Some(ServerProject {
max_players: None,
country: None,
region: None,
languages: vec![],
active_version: None,
}),

View File

@@ -101,6 +101,15 @@ component::define! {
#[validate(length(min = 2, max = 2))]
pub country: Option<String>,
#[base(serde(default))]
#[edit(serde(
default,
skip_serializing_if = "Option::is_none",
with = "serde_with::rust::double_option"
))]
#[create(optional)]
/// Geographical region which this server is hosted in.
pub region: Option<ServerRegion>,
#[base(serde(default))]
#[edit(serde(default))]
#[create(default)]
/// Languages which the owners of this server prefer.
@@ -129,11 +138,6 @@ component::define! {
/// Address (IP or domain name) of the Bedrock server, excluding port.
#[validate(length(max = 255))]
pub address: String,
#[base()]
#[edit(serde(default))]
#[create(required)]
/// Port which the server runs on.
pub port: u16,
}
}
@@ -167,8 +171,6 @@ pub struct JavaServerProject {
/// Address (IP or domain name) of the Java server, excluding port.
#[validate(length(max = 255))]
pub address: String,
/// Port which the server runs on.
pub port: u16,
/// What game content this server is using.
#[serde(default)]
pub content: ServerContent,
@@ -180,15 +182,12 @@ pub struct JavaServerProjectEdit {
#[serde(default)]
pub address: Option<String>,
#[serde(default)]
pub port: Option<u16>,
#[serde(default)]
pub content: Option<ServerContent>,
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct JavaServerProjectQuery {
pub address: String,
pub port: u16,
pub content: ServerContentQuery,
pub ping: Option<JavaServerPing>,
pub verified_plays_2w: Option<u64>,
@@ -229,7 +228,6 @@ impl ComponentQuery for JavaServerProjectQuery {
let analytics = context.minecraft_server_analytics.get(&project_id);
Ok(Self {
address: serial.address,
port: serial.port,
content: match serial.content {
ServerContent::Vanilla {
supported_game_versions,
@@ -276,7 +274,6 @@ impl ComponentEdit for JavaServerProjectEdit {
fn create(self) -> Result<Self::Component> {
Ok(JavaServerProject {
address: self.address.wrap_err("missing `address`")?,
port: self.port.wrap_err("missing `port`")?,
content: self.content.unwrap_or_default(),
})
}
@@ -285,9 +282,6 @@ impl ComponentEdit for JavaServerProjectEdit {
if let Some(address) = self.address {
component.address = address;
}
if let Some(port) = self.port {
component.port = port;
}
if let Some(content) = self.content {
component.content = content;
}
@@ -347,6 +341,29 @@ impl Default for ServerContent {
}
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
utoipa::ToSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum ServerRegion {
UsEast,
UsWest,
Europe,
Asia,
Australia,
SouthAmerica,
MiddleEast,
Russia,
}
/// Recorded ping attempt that Labrinth made to a Minecraft Java server project.
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct JavaServerPing {
@@ -354,8 +371,6 @@ pub struct JavaServerPing {
pub when: DateTime<Utc>,
/// Address of the server at the time of the ping.
pub address: String,
/// Port of the server at the time of the ping.
pub port: u16,
/// If the ping was successful, info on the ping response.
pub data: Option<JavaServerPingData>,
}

View File

@@ -15,7 +15,7 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::Semaphore;
use tokio::task::JoinSet;
use tracing::{Instrument, debug, info, info_span, trace, warn};
use tracing::{Instrument, info, info_span, trace, warn};
pub struct ServerPingQueue {
pub db: PgPool,
@@ -44,17 +44,16 @@ impl ServerPingQueue {
let pings = server_projects
.into_iter()
.map(|(project_id, java_server)| {
let address = java_server.address.to_string();
let port = java_server.port;
let span = info_span!("ping", %project_id, %address, %port);
let span = info_span!("ping", %project_id, address = %java_server.address);
let active_pings = active_pings.clone();
let address = java_server.address;
let task = async move {
let _permit = active_pings.acquire().await.expect("semaphore should not be closed now");
let mut retries = ENV.SERVER_PING_RETRIES;
let result = loop {
match ping_server(&address, port, None).await {
match ping_server(&address, None).await {
Ok(ping) => {
info!(?ping, "Received successful ping");
break Ok(ping);
@@ -73,8 +72,7 @@ impl ServerPingQueue {
(project_id, exp::minecraft::JavaServerPing {
when: Utc::now(),
address: address.to_string(),
port,
address,
data: result.ok(),
})
};
@@ -108,7 +106,6 @@ impl ServerPingQueue {
/ 100_000,
project_id: project_id.0,
address: ping.address.clone(),
port: ping.port,
latency_ms: data.map(|d| d.latency.as_millis() as u32),
description: data.map(|d| d.description.clone()),
version_name: data.map(|d| d.version_name.clone()),
@@ -251,7 +248,6 @@ impl ServerPingQueue {
pub async fn ping_server(
address: &str,
port: u16,
timeout: Option<Duration>,
) -> eyre::Result<exp::minecraft::JavaServerPingData> {
let start = Instant::now();
@@ -260,97 +256,45 @@ pub async fn ping_server(
.map(|duration| duration.min(default_duration))
.unwrap_or(default_duration);
let task_ep = async move {
fn map_component(c: elytra_ping::parse::TextComponent) -> String {
match c {
elytra_ping::parse::TextComponent::Plain(t) => t,
elytra_ping::parse::TextComponent::Fancy(t) => {
t.text.unwrap_or_default()
}
elytra_ping::parse::TextComponent::Extra(e) => e
.into_iter()
.map(map_component)
.collect::<Vec<String>>()
.join(""),
}
let (address, port) = match address.rsplit_once(':') {
Some((addr, port)) => {
let port = port.parse::<u16>().wrap_err("invalid port number")?;
(addr, port)
}
None => (address, 25565),
};
let (result, latency) =
elytra_ping::ping_or_timeout((address.to_string(), port), timeout)
.await?;
let task = async move {
let conn = async_minecraft_ping::ConnectionConfig::build(address)
.with_port(port)
.with_srv_lookup()
.connect()
.await
.wrap_err("failed to connect to server")?;
let status = conn
.status()
.await
.wrap_err("failed to get server status")?
.status;
eyre::Ok(exp::minecraft::JavaServerPingData {
latency,
version_name: result
.version
.as_ref()
.map(|v| v.name.to_string())
.unwrap_or_default(),
version_protocol: result
.version
.as_ref()
.map(|v| v.protocol.cast_unsigned())
.unwrap_or_default(),
description: map_component(result.description),
players_online: result
.players
.as_ref()
.map(|p| p.online)
.unwrap_or(0),
players_max: result.players.as_ref().map(|p| p.max).unwrap_or(0),
latency: start.elapsed(),
version_name: status.version.name,
version_protocol: status.version.protocol,
description: match status.description {
ServerDescription::Plain(text)
| ServerDescription::Object { text } => text,
},
players_online: status.players.online,
players_max: status.players.max,
})
};
let task_amp = async move {
let task = async move {
let conn = async_minecraft_ping::ConnectionConfig::build(address)
.with_port(port)
.connect()
.await
.wrap_err("failed to connect to server")?;
let status = conn
.status()
.await
.wrap_err("failed to get server status")?
.status;
eyre::Ok(exp::minecraft::JavaServerPingData {
latency: start.elapsed(),
version_name: status.version.name,
version_protocol: status.version.protocol,
description: match status.description {
ServerDescription::Plain(text)
| ServerDescription::Object { text } => text,
},
players_online: status.players.online,
players_max: status.players.max,
})
};
tokio::time::timeout(timeout, task)
.await
.map_err(eyre::Error::new)
.flatten()
};
async move {
let (result_ep, result_amp) = (task_ep.await, task_amp.await);
let result_ep = result_ep
.inspect(|_| debug!("Successful ping with `elytra_ping`"))
.inspect_err(|err| {
debug!("Failed to ping with `elytra_ping`: {err:#}")
});
let result_amp = result_amp
.inspect(|_| debug!("Successful ping with `async_minecraft_ping`"))
.inspect_err(|err| {
debug!("Failed to ping with `async_minecraft_ping`: {err:#}")
});
result_ep.or(result_amp)
}
.await
tokio::time::timeout(timeout, task)
.await
.map_err(eyre::Error::new)
.flatten()
}
#[derive(Debug, Row, Serialize, Clone)]
@@ -358,7 +302,6 @@ struct ServerPingRecord {
recorded: i64,
project_id: u64,
address: String,
port: u16,
latency_ms: Option<u32>,
description: Option<String>,
version_name: Option<String>,
@@ -373,19 +316,22 @@ mod tests {
#[actix_rt::test]
async fn test_ping_server_success() {
let _status = ping_server("mc.hypixel.net", 25565, None).await.unwrap();
let _status = ping_server("mc.hypixel.net", None).await.unwrap();
}
#[actix_rt::test]
async fn test_follow_srv_record() {
_ = ping_server("hypixel.net", None).await.unwrap();
}
#[actix_rt::test]
async fn test_ping_server_invalid_address() {
_ = ping_server("invalid.invalid", 25565, None)
.await
.unwrap_err();
_ = ping_server("invalid.invalid", None).await.unwrap_err();
}
#[actix_rt::test]
async fn test_ping_zero_timeout() {
_ = ping_server("hypixel.net", 25565, Some(Duration::ZERO))
_ = ping_server("mc.hypixel.net", Some(Duration::ZERO))
.await
.unwrap_err();
}

View File

@@ -19,7 +19,6 @@ pub fn config(cfg: &mut utoipa_actix_web::service_config::ServiceConfig) {
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct PingRequest {
pub address: String,
pub port: u16,
pub timeout_ms: Option<u64>,
}
@@ -42,7 +41,7 @@ pub async fn ping_minecraft_java(
.await?;
let timeout = request.timeout_ms.map(Duration::from_millis);
server_ping::ping_server(&request.address, request.port, timeout)
server_ping::ping_server(&request.address, timeout)
.await
.wrap_request_err("failed to ping server")?;

View File

@@ -646,6 +646,7 @@ const DEFAULT_ATTRIBUTES_FOR_FACETING: &[&str] = &[
"minecraft_java_server.content.supported_game_versions",
"minecraft_java_server.content.recommended_game_version",
"minecraft_java_server.verified_plays_2w",
"minecraft_java_server.ping.data",
"minecraft_java_server.ping.data.players_online",
];

View File

@@ -274,9 +274,9 @@ pub fn get_sort_index(
"relevance" => (
projects_name,
&[
"downloads:desc",
"minecraft_java_server.verified_plays_2w:desc",
"minecraft_java_server.ping.data.players_online:desc",
"downloads:desc",
],
),
"downloads" => (projects_filtered_name, &["downloads:desc"]),