@@ -8,13 +8,20 @@ use axum::{
8
8
Extension , Router ,
9
9
} ;
10
10
use custom_error:: custom_error;
11
- use libmcmeta:: models:: mojang:: MojangVersionManifest ;
12
- use serde:: Deserialize ;
11
+ use libmcmeta:: models:: {
12
+ forge:: {
13
+ ForgeInstallerManifestVersion , ForgeMavenMetadata , ForgeMavenPromotions , ForgeVersion ,
14
+ ForgeVersionMeta ,
15
+ } ,
16
+ mojang:: { MinecraftVersion , MojangVersionManifest } ,
17
+ } ;
18
+ use serde:: { Deserialize , Serialize } ;
13
19
use serde_json:: json;
14
- use tracing:: info;
20
+ use tracing:: { debug , info} ;
15
21
16
22
mod app_config;
17
23
mod download;
24
+ mod storage;
18
25
19
26
custom_error ! { pub MetaMCError
20
27
MojangMetadata { source: download:: mojang:: MojangMetadataError } = "Error while downloading Mojang metadata: {source}" ,
@@ -25,80 +32,10 @@ custom_error! {pub MetaMCError
25
32
Json { source: serde_json:: Error } = "Error while serializing or deserializing JSON: {source}" ,
26
33
}
27
34
28
- impl StorageFormat {
29
- pub async fn initialize_metadata ( & self ) -> Result < ( ) , MetaMCError > {
30
- match self {
31
- app_config:: StorageFormat :: Json { meta_directory } => {
32
- let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
33
- if !metadata_dir. exists ( ) {
34
- info ! (
35
- "Metadata directory at {} does not exist, creating it" ,
36
- meta_directory
37
- ) ;
38
- std:: fs:: create_dir_all ( metadata_dir) ?;
39
- }
40
-
41
- self . initialize_mojang_metadata ( ) . await ?;
42
- }
43
- app_config:: StorageFormat :: Database => todo ! ( ) ,
44
- }
45
-
46
- Ok ( ( ) )
47
- }
48
-
49
- pub async fn initialize_mojang_metadata ( & self ) -> Result < ( ) , MetaMCError > {
50
- match self {
51
- StorageFormat :: Json { meta_directory } => {
52
- info ! ( "Checking for Mojang metadata" ) ;
53
- let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
54
- let mojang_meta_dir = metadata_dir. join ( "mojang" ) ;
55
-
56
- if !mojang_meta_dir. exists ( ) {
57
- info ! (
58
- "Mojang metadata directory at {} does not exist, creating it" ,
59
- mojang_meta_dir. display( )
60
- ) ;
61
- std:: fs:: create_dir_all ( & mojang_meta_dir) ?;
62
- }
63
-
64
- let local_manifest = mojang_meta_dir. join ( "version_manifest_v2.json" ) ;
65
- if !local_manifest. exists ( ) {
66
- info ! ( "Mojang metadata does not exist, downloading it" ) ;
67
- let manifest = download:: mojang:: load_manifest ( ) . await ?;
68
- let manifest_json = serde_json:: to_string_pretty ( & manifest) ?;
69
- std:: fs:: write ( & local_manifest, manifest_json) ?;
70
- }
71
- let manifest = serde_json:: from_str :: < MojangVersionManifest > (
72
- & std:: fs:: read_to_string ( & local_manifest) ?,
73
- ) ?;
74
- let versions_dir = mojang_meta_dir. join ( "versions" ) ;
75
- if !versions_dir. exists ( ) {
76
- info ! (
77
- "Mojang versions directory at {} does not exist, creating it" ,
78
- versions_dir. display( )
79
- ) ;
80
- std:: fs:: create_dir_all ( & versions_dir) ?;
81
- }
82
- for version in & manifest. versions {
83
- let version_file = versions_dir. join ( format ! ( "{}.json" , & version. id) ) ;
84
- if !version_file. exists ( ) {
85
- info ! (
86
- "Mojang metadata for version {} does not exist, downloading it" ,
87
- & version. id
88
- ) ;
89
- let version_manifest =
90
- download:: mojang:: load_version_manifest ( & version. url ) . await ?;
91
- let version_manifest_json =
92
- serde_json:: to_string_pretty ( & version_manifest) ?;
93
- std:: fs:: write ( & version_file, version_manifest_json) ?;
94
- }
95
- }
96
- }
97
- StorageFormat :: Database => todo ! ( ) ,
98
- }
99
-
100
- Ok ( ( ) )
101
- }
35
+ #[ derive( Serialize , Debug , Clone ) ]
36
+ pub struct APIResponse < T > {
37
+ pub data : Option < T > ,
38
+ pub error : Option < String > ,
102
39
}
103
40
104
41
async fn raw_mojang_manifest ( config : Extension < Arc < ServerConfig > > ) -> impl IntoResponse {
@@ -112,7 +49,10 @@ async fn raw_mojang_manifest(config: Extension<Arc<ServerConfig>>) -> impl IntoR
112
49
)
113
50
. unwrap ( ) ;
114
51
115
- axum:: Json ( manifest)
52
+ axum:: Json ( APIResponse {
53
+ data : Some ( manifest) ,
54
+ error : None ,
55
+ } )
116
56
}
117
57
app_config:: StorageFormat :: Database => todo ! ( ) ,
118
58
}
@@ -131,15 +71,178 @@ async fn raw_mojang_version(
131
71
if !version_file. exists ( ) {
132
72
return (
133
73
axum:: http:: StatusCode :: NOT_FOUND ,
134
- axum:: Json ( json ! ( "Version not found" ) ) ,
74
+ axum:: Json ( APIResponse {
75
+ data : None ,
76
+ error : Some ( format ! ( "Version {} does not exist" , version) ) ,
77
+ } ) ,
135
78
) ;
136
79
}
137
- let manifest = serde_json:: from_str :: < serde_json :: Value > (
80
+ let manifest = serde_json:: from_str :: < MinecraftVersion > (
138
81
& std:: fs:: read_to_string ( & version_file) . unwrap ( ) ,
139
82
)
140
83
. unwrap ( ) ;
141
84
142
- ( axum:: http:: StatusCode :: OK , axum:: Json ( manifest) )
85
+ (
86
+ axum:: http:: StatusCode :: OK ,
87
+ axum:: Json ( APIResponse {
88
+ data : Some ( manifest) ,
89
+ error : None ,
90
+ } ) ,
91
+ )
92
+ }
93
+ StorageFormat :: Database => todo ! ( ) ,
94
+ }
95
+ }
96
+
97
+ async fn raw_forge_maven_meta ( config : Extension < Arc < ServerConfig > > ) -> impl IntoResponse {
98
+ match & config. storage_format {
99
+ StorageFormat :: Json { meta_directory } => {
100
+ let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
101
+ let forge_meta_dir = metadata_dir. join ( "forge" ) ;
102
+ let maven_meta_file = forge_meta_dir. join ( "maven-metadata.json" ) ;
103
+ let manifest = serde_json:: from_str :: < ForgeMavenMetadata > (
104
+ & std:: fs:: read_to_string ( & maven_meta_file) . unwrap ( ) ,
105
+ )
106
+ . unwrap ( ) ;
107
+
108
+ (
109
+ axum:: http:: StatusCode :: OK ,
110
+ axum:: Json ( APIResponse {
111
+ data : Some ( manifest) ,
112
+ error : None ,
113
+ } ) ,
114
+ )
115
+ }
116
+ StorageFormat :: Database => todo ! ( ) ,
117
+ }
118
+ }
119
+
120
+ async fn raw_forge_promotions ( config : Extension < Arc < ServerConfig > > ) -> impl IntoResponse {
121
+ match & config. storage_format {
122
+ StorageFormat :: Json { meta_directory } => {
123
+ let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
124
+ let forge_meta_dir = metadata_dir. join ( "forge" ) ;
125
+ let promotions_file = forge_meta_dir. join ( "promotions_slim.json" ) ;
126
+ let manifest = serde_json:: from_str :: < ForgeMavenPromotions > (
127
+ & std:: fs:: read_to_string ( & promotions_file) . unwrap ( ) ,
128
+ )
129
+ . unwrap ( ) ;
130
+
131
+ (
132
+ axum:: http:: StatusCode :: OK ,
133
+ axum:: Json ( APIResponse {
134
+ data : Some ( manifest) ,
135
+ error : None ,
136
+ } ) ,
137
+ )
138
+ }
139
+ StorageFormat :: Database => todo ! ( ) ,
140
+ }
141
+ }
142
+
143
+ async fn raw_forge_version (
144
+ config : Extension < Arc < ServerConfig > > ,
145
+ Path ( version) : Path < String > ,
146
+ ) -> impl IntoResponse {
147
+ match & config. storage_format {
148
+ StorageFormat :: Json { meta_directory } => {
149
+ let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
150
+ let forge_meta_dir = metadata_dir. join ( "forge" ) ;
151
+ let versions_dir = forge_meta_dir. join ( "version_manifests" ) ;
152
+ let version_file = versions_dir. join ( format ! ( "{}.json" , version) ) ;
153
+ if !version_file. exists ( ) {
154
+ return (
155
+ axum:: http:: StatusCode :: NOT_FOUND ,
156
+ axum:: Json ( APIResponse {
157
+ data : None ,
158
+ error : Some ( format ! ( "Version {} does not exist" , version) ) ,
159
+ } ) ,
160
+ ) ;
161
+ }
162
+ let manifest = serde_json:: from_str :: < ForgeVersion > (
163
+ & std:: fs:: read_to_string ( & version_file) . unwrap ( ) ,
164
+ )
165
+ . unwrap ( ) ;
166
+
167
+ (
168
+ axum:: http:: StatusCode :: OK ,
169
+ axum:: Json ( APIResponse {
170
+ data : Some ( manifest) ,
171
+ error : None ,
172
+ } ) ,
173
+ )
174
+ }
175
+ StorageFormat :: Database => todo ! ( ) ,
176
+ }
177
+ }
178
+
179
+ async fn raw_forge_version_meta (
180
+ config : Extension < Arc < ServerConfig > > ,
181
+ Path ( version) : Path < String > ,
182
+ ) -> impl IntoResponse {
183
+ match & config. storage_format {
184
+ StorageFormat :: Json { meta_directory } => {
185
+ let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
186
+ let forge_meta_dir = metadata_dir. join ( "forge" ) ;
187
+ let versions_dir = forge_meta_dir. join ( "files_manifests" ) ;
188
+ let version_file = versions_dir. join ( format ! ( "{}.json" , version) ) ;
189
+ if !version_file. exists ( ) {
190
+ return (
191
+ axum:: http:: StatusCode :: NOT_FOUND ,
192
+ axum:: Json ( APIResponse {
193
+ data : None ,
194
+ error : Some ( format ! ( "Version {} does not exist" , version) ) ,
195
+ } ) ,
196
+ ) ;
197
+ }
198
+ let manifest = serde_json:: from_str :: < ForgeVersionMeta > (
199
+ & std:: fs:: read_to_string ( & version_file) . unwrap ( ) ,
200
+ )
201
+ . unwrap ( ) ;
202
+
203
+ (
204
+ axum:: http:: StatusCode :: OK ,
205
+ axum:: Json ( APIResponse {
206
+ data : Some ( manifest) ,
207
+ error : None ,
208
+ } ) ,
209
+ )
210
+ }
211
+ StorageFormat :: Database => todo ! ( ) ,
212
+ }
213
+ }
214
+
215
+ async fn raw_forge_version_installer (
216
+ config : Extension < Arc < ServerConfig > > ,
217
+ Path ( version) : Path < String > ,
218
+ ) -> impl IntoResponse {
219
+ match & config. storage_format {
220
+ StorageFormat :: Json { meta_directory } => {
221
+ let metadata_dir = std:: path:: Path :: new ( meta_directory) ;
222
+ let forge_meta_dir = metadata_dir. join ( "forge" ) ;
223
+ let versions_dir = forge_meta_dir. join ( "installer_manifests" ) ;
224
+ let version_file = versions_dir. join ( format ! ( "{}.json" , version) ) ;
225
+ if !version_file. exists ( ) {
226
+ return (
227
+ axum:: http:: StatusCode :: NOT_FOUND ,
228
+ axum:: Json ( APIResponse {
229
+ data : None ,
230
+ error : Some ( format ! ( "Version {} does not exist" , version) ) ,
231
+ } ) ,
232
+ ) ;
233
+ }
234
+ let manifest = serde_json:: from_str :: < ForgeInstallerManifestVersion > (
235
+ & std:: fs:: read_to_string ( & version_file) . unwrap ( ) ,
236
+ )
237
+ . unwrap ( ) ;
238
+
239
+ (
240
+ axum:: http:: StatusCode :: OK ,
241
+ axum:: Json ( APIResponse {
242
+ data : Some ( manifest) ,
243
+ error : None ,
244
+ } ) ,
245
+ )
143
246
}
144
247
StorageFormat :: Database => todo ! ( ) ,
145
248
}
@@ -149,14 +252,23 @@ async fn raw_mojang_version(
149
252
async fn main ( ) -> Result < ( ) , MetaMCError > {
150
253
tracing_subscriber:: fmt:: init ( ) ;
151
254
let config = Arc :: new ( ServerConfig :: from_config ( ) ?) ;
255
+ debug ! ( "Config: {:#?}" , config) ;
152
256
153
257
config. storage_format . initialize_metadata ( ) . await ?;
154
258
155
259
let raw_mojang_routes = Router :: new ( )
156
260
. route ( "/" , get ( raw_mojang_manifest) )
157
261
. route ( "/:version" , get ( raw_mojang_version) ) ;
262
+ let raw_forge_routes = Router :: new ( )
263
+ . route ( "/" , get ( raw_forge_maven_meta) )
264
+ . route ( "/promotions" , get ( raw_forge_promotions) )
265
+ . route ( "/:version" , get ( raw_forge_version) )
266
+ . route ( "/:version/meta" , get ( raw_forge_version_meta) )
267
+ . route ( "/:version/installer" , get ( raw_forge_version_installer) ) ;
158
268
159
- let raw_routes = Router :: new ( ) . nest ( "/mojang" , raw_mojang_routes) ;
269
+ let raw_routes = Router :: new ( )
270
+ . nest ( "/mojang" , raw_mojang_routes)
271
+ . nest ( "/forge" , raw_forge_routes) ;
160
272
161
273
let http = Router :: new ( )
162
274
. nest ( "/raw" , raw_routes)
0 commit comments