@@ -8,10 +8,15 @@ import { PrismaClient } from '@prisma/client'
8
8
import Logger from './logger.js'
9
9
10
10
import { authError , authResponse , authErrorData } from './interfaces'
11
+ import { EvaluationResult , ModEvaluator , ModLoader , OutGenerator } from 'knockoutcity-mod-loader' ;
12
+ import { createZipFromFolder } from './ziputil' ;
13
+
14
+ import path from 'node:path' ;
15
+ import os from 'node:os' ;
11
16
12
17
const log = new Logger ( ) ;
13
18
14
- if ( config . name == "ServerName" ) log . warn ( "Please change the name in the config.json or via the environment (SERVER_NAME)" ) ;
19
+ if ( config . name == "ServerName" ) log . warn ( "Please change the name in the config.json or via the environment (SERVER_NAME)" ) ;
15
20
16
21
const redis = createClient ( {
17
22
socket : {
@@ -59,18 +64,70 @@ app.get('/stats/status', async (req, res) => {
59
64
} ) ;
60
65
} ) ;
61
66
67
+ const modLoader = new ModLoader ( {
68
+ modDir : config . mod . dirPath ,
69
+ } ) ;
70
+
71
+ const createModZip = async ( modPath : string ) : Promise < Buffer > => {
72
+ const zip = await createZipFromFolder ( modPath ) ;
73
+ return zip . generateAsync ( { type : 'nodebuffer' , compression : 'DEFLATE' } ) ;
74
+ } ;
75
+
76
+ app . get ( '/mods/list' , async ( req , res ) => {
77
+ const mods = modLoader . loadModManifests ( ) ;
78
+
79
+ return res . json (
80
+ await Promise . all (
81
+ mods
82
+ . filter ( ( mod ) => mod . manifest . type === 'server-client' )
83
+ . map ( async ( mod ) => ( {
84
+ name : mod . manifest . name ,
85
+ version : mod . manifest . version ,
86
+ } ) )
87
+ )
88
+ ) ;
89
+ } ) ;
90
+
91
+ app . get ( '/mods/download' , async ( req , res ) => {
92
+ const mods = modLoader . loadMods ( ) ;
93
+ const clientServerMods = mods . filter ( ( mod ) => mod . manifest . type === 'server-client' ) ;
94
+
95
+ if ( clientServerMods . length === 0 ) {
96
+ return res . status ( 400 ) . send ( ) ;
97
+ }
98
+
99
+ const evaluationResults : EvaluationResult [ ] = [ ] ;
100
+ for ( const mod of clientServerMods ) {
101
+ const modEvaluator = new ModEvaluator ( mod , { modsConfigDir : config . mod . configDirPath } ) ;
102
+ evaluationResults . push ( await modEvaluator . evaulate ( ) )
103
+ }
104
+
105
+ const tempDirPath = path . join ( os . tmpdir ( ) , 'generated-mod-output' ) ;
106
+ const outGenerator = new OutGenerator ( { baseDir : tempDirPath } ) ;
107
+ await outGenerator . generate ( evaluationResults ) ;
108
+
109
+ const zipBuffer = await createModZip ( tempDirPath ) ;
110
+ return (
111
+ res
112
+ . header ( 'Content-Disposition' , `attachment; filename="mods.zip"` )
113
+ . contentType ( 'application/zip' )
114
+ . send ( zipBuffer )
115
+ ) ;
116
+ } ) ;
117
+
118
+
62
119
app . use ( async ( req : express . Request , res : express . Response , next : express . NextFunction ) => {
63
120
log . info ( `Request from ${ req . ip } to ${ req . url } ` ) ;
64
121
res . set ( 'X-Powered-By' , 'KoCity Proxy' ) ;
65
122
66
- if ( ! req . body . credentials ) {
123
+ if ( ! req . body . credentials ) {
67
124
log . info ( "No credentials" ) ;
68
125
return next ( ) ;
69
126
}
70
127
71
128
const authkey = req . body . credentials . username
72
129
73
- if ( ! authkey ) {
130
+ if ( ! authkey ) {
74
131
log . info ( "Invalid credentials" ) ;
75
132
return res . status ( 401 ) . send ( "Invalid credentials" ) ;
76
133
}
@@ -80,27 +137,27 @@ app.use(async (req: express.Request, res: express.Response, next: express.NextFu
80
137
server : config . publicAddr
81
138
} ) . catch ( ( err : authError ) : null => {
82
139
res . status ( 401 ) . send ( "Unauthorized" ) ;
83
- if ( err . response ) log . err ( `${ ( err . response . data as authErrorData ) . type } ${ ( err . response . data as authErrorData ) . message } ` ) ;
140
+ if ( err . response ) log . err ( `${ ( err . response . data as authErrorData ) . type } ${ ( err . response . data as authErrorData ) . message } ` ) ;
84
141
else log . err ( err . message ) ;
85
142
return null ;
86
143
} ) ;
87
144
88
- if ( ! response ) return log . info ( "Request denied" ) ;
145
+ if ( ! response ) return log . info ( "Request denied" ) ;
89
146
90
- if ( ! response . data ?. username ) {
147
+ if ( ! response . data ?. username ) {
91
148
log . info ( "Request denied" ) ;
92
149
return res . status ( 401 ) . send ( "Unauthorized" ) ;
93
150
}
94
151
95
- if ( ! response . data . velanID ) {
152
+ if ( ! response . data . velanID ) {
96
153
let localUser = await prisma . users . findFirst ( {
97
154
where : {
98
155
username : response . data . username ,
99
156
}
100
157
} ) ;
101
-
158
+
102
159
let velanID : number | undefined ;
103
- if ( ! localUser ) {
160
+ if ( ! localUser ) {
104
161
const createdUser = await axios . post ( `http://${ config . internal . host } :${ config . internal . port } /api/auth` , {
105
162
credentials : {
106
163
username : response . data . username ,
@@ -124,17 +181,17 @@ app.use(async (req: express.Request, res: express.Response, next: express.NextFu
124
181
velanID
125
182
} ) . catch ( ( err : authError ) : null => {
126
183
res . status ( 401 ) . send ( "Unauthorized" ) ;
127
- if ( err . response ) log . err ( `${ ( err . response . data as authErrorData ) . type } ${ ( err . response . data as authErrorData ) . message } ` ) ;
184
+ if ( err . response ) log . err ( `${ ( err . response . data as authErrorData ) . type } ${ ( err . response . data as authErrorData ) . message } ` ) ;
128
185
else log . err ( err . message ) ;
129
186
return null ;
130
187
} ) ;
131
- if ( ! saved ) return log . info ( "Request denied" ) ;
188
+ if ( ! saved ) return log . info ( "Request denied" ) ;
132
189
133
190
response . data . velanID = velanID ;
134
191
}
135
- if ( ! response . data . velanID ) return log . info ( "Request denied" ) ;
192
+ if ( ! response . data . velanID ) return log . info ( "Request denied" ) ;
136
193
137
- await prisma . users . update ( {
194
+ await prisma . users . update ( {
138
195
where : {
139
196
id : Number ( response . data . velanID )
140
197
} ,
@@ -148,7 +205,7 @@ app.use(async (req: express.Request, res: express.Response, next: express.NextFu
148
205
req . body . credentials . username = `${ response . data . color ? `:${ response . data . color } FF:` : '' } ${ response . data . username } `
149
206
req . headers [ 'content-length' ] = Buffer . byteLength ( JSON . stringify ( req . body ) ) . toString ( ) ;
150
207
next ( ) ;
151
- } )
208
+ } )
152
209
153
210
const proxy = createProxyMiddleware ( {
154
211
target : `http://${ config . internal . host } :${ config . internal . port } ` ,
0 commit comments