Skip to content

Commit 5fa8b72

Browse files
authored
Merge pull request #20 from geode-sdk/unlisted-mods
Unlisted mods
2 parents a8b3f95 + e4419d0 commit 5fa8b72

10 files changed

+335
-143
lines changed

.sqlx/query-159785d4a225f320a514c42f4f5c6140e25272a5c6838135a5ebbd306da5d471.json

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-7b359410b3aa72262d162f0eb3d154fcd26368c7b59478f240235b8a49a4e61e.json

-22
This file was deleted.

.sqlx/query-4abc4f3d4ecd6ccb07948086234a24bceacc1c2516b3a524b19b68dc871805bd.json renamed to .sqlx/query-8766c857a28fd2da53b8cc0182c2d810f6aaf5ecf31fe6099e08400ecc9a3045.json

+4-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-b20b4b54a01407e33d467b1704b8cf28e81735de37096b319e5d91f31a917526.json

-23
This file was deleted.

openapi.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ paths:
207207
tags:
208208
- mods
209209
summary: Get info for a mod
210-
description: Returns info for the mod, without dependencies and incompatibilities
210+
description: Returns info for the mod, without dependencies and incompatibilities.
211211
parameters:
212212
- $ref: "#/components/parameters/ModID"
213213
responses:
@@ -281,14 +281,13 @@ paths:
281281
tags:
282282
- mods
283283
summary: Get info for the latest version of a mod
284-
description: Returns info for the current latest version of the mod
284+
description: Returns info for the current latest approved version of the mod
285285
parameters:
286286
- $ref: "#/components/parameters/ModID"
287287
- $ref: "#/components/parameters/Platforms"
288288
- name: gd
289289
in: query
290290
description: Geometry Dash version
291-
required: true
292291
schema:
293292
$ref: "#/components/schemas/GDVersionString"
294293

@@ -410,7 +409,7 @@ paths:
410409
get:
411410
tags:
412411
- mods
413-
summary: Download the latest version of a mod
412+
summary: Download the latest available version of a mod
414413
parameters:
415414
- $ref: "#/components/parameters/ModID"
416415
responses:

src/endpoints/mod_versions.rs

+88-25
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ use crate::{
1414
download,
1515
mod_entity::{download_geode_file, Mod},
1616
mod_gd_version::{GDVersionEnum, VerPlatform},
17-
mod_version::ModVersion,
17+
mod_version::{self, ModVersion},
1818
mod_version_status::ModVersionStatusEnum,
1919
},
2020
},
2121
AppData,
2222
};
2323

24+
#[derive(Deserialize)]
25+
struct IndexPath {
26+
id: String,
27+
}
28+
2429
#[derive(Deserialize)]
2530
pub struct GetOnePath {
2631
id: String,
@@ -56,6 +61,46 @@ struct GetOneQuery {
5661
major: Option<u32>,
5762
}
5863

64+
#[derive(Deserialize)]
65+
struct IndexQuery {
66+
page: Option<i64>,
67+
per_page: Option<i64>,
68+
#[serde(default)]
69+
gd: Option<GDVersionEnum>,
70+
platforms: Option<String>,
71+
status: Option<ModVersionStatusEnum>,
72+
}
73+
74+
#[get("v1/mods/{id}/versions")]
75+
pub async fn get_version_index(
76+
path: web::Path<IndexPath>,
77+
data: web::Data<AppData>,
78+
query: web::Query<IndexQuery>,
79+
) -> Result<impl Responder, ApiError> {
80+
let platforms = VerPlatform::parse_query_string(&query.platforms.clone().unwrap_or_default());
81+
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
82+
let mut result = ModVersion::get_index(
83+
mod_version::IndexQuery {
84+
mod_id: path.id.clone(),
85+
page: query.page.unwrap_or(1),
86+
per_page: query.per_page.unwrap_or(10),
87+
gd: query.gd,
88+
platforms,
89+
status: query.status.unwrap_or(ModVersionStatusEnum::Accepted),
90+
},
91+
&mut pool,
92+
)
93+
.await?;
94+
for i in &mut result.data {
95+
i.modify_download_link(&data.app_url);
96+
}
97+
98+
Ok(web::Json(ApiResponse {
99+
payload: result,
100+
error: "".to_string(),
101+
}))
102+
}
103+
59104
#[get("v1/mods/{id}/versions/{version}")]
60105
pub async fn get_one(
61106
path: web::Path<GetOnePath>,
@@ -74,29 +119,12 @@ pub async fn get_one(
74119
None => None,
75120
};
76121

77-
let mut platforms: Vec<VerPlatform> = vec![];
78-
79-
if let Some(p) = &query.platforms {
80-
for x in p.split(',') {
81-
match VerPlatform::from_str(x) {
82-
Ok(v) => {
83-
if v == VerPlatform::Android {
84-
platforms.push(VerPlatform::Android32);
85-
platforms.push(VerPlatform::Android64);
86-
} else {
87-
platforms.push(v);
88-
}
89-
}
90-
Err(_) => {
91-
return Err(ApiError::BadRequest("Invalid platform".to_string()));
92-
}
93-
}
94-
}
95-
};
122+
let platform_string = query.platforms.clone().unwrap_or_default();
123+
let platforms = VerPlatform::parse_query_string(&platform_string);
96124

97125
ModVersion::get_latest_for_mod(&path.id, gd, platforms, query.major, &mut pool).await?
98126
} else {
99-
ModVersion::get_one(&path.id, &path.version, true, &mut pool).await?
127+
ModVersion::get_one(&path.id, &path.version, true, false, &mut pool).await?
100128
}
101129
};
102130

@@ -107,15 +135,33 @@ pub async fn get_one(
107135
}))
108136
}
109137

138+
#[derive(Deserialize)]
139+
struct DownloadQuery {
140+
gd: Option<GDVersionEnum>,
141+
// platform1,platform2,...
142+
platforms: Option<String>,
143+
major: Option<u32>,
144+
}
145+
110146
#[get("v1/mods/{id}/versions/{version}/download")]
111147
pub async fn download_version(
112148
path: web::Path<GetOnePath>,
113149
data: web::Data<AppData>,
150+
query: web::Query<DownloadQuery>,
114151
info: ConnectionInfo,
115152
) -> Result<impl Responder, ApiError> {
116153
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
117-
let mod_version = ModVersion::get_one(&path.id, &path.version, false, &mut pool).await?;
118-
let url = ModVersion::get_download_url(&path.id, &path.version, &mut pool).await?;
154+
let mod_version = {
155+
if path.version == "latest" {
156+
let platform_str = query.platforms.clone().unwrap_or_default();
157+
let platforms = VerPlatform::parse_query_string(&platform_str);
158+
ModVersion::get_latest_for_mod(&path.id, query.gd, platforms, query.major, &mut pool)
159+
.await?
160+
} else {
161+
ModVersion::get_one(&path.id, &path.version, false, false, &mut pool).await?
162+
}
163+
};
164+
let url = mod_version.download_link;
119165

120166
let ip = match info.realip_remote_addr() {
121167
None => return Err(ApiError::InternalError),
@@ -124,8 +170,25 @@ pub async fn download_version(
124170
let net: IpNetwork = ip.parse().or(Err(ApiError::InternalError))?;
125171

126172
if download::create_download(net, mod_version.id, &mut pool).await? {
127-
ModVersion::calculate_cached_downloads(mod_version.id, &mut pool).await?;
128-
Mod::calculate_cached_downloads(&mod_version.mod_id, &mut pool).await?;
173+
let name = mod_version.mod_id.clone();
174+
let version = mod_version.version.clone();
175+
tokio::spawn(async move {
176+
if let Err(e) = ModVersion::calculate_cached_downloads(mod_version.id, &mut pool).await
177+
{
178+
log::error!(
179+
"Failed to calculate cached downloads for mod version {}. Error: {}",
180+
version,
181+
e
182+
);
183+
}
184+
if let Err(e) = Mod::calculate_cached_downloads(&mod_version.mod_id, &mut pool).await {
185+
log::error!(
186+
"Failed to calculate cached downloads for mod {}. Error: {}",
187+
name,
188+
e
189+
);
190+
}
191+
});
129192
}
130193

131194
Ok(HttpResponse::Found()

src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ async fn main() -> anyhow::Result<()> {
9999
.service(endpoints::mods::create)
100100
.service(endpoints::mods::update_mod)
101101
.service(endpoints::mods::get_logo)
102+
.service(endpoints::mod_versions::get_version_index)
102103
.service(endpoints::mod_versions::get_one)
103104
.service(endpoints::mod_versions::download_version)
104105
.service(endpoints::mod_versions::create_version)

src/types/models/mod_entity.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -690,11 +690,16 @@ impl Mod {
690690
id: &str,
691691
pool: &mut PgConnection,
692692
) -> Result<Option<Vec<u8>>, ApiError> {
693-
match sqlx::query!(
694-
"SELECT DISTINCT m.image FROM mods m
695-
INNER JOIN mod_versions mv ON mv.mod_id = m.id
696-
INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id
697-
WHERE m.id = $1 AND mvs.status = 'accepted'",
693+
struct QueryResult {
694+
image: Option<Vec<u8>>
695+
}
696+
match sqlx::query_as!(
697+
QueryResult,
698+
"SELECT m.image
699+
FROM mods m
700+
INNER JOIN mod_versions mv ON mv.mod_id = m.id
701+
INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id
702+
WHERE m.id = $1",
698703
id
699704
)
700705
.fetch_optional(&mut *pool)
@@ -704,10 +709,8 @@ impl Mod {
704709
log::error!("{}", e);
705710
Err(ApiError::DbError)
706711
}
707-
Ok(r) => match r {
708-
Some(r) => Ok(r.image),
709-
None => Ok(None),
710-
},
712+
Ok(Some(r)) => Ok(r.image),
713+
Ok(None) => Ok(None)
711714
}
712715
}
713716

src/types/models/mod_gd_version.rs

+29
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ pub enum GDVersionEnum {
2626
#[serde(rename = "2.205")]
2727
#[sqlx(rename = "2.205")]
2828
GD2205,
29+
#[serde(rename = "2.206")]
30+
#[sqlx(rename = "2.206")]
31+
GD2206,
2932
}
3033

3134
impl FromStr for GDVersionEnum {
@@ -74,6 +77,32 @@ impl FromStr for VerPlatform {
7477
}
7578
}
7679

80+
impl VerPlatform {
81+
pub fn parse_query_string(s: &str) -> Vec<VerPlatform> {
82+
let mut ret = vec![];
83+
if s.is_empty() {
84+
return ret;
85+
}
86+
87+
for x in s.split(',') {
88+
match VerPlatform::from_str(x) {
89+
Ok(v) => {
90+
if v == VerPlatform::Android {
91+
ret.push(VerPlatform::Android32);
92+
ret.push(VerPlatform::Android64);
93+
} else {
94+
ret.push(v);
95+
}
96+
}
97+
Err(_) => {
98+
log::error!("invalid platform {}", x);
99+
}
100+
}
101+
}
102+
ret
103+
}
104+
}
105+
77106
#[derive(sqlx::FromRow, Clone, Copy, Debug, Serialize)]
78107
pub struct ModGDVersion {
79108
id: i32,

0 commit comments

Comments
 (0)