Skip to content

Commit 1ab3f4c

Browse files
committed
synthetic server project version for search indexing
1 parent 4a20290 commit 1ab3f4c

7 files changed

Lines changed: 104 additions & 16 deletions

File tree

apps/labrinth/.sqlx/query-702a2826d5857dc51b1a7a79c9043ae8987441bb5e89c9ea62d347e47899e3c2.json renamed to apps/labrinth/.sqlx/query-b760951120c1885530f3fb8208a5874fc472ec160a673abeeee10c778b9cf23f.json

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/labrinth/src/database/models/project_item.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ impl DBProject {
837837
let project_id = DBProjectId(id);
838838
let VersionLoaderData {
839839
loaders,
840-
project_types,
840+
mut project_types,
841841
games,
842842
loader_loader_field_ids,
843843
} = loaders_ptypes_games.remove(&project_id).map(|x|x.1).unwrap_or_default();
@@ -852,6 +852,11 @@ impl DBProject {
852852
.filter(|x| loader_loader_field_ids.contains(&x.id))
853853
.collect::<Vec<_>>();
854854

855+
exp::compat::correct_project_types(
856+
&m.components,
857+
&mut project_types,
858+
);
859+
855860
let project = ProjectQueryResult {
856861
inner: DBProject {
857862
id: DBProjectId(id),
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! Compatibility utilities for V3 API.
2+
3+
use crate::models::exp::ProjectSerial;
4+
5+
const MINECRAFT_JAVA_SERVER: &str = "minecraft_java_server";
6+
7+
/// Adjusts V3 project types based on a project's components.
8+
///
9+
/// The experimental API does not have a concept of project types; instead, a
10+
/// project's "type" is implicit based on what components it has.
11+
/// To reflect this in the V3 API, we manually add `project_types` values
12+
/// for compatibility with stuff like searching.
13+
pub fn correct_project_types(
14+
components: &ProjectSerial,
15+
project_types: &mut Vec<String>,
16+
) {
17+
if components.minecraft_server.is_some() {
18+
project_types.push(MINECRAFT_JAVA_SERVER.into());
19+
}
20+
}

apps/labrinth/src/models/exp/minecraft.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ pub struct JavaServerPing {
190190
/// Ping response data for a Minecraft Java server.
191191
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
192192
pub struct JavaServerPingData {
193-
/// How long it took to ping the server.
193+
/// How long it took for the Labrinth worker to ping the server.
194+
///
195+
/// Note: this is explicitly *not* a client-side ping time, so this should
196+
/// not be used to display to a client how much latency they have to a
197+
/// specific server. This is purely for internal metrics.
194198
pub latency: Duration,
195199
/// Reported version name of the server.
196200
pub version_name: String,

apps/labrinth/src/models/exp/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize};
1818
use validator::Validate;
1919

2020
pub mod base;
21+
pub mod compat;
2122
pub mod component;
2223
pub mod minecraft;
2324

apps/labrinth/src/routes/v3/project_creation/new.rs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ use crate::{
1111
models::{
1212
self, DBOrganization, DBTeamMember, DBUser,
1313
project_item::ProjectBuilder, thread_item::ThreadBuilder,
14+
version_item::VersionBuilder,
1415
},
1516
redis::RedisPool,
1617
},
1718
models::{
1819
exp::{self, ProjectComponentKind, component::ComponentRelationError},
1920
ids::ProjectId,
2021
pats::Scopes,
21-
projects::{MonetizationStatus, ProjectStatus},
22+
projects::{
23+
MonetizationStatus, ProjectStatus, VersionStatus, VersionType,
24+
},
2225
teams::{OrganizationPermissions, ProjectPermissions},
2326
threads::ThreadType,
2427
v3::user_limits::UserLimits,
@@ -233,12 +236,44 @@ pub async fn create(
233236
.wrap_internal_err("failed to generate project ID")?
234237
.into();
235238

236-
// TODO: special-case server projects to be unmonetized
237-
let monetization_status = if details.minecraft_server.is_some() {
238-
MonetizationStatus::ForceDemonetized
239-
} else {
240-
MonetizationStatus::Monetized
241-
};
239+
// TODO: special casing certain components
240+
let mut monetization_status = MonetizationStatus::Monetized;
241+
let mut version_builder = None::<VersionBuilder>;
242+
243+
if details.minecraft_server.is_some() {
244+
// servers are not part of the monetization pool;
245+
// they generate no payouts for their owners
246+
monetization_status = MonetizationStatus::ForceDemonetized;
247+
248+
// servers may never have a version added, if e.g. they are a vanilla server
249+
// but we need at least 1 version on this project for certain features,
250+
// like search indexing, to work.
251+
// so we generate a synthetic initial version.
252+
let version_id = models::generate_version_id(&mut txn)
253+
.await
254+
.wrap_internal_err("failed to generate project ID")?;
255+
version_builder = Some(VersionBuilder {
256+
version_id,
257+
project_id: project_id.into(),
258+
author_id: user.id.into(),
259+
name: "__synthetic".into(),
260+
version_number: String::new(),
261+
changelog: String::new(),
262+
files: Vec::new(),
263+
dependencies: Vec::new(),
264+
loaders: Vec::new(),
265+
version_fields: Vec::new(),
266+
version_type: VersionType::Release.to_string(),
267+
featured: false,
268+
status: VersionStatus::Listed,
269+
requested_status: None,
270+
ordering: None,
271+
components: exp::VersionCreate {
272+
base: None,
273+
minecraft_java_server: None,
274+
},
275+
});
276+
}
242277

243278
let project_builder = ProjectBuilder {
244279
project_id: project_id.into(),
@@ -268,6 +303,14 @@ pub async fn create(
268303
.insert(&mut txn)
269304
.await
270305
.wrap_internal_err("failed to insert project")?;
306+
307+
if let Some(version_builder) = version_builder {
308+
version_builder
309+
.insert(&mut txn)
310+
.await
311+
.wrap_internal_err("failed to insert initial version")?;
312+
}
313+
271314
DBUser::clear_project_cache(&[user.id.into()], &redis)
272315
.await
273316
.wrap_internal_err("failed to clear user project cache")?;

apps/labrinth/src/search/indexing/local_import.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::database::models::{
1515
DBProjectId, DBVersionId, LoaderFieldEnumId, LoaderFieldEnumValueId,
1616
LoaderFieldId,
1717
};
18+
use crate::models::exp;
1819
use crate::models::projects::from_duplicate_version_fields;
1920
use crate::models::v2::projects::LegacyProject;
2021
use crate::routes::v2_reroute;
@@ -40,18 +41,20 @@ pub async fn index_local(
4041
slug: Option<String>,
4142
color: Option<i32>,
4243
license: String,
44+
components: exp::ProjectSerial,
4345
}
4446

4547
let db_projects = sqlx::query!(
46-
"
48+
r#"
4749
SELECT m.id id, m.name name, m.summary summary, m.downloads downloads, m.follows follows,
48-
m.icon_url icon_url, m.updated updated, m.approved approved, m.published, m.license license, m.slug slug, m.color
50+
m.icon_url icon_url, m.updated updated, m.approved approved, m.published, m.license license, m.slug slug, m.color,
51+
m.components AS "components: sqlx::types::Json<exp::ProjectSerial>"
4952
FROM mods m
5053
WHERE m.status = ANY($1) AND m.id > $3
5154
GROUP BY m.id
5255
ORDER BY m.id ASC
5356
LIMIT $2;
54-
",
57+
"#,
5558
&*crate::models::projects::ProjectStatus::iterator()
5659
.filter(|x| x.is_searchable())
5760
.map(|x| x.to_string())
@@ -73,6 +76,7 @@ pub async fn index_local(
7376
slug: m.slug,
7477
color: m.color,
7578
license: m.license,
79+
components: m.components.0,
7680
}
7781
})
7882
.try_collect::<Vec<PartialProject>>()
@@ -336,7 +340,12 @@ pub async fn index_local(
336340
.collect();
337341
let mut loader_fields =
338342
from_duplicate_version_fields(version_fields);
339-
let project_types = version.project_types;
343+
let mut project_types = version.project_types;
344+
345+
exp::compat::correct_project_types(
346+
&project.components,
347+
&mut project_types,
348+
);
340349

341350
let mut version_loaders = version.loaders;
342351

0 commit comments

Comments
 (0)