@minecraft-docker/mcctl-api 1.10.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +2 -0
- package/dist/app.js.map +1 -1
- package/dist/routes/servers/actions.d.ts.map +1 -1
- package/dist/routes/servers/actions.js +30 -0
- package/dist/routes/servers/actions.js.map +1 -1
- package/dist/routes/servers/config.d.ts +10 -0
- package/dist/routes/servers/config.d.ts.map +1 -0
- package/dist/routes/servers/config.js +208 -0
- package/dist/routes/servers/config.js.map +1 -0
- package/dist/routes/servers.d.ts.map +1 -1
- package/dist/routes/servers.js +184 -42
- package/dist/routes/servers.js.map +1 -1
- package/dist/schemas/audit-log.d.ts +4 -4
- package/dist/schemas/audit-log.js +1 -1
- package/dist/schemas/audit-log.js.map +1 -1
- package/dist/schemas/config.d.ts +88 -0
- package/dist/schemas/config.d.ts.map +1 -0
- package/dist/schemas/config.js +78 -0
- package/dist/schemas/config.js.map +1 -0
- package/dist/services/ConfigService.d.ts +38 -0
- package/dist/services/ConfigService.d.ts.map +1 -0
- package/dist/services/ConfigService.js +247 -0
- package/dist/services/ConfigService.js.map +1 -0
- package/dist/services/audit-log-service.d.ts +5 -1
- package/dist/services/audit-log-service.d.ts.map +1 -1
- package/dist/services/audit-log-service.js +22 -1
- package/dist/services/audit-log-service.js.map +1 -1
- package/package.json +2 -2
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAiBnD,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAoFtF;AAED,eAAe,QAAQ,CAAC"}
|
package/dist/app.js
CHANGED
|
@@ -6,6 +6,7 @@ import authPlugin from './plugins/auth.js';
|
|
|
6
6
|
import swaggerPlugin from './plugins/swagger.js';
|
|
7
7
|
import serversRoutes from './routes/servers.js';
|
|
8
8
|
import serverActionsRoutes from './routes/servers/actions.js';
|
|
9
|
+
import serverConfigRoutes from './routes/servers/config.js';
|
|
9
10
|
import consoleRoutes from './routes/console.js';
|
|
10
11
|
import worldsRoutes from './routes/worlds.js';
|
|
11
12
|
import authRoutes from './routes/auth.js';
|
|
@@ -45,6 +46,7 @@ export async function buildApp(options = {}) {
|
|
|
45
46
|
// Register server routes
|
|
46
47
|
await app.register(serversRoutes);
|
|
47
48
|
await app.register(serverActionsRoutes);
|
|
49
|
+
await app.register(serverConfigRoutes);
|
|
48
50
|
// Register router routes
|
|
49
51
|
await app.register(routerRoutes);
|
|
50
52
|
// Register player routes
|
package/dist/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAA4B,MAAM,SAAS,CAAC;AACnD,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,aAAa,MAAM,sBAAsB,CAAC;AACjD,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAC9D,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,eAAe,MAAM,wBAAwB,CAAC;AAMrD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAA2B,EAAE;IAC1D,MAAM,GAAG,GAAG,OAAO,CAAC;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC;YACpD,KAAK,EAAE,MAAM,CAAC,QAAQ;SACvB,CAAC,CAAC,CAAC,KAAK;KACV,CAAC,CAAC;IAEH,oCAAoC;IACpC,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;QACvB,MAAM,EAAE,GAAG;KACZ,CAAC,CAAC;IAEH,wEAAwE;IACxE,IAAI,MAAM,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;QACpC,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE;YACzB,qBAAqB,EAAE,IAAI;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,iCAAiC;IACjC,MAAM,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE;QAC7B,MAAM,EAAE,MAAM,CAAC,IAAI;KACpB,CAAC,CAAC;IAEH,mFAAmF;IACnF,IAAI,MAAM,CAAC,OAAO,KAAK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,MAAM,EAAE,CAAC;QACjF,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,EAAE;YAChC,KAAK,EAAE,WAAW;YAClB,WAAW,EAAE,gDAAgD;YAC7D,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,OAAO;SACrB,CAAC,CAAC;IACL,CAAC;IAED,yBAAyB;IACzB,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAClC,MAAM,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/routes/servers/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/routes/servers/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AA8G5F,QAAA,MAAM,mBAAmB,EAAE,kBAwB1B,CAAC;;AAMF,wBAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import fp from 'fastify-plugin';
|
|
2
2
|
import { isValidServerName, sanitizeServerName, executeServerAction, } from '../../utils/docker-compose.js';
|
|
3
|
+
import { writeAuditLog } from '../../services/audit-log-service.js';
|
|
4
|
+
import { AuditActionEnum } from '@minecraft-docker/shared';
|
|
3
5
|
// ============================================================
|
|
4
6
|
// Route Handlers
|
|
5
7
|
// ============================================================
|
|
8
|
+
/**
|
|
9
|
+
* Map server action to audit action enum
|
|
10
|
+
*/
|
|
11
|
+
function toAuditAction(action) {
|
|
12
|
+
switch (action) {
|
|
13
|
+
case 'start': return AuditActionEnum.SERVER_START;
|
|
14
|
+
case 'stop': return AuditActionEnum.SERVER_STOP;
|
|
15
|
+
case 'restart': return AuditActionEnum.SERVER_RESTART;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
6
18
|
async function handleServerAction(request, reply, action) {
|
|
7
19
|
const serverName = sanitizeServerName(request.params.name);
|
|
8
20
|
// Validate server name
|
|
@@ -19,6 +31,15 @@ async function handleServerAction(request, reply, action) {
|
|
|
19
31
|
// Execute the action
|
|
20
32
|
const result = await executeServerAction(serverName, action);
|
|
21
33
|
if (!result.success) {
|
|
34
|
+
await writeAuditLog({
|
|
35
|
+
action: toAuditAction(action),
|
|
36
|
+
actor: 'api:console',
|
|
37
|
+
targetType: 'server',
|
|
38
|
+
targetName: serverName,
|
|
39
|
+
status: 'failure',
|
|
40
|
+
details: null,
|
|
41
|
+
errorMessage: result.error ?? 'Failed to execute action',
|
|
42
|
+
});
|
|
22
43
|
reply.code(500);
|
|
23
44
|
return {
|
|
24
45
|
success: false,
|
|
@@ -29,6 +50,15 @@ async function handleServerAction(request, reply, action) {
|
|
|
29
50
|
message: result.stderr,
|
|
30
51
|
};
|
|
31
52
|
}
|
|
53
|
+
await writeAuditLog({
|
|
54
|
+
action: toAuditAction(action),
|
|
55
|
+
actor: 'api:console',
|
|
56
|
+
targetType: 'server',
|
|
57
|
+
targetName: serverName,
|
|
58
|
+
status: 'success',
|
|
59
|
+
details: null,
|
|
60
|
+
errorMessage: null,
|
|
61
|
+
});
|
|
32
62
|
return {
|
|
33
63
|
success: true,
|
|
34
64
|
server: serverName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/routes/servers/actions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,GAEpB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/routes/servers/actions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,GAEpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAmB3D,+DAA+D;AAC/D,iBAAiB;AACjB,+DAA+D;AAE/D;;GAEG;AACH,SAAS,aAAa,CAAC,MAAoB;IACzC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO,CAAC,CAAC,OAAO,eAAe,CAAC,YAAY,CAAC;QAClD,KAAK,MAAM,CAAC,CAAC,OAAO,eAAe,CAAC,WAAW,CAAC;QAChD,KAAK,SAAS,CAAC,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC;IACxD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,OAAqD,EACrD,KAAmB,EACnB,MAAoB;IAEpB,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAE3D,uBAAuB;IACvB,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,UAAU;YAClB,MAAM;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK,EAAE,wIAAwI;SAChJ,CAAC;IACJ,CAAC;IAED,qBAAqB;IACrB,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAE7D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,aAAa,CAAC;YAClB,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC;YAC7B,KAAK,EAAE,aAAa;YACpB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,UAAU;YACtB,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,IAAI;YACb,YAAY,EAAE,MAAM,CAAC,KAAK,IAAI,0BAA0B;SACzD,CAAC,CAAC;QAEH,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,UAAU;YAClB,MAAM;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,0BAA0B;YACjD,OAAO,EAAE,MAAM,CAAC,MAAM;SACvB,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,CAAC;QAClB,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC;QAC7B,KAAK,EAAE,aAAa;QACpB,UAAU,EAAE,QAAQ;QACpB,UAAU,EAAE,UAAU;QACtB,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,IAAI;QACb,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,UAAU;QAClB,MAAM;QACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D,MAAM,mBAAmB,GAAuB,KAAK,EAAE,OAAwB,EAAE,EAAE;IACjF,gCAAgC;IAChC,OAAO,CAAC,IAAI,CACV,0BAA0B,EAC1B,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,OAAO,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC,CACF,CAAC;IAEF,+BAA+B;IAC/B,OAAO,CAAC,IAAI,CACV,yBAAyB,EACzB,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,OAAO,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC,CACF,CAAC;IAEF,kCAAkC;IAClC,OAAO,CAAC,IAAI,CACV,4BAA4B,EAC5B,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,OAAO,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC,CACF,CAAC;AACJ,CAAC,CAAC;AAEF,+DAA+D;AAC/D,SAAS;AACT,+DAA+D;AAE/D,eAAe,EAAE,CAAC,mBAAmB,EAAE;IACrC,IAAI,EAAE,uBAAuB;IAC7B,OAAO,EAAE,KAAK;CACf,CAAC,CAAC;AAEH,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FastifyPluginAsync } from 'fastify';
|
|
2
|
+
/**
|
|
3
|
+
* Server configuration routes plugin
|
|
4
|
+
* Provides REST API for server configuration management
|
|
5
|
+
*/
|
|
6
|
+
declare const configPlugin: FastifyPluginAsync;
|
|
7
|
+
declare const _default: FastifyPluginAsync;
|
|
8
|
+
export default _default;
|
|
9
|
+
export { configPlugin };
|
|
10
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/routes/servers/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AAqC5F;;;GAGG;AACH,QAAA,MAAM,YAAY,EAAE,kBA0MnB,CAAC;;AAMF,wBAGG;AAEH,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import fp from 'fastify-plugin';
|
|
2
|
+
import { join, resolve } from 'path';
|
|
3
|
+
import { existsSync, readdirSync, rmSync } from 'fs';
|
|
4
|
+
import { serverExists, getContainerStatus } from '@minecraft-docker/shared';
|
|
5
|
+
import { ServerConfigResponseSchema, UpdateServerConfigRequestSchema, UpdateServerConfigResponseSchema, WorldResetResponseSchema, } from '../../schemas/config.js';
|
|
6
|
+
import { ErrorResponseSchema, ServerNameParamsSchema } from '../../schemas/server.js';
|
|
7
|
+
import { config } from '../../config/index.js';
|
|
8
|
+
import { createConfigService } from '../../services/ConfigService.js';
|
|
9
|
+
// ============================================================
|
|
10
|
+
// Plugin Definition
|
|
11
|
+
// ============================================================
|
|
12
|
+
/**
|
|
13
|
+
* Server configuration routes plugin
|
|
14
|
+
* Provides REST API for server configuration management
|
|
15
|
+
*/
|
|
16
|
+
const configPlugin = async (fastify) => {
|
|
17
|
+
const configService = createConfigService(config.platformPath);
|
|
18
|
+
/**
|
|
19
|
+
* GET /api/servers/:name/config
|
|
20
|
+
* Get server configuration
|
|
21
|
+
*/
|
|
22
|
+
fastify.get('/api/servers/:name/config', {
|
|
23
|
+
schema: {
|
|
24
|
+
description: 'Get server configuration from config.env',
|
|
25
|
+
tags: ['servers', 'config'],
|
|
26
|
+
params: ServerNameParamsSchema,
|
|
27
|
+
response: {
|
|
28
|
+
200: ServerConfigResponseSchema,
|
|
29
|
+
404: ErrorResponseSchema,
|
|
30
|
+
500: ErrorResponseSchema,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
}, async (request, reply) => {
|
|
34
|
+
const { name } = request.params;
|
|
35
|
+
try {
|
|
36
|
+
// Check if server exists
|
|
37
|
+
if (!serverExists(name)) {
|
|
38
|
+
return reply.code(404).send({
|
|
39
|
+
error: 'NotFound',
|
|
40
|
+
message: `Server '${name}' not found`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Check if config exists
|
|
44
|
+
if (!configService.configExists(name)) {
|
|
45
|
+
return reply.code(404).send({
|
|
46
|
+
error: 'NotFound',
|
|
47
|
+
message: `Configuration for server '${name}' not found`,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const serverConfig = configService.getConfig(name);
|
|
51
|
+
return reply.send({
|
|
52
|
+
config: serverConfig,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
fastify.log.error(error, 'Failed to get server configuration');
|
|
57
|
+
return reply.code(500).send({
|
|
58
|
+
error: 'InternalServerError',
|
|
59
|
+
message: 'Failed to get server configuration',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* PATCH /api/servers/:name/config
|
|
65
|
+
* Update server configuration
|
|
66
|
+
*/
|
|
67
|
+
fastify.patch('/api/servers/:name/config', {
|
|
68
|
+
schema: {
|
|
69
|
+
description: 'Update server configuration in config.env',
|
|
70
|
+
tags: ['servers', 'config'],
|
|
71
|
+
params: ServerNameParamsSchema,
|
|
72
|
+
body: UpdateServerConfigRequestSchema,
|
|
73
|
+
response: {
|
|
74
|
+
200: UpdateServerConfigResponseSchema,
|
|
75
|
+
404: ErrorResponseSchema,
|
|
76
|
+
500: ErrorResponseSchema,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}, async (request, reply) => {
|
|
80
|
+
const { name } = request.params;
|
|
81
|
+
const updates = request.body;
|
|
82
|
+
try {
|
|
83
|
+
// Check if server exists
|
|
84
|
+
if (!serverExists(name)) {
|
|
85
|
+
return reply.code(404).send({
|
|
86
|
+
error: 'NotFound',
|
|
87
|
+
message: `Server '${name}' not found`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// Check if config exists
|
|
91
|
+
if (!configService.configExists(name)) {
|
|
92
|
+
return reply.code(404).send({
|
|
93
|
+
error: 'NotFound',
|
|
94
|
+
message: `Configuration for server '${name}' not found`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const result = configService.updateConfig(name, updates);
|
|
98
|
+
fastify.log.info({
|
|
99
|
+
server: name,
|
|
100
|
+
changedFields: result.changedFields,
|
|
101
|
+
restartRequired: result.restartRequired,
|
|
102
|
+
}, 'Server configuration updated');
|
|
103
|
+
return reply.send({
|
|
104
|
+
success: true,
|
|
105
|
+
config: result.config,
|
|
106
|
+
restartRequired: result.restartRequired,
|
|
107
|
+
changedFields: result.changedFields,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
fastify.log.error(error, 'Failed to update server configuration');
|
|
112
|
+
return reply.code(500).send({
|
|
113
|
+
error: 'InternalServerError',
|
|
114
|
+
message: 'Failed to update server configuration',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* POST /api/servers/:name/world/reset
|
|
120
|
+
* Reset server world data
|
|
121
|
+
* Precondition: Server must be stopped
|
|
122
|
+
*/
|
|
123
|
+
fastify.post('/api/servers/:name/world/reset', {
|
|
124
|
+
schema: {
|
|
125
|
+
description: 'Reset server world data (server must be stopped)',
|
|
126
|
+
tags: ['servers', 'world'],
|
|
127
|
+
params: ServerNameParamsSchema,
|
|
128
|
+
response: {
|
|
129
|
+
200: WorldResetResponseSchema,
|
|
130
|
+
404: ErrorResponseSchema,
|
|
131
|
+
409: ErrorResponseSchema,
|
|
132
|
+
500: ErrorResponseSchema,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}, async (request, reply) => {
|
|
136
|
+
const { name } = request.params;
|
|
137
|
+
const containerName = `mc-${name}`;
|
|
138
|
+
try {
|
|
139
|
+
// Check if server exists
|
|
140
|
+
if (!serverExists(name)) {
|
|
141
|
+
return reply.code(404).send({
|
|
142
|
+
error: 'NotFound',
|
|
143
|
+
message: `Server '${name}' not found`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Check if server is stopped - must be fully stopped to reset world
|
|
147
|
+
const status = getContainerStatus(containerName);
|
|
148
|
+
if (status === 'running' || status === 'paused' || status === 'restarting' || status === 'created') {
|
|
149
|
+
return reply.code(409).send({
|
|
150
|
+
error: 'Conflict',
|
|
151
|
+
message: `Server must be stopped before resetting world (current status: ${status}). Please stop the server first.`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Get world name from configuration
|
|
155
|
+
const worldName = configService.getWorldName(name);
|
|
156
|
+
// Validate world path to prevent path traversal
|
|
157
|
+
const worldsBase = resolve(config.platformPath, 'worlds');
|
|
158
|
+
const worldPath = resolve(worldsBase, worldName);
|
|
159
|
+
if (!worldPath.startsWith(worldsBase + '/')) {
|
|
160
|
+
return reply.code(400).send({
|
|
161
|
+
error: 'BadRequest',
|
|
162
|
+
message: 'Invalid world name in server configuration',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (!existsSync(worldPath)) {
|
|
166
|
+
return reply.code(404).send({
|
|
167
|
+
error: 'NotFound',
|
|
168
|
+
message: `World '${worldName}' not found`,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// Delete world directory contents, preserving .meta file
|
|
172
|
+
const entries = readdirSync(worldPath, { withFileTypes: true });
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
if (entry.name === '.meta') {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const entryPath = join(worldPath, entry.name);
|
|
178
|
+
rmSync(entryPath, { recursive: true, force: true });
|
|
179
|
+
}
|
|
180
|
+
fastify.log.info({
|
|
181
|
+
server: name,
|
|
182
|
+
worldName,
|
|
183
|
+
worldPath,
|
|
184
|
+
}, 'World reset completed');
|
|
185
|
+
return reply.send({
|
|
186
|
+
success: true,
|
|
187
|
+
message: 'World data has been reset. Start the server to generate a new world.',
|
|
188
|
+
worldName,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
fastify.log.error(error, 'Failed to reset world');
|
|
193
|
+
return reply.code(500).send({
|
|
194
|
+
error: 'InternalServerError',
|
|
195
|
+
message: 'Failed to reset world',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
// ============================================================
|
|
201
|
+
// Export
|
|
202
|
+
// ============================================================
|
|
203
|
+
export default fp(configPlugin, {
|
|
204
|
+
name: 'server-config-routes',
|
|
205
|
+
fastify: '5.x',
|
|
206
|
+
});
|
|
207
|
+
export { configPlugin };
|
|
208
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/routes/servers/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/routes/servers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/routes/servers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AAyH5F;;;GAGG;AACH,QAAA,MAAM,aAAa,EAAE,kBA0yBpB,CAAC;;AAEF,wBAGG;AAEH,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/routes/servers.js
CHANGED
|
@@ -2,11 +2,53 @@ import fp from 'fastify-plugin';
|
|
|
2
2
|
import { getAllServers, getServerInfoFromConfig, getServerDetailedInfo, getContainerLogs, containerExists, serverExists, getContainerStatus, getContainerHealth, stopContainer, } from '@minecraft-docker/shared';
|
|
3
3
|
import { ServerListResponseSchema, ServerDetailResponseSchema, ExecCommandResponseSchema, ExecCommandRequestSchema, LogsResponseSchema, LogsQuerySchema, StatusQuerySchema, StatusResponseSchema, ErrorResponseSchema, ServerNameParamsSchema, CreateServerRequestSchema, CreateServerQuerySchema, CreateServerResponseSchema, DeleteServerResponseSchema, DeleteServerQuerySchema, } from '../schemas/server.js';
|
|
4
4
|
import { config } from '../config/index.js';
|
|
5
|
+
import { writeAuditLog } from '../services/audit-log-service.js';
|
|
6
|
+
import { AuditActionEnum } from '@minecraft-docker/shared';
|
|
5
7
|
import { exec } from 'child_process';
|
|
6
8
|
import { promisify } from 'util';
|
|
7
9
|
import { join } from 'path';
|
|
8
10
|
import { existsSync } from 'fs';
|
|
9
11
|
const execPromise = promisify(exec);
|
|
12
|
+
/**
|
|
13
|
+
* Map Docker container status to SSE-compatible status
|
|
14
|
+
* Frontend expects: 'running' | 'stopped' | 'created' | 'exited' | 'unknown'
|
|
15
|
+
*/
|
|
16
|
+
function mapContainerStatus(dockerStatus) {
|
|
17
|
+
switch (dockerStatus) {
|
|
18
|
+
case 'running':
|
|
19
|
+
return 'running';
|
|
20
|
+
case 'exited':
|
|
21
|
+
return 'exited';
|
|
22
|
+
case 'created':
|
|
23
|
+
return 'created';
|
|
24
|
+
case 'paused':
|
|
25
|
+
case 'dead':
|
|
26
|
+
case 'not_found':
|
|
27
|
+
case 'not_created':
|
|
28
|
+
return 'stopped';
|
|
29
|
+
case 'restarting':
|
|
30
|
+
default:
|
|
31
|
+
return 'unknown';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Map Docker health status to SSE-compatible health
|
|
36
|
+
* Frontend expects: 'healthy' | 'unhealthy' | 'starting' | 'none' | 'unknown'
|
|
37
|
+
*/
|
|
38
|
+
function mapHealthStatus(dockerHealth) {
|
|
39
|
+
switch (dockerHealth) {
|
|
40
|
+
case 'healthy':
|
|
41
|
+
return 'healthy';
|
|
42
|
+
case 'unhealthy':
|
|
43
|
+
return 'unhealthy';
|
|
44
|
+
case 'starting':
|
|
45
|
+
return 'starting';
|
|
46
|
+
case 'none':
|
|
47
|
+
return 'none';
|
|
48
|
+
default:
|
|
49
|
+
return 'unknown';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
10
52
|
/**
|
|
11
53
|
* Server routes plugin
|
|
12
54
|
* Provides REST API for Minecraft server management
|
|
@@ -50,6 +92,91 @@ const serversPlugin = async (fastify) => {
|
|
|
50
92
|
});
|
|
51
93
|
}
|
|
52
94
|
});
|
|
95
|
+
/**
|
|
96
|
+
* GET /api/servers-status
|
|
97
|
+
* Get real-time status for all servers (supports SSE streaming with follow=true)
|
|
98
|
+
*/
|
|
99
|
+
fastify.get('/api/servers-status', {
|
|
100
|
+
schema: {
|
|
101
|
+
description: 'Get all servers status (supports SSE streaming)',
|
|
102
|
+
tags: ['servers'],
|
|
103
|
+
querystring: StatusQuerySchema,
|
|
104
|
+
response: {
|
|
105
|
+
200: {
|
|
106
|
+
type: 'array',
|
|
107
|
+
items: StatusResponseSchema,
|
|
108
|
+
},
|
|
109
|
+
500: ErrorResponseSchema,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
}, async (request, reply) => {
|
|
113
|
+
const { follow = false, interval = 5000 } = request.query;
|
|
114
|
+
// SSE streaming mode
|
|
115
|
+
if (follow) {
|
|
116
|
+
reply.raw.writeHead(200, {
|
|
117
|
+
'Content-Type': 'text/event-stream',
|
|
118
|
+
'Cache-Control': 'no-cache',
|
|
119
|
+
'Connection': 'keep-alive',
|
|
120
|
+
'Access-Control-Allow-Origin': '*',
|
|
121
|
+
});
|
|
122
|
+
// Send status update for all servers
|
|
123
|
+
const sendAllStatuses = () => {
|
|
124
|
+
const serverNames = getAllServers();
|
|
125
|
+
for (const name of serverNames) {
|
|
126
|
+
const containerName = `mc-${name}`;
|
|
127
|
+
const dockerStatus = getContainerStatus(containerName);
|
|
128
|
+
const dockerHealth = getContainerHealth(containerName);
|
|
129
|
+
const status = mapContainerStatus(dockerStatus);
|
|
130
|
+
const health = mapHealthStatus(dockerHealth);
|
|
131
|
+
reply.raw.write(`event: server-status\n`);
|
|
132
|
+
reply.raw.write(`data: ${JSON.stringify({
|
|
133
|
+
serverName: name,
|
|
134
|
+
status,
|
|
135
|
+
health,
|
|
136
|
+
timestamp: new Date().toISOString(),
|
|
137
|
+
})}\n\n`);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
// Send initial status immediately
|
|
141
|
+
sendAllStatuses();
|
|
142
|
+
// Poll for status updates at the specified interval
|
|
143
|
+
const polling = setInterval(sendAllStatuses, interval);
|
|
144
|
+
// Heartbeat to keep connection alive (every 30 seconds)
|
|
145
|
+
const heartbeat = setInterval(() => {
|
|
146
|
+
reply.raw.write(': heartbeat\n\n');
|
|
147
|
+
}, 30000);
|
|
148
|
+
// Cleanup on client disconnect
|
|
149
|
+
request.raw.on('close', () => {
|
|
150
|
+
clearInterval(polling);
|
|
151
|
+
clearInterval(heartbeat);
|
|
152
|
+
reply.raw.end();
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Standard JSON response (non-streaming)
|
|
157
|
+
try {
|
|
158
|
+
const serverNames = getAllServers();
|
|
159
|
+
const statuses = serverNames.map((name) => {
|
|
160
|
+
const containerName = `mc-${name}`;
|
|
161
|
+
const dockerStatus = getContainerStatus(containerName);
|
|
162
|
+
const dockerHealth = getContainerHealth(containerName);
|
|
163
|
+
return {
|
|
164
|
+
serverName: name,
|
|
165
|
+
status: mapContainerStatus(dockerStatus),
|
|
166
|
+
health: mapHealthStatus(dockerHealth),
|
|
167
|
+
timestamp: new Date().toISOString(),
|
|
168
|
+
};
|
|
169
|
+
});
|
|
170
|
+
return reply.send(statuses);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
fastify.log.error(error, 'Failed to get all server statuses');
|
|
174
|
+
return reply.code(500).send({
|
|
175
|
+
error: 'InternalServerError',
|
|
176
|
+
message: 'Failed to get all server statuses',
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
53
180
|
/**
|
|
54
181
|
* GET /api/servers/:name
|
|
55
182
|
* Get detailed server information
|
|
@@ -127,46 +254,6 @@ const serversPlugin = async (fastify) => {
|
|
|
127
254
|
message: `Server '${name}' not found`,
|
|
128
255
|
});
|
|
129
256
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Map Docker container status to SSE-compatible status
|
|
132
|
-
* Frontend expects: 'running' | 'stopped' | 'created' | 'exited' | 'unknown'
|
|
133
|
-
*/
|
|
134
|
-
const mapContainerStatus = (dockerStatus) => {
|
|
135
|
-
switch (dockerStatus) {
|
|
136
|
-
case 'running':
|
|
137
|
-
return 'running';
|
|
138
|
-
case 'exited':
|
|
139
|
-
return 'exited';
|
|
140
|
-
case 'created':
|
|
141
|
-
return 'created';
|
|
142
|
-
case 'paused':
|
|
143
|
-
case 'dead':
|
|
144
|
-
case 'not_found':
|
|
145
|
-
case 'not_created':
|
|
146
|
-
return 'stopped';
|
|
147
|
-
case 'restarting':
|
|
148
|
-
default:
|
|
149
|
-
return 'unknown';
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
/**
|
|
153
|
-
* Map Docker health status to SSE-compatible health
|
|
154
|
-
* Frontend expects: 'healthy' | 'unhealthy' | 'starting' | 'none' | 'unknown'
|
|
155
|
-
*/
|
|
156
|
-
const mapHealthStatus = (dockerHealth) => {
|
|
157
|
-
switch (dockerHealth) {
|
|
158
|
-
case 'healthy':
|
|
159
|
-
return 'healthy';
|
|
160
|
-
case 'unhealthy':
|
|
161
|
-
return 'unhealthy';
|
|
162
|
-
case 'starting':
|
|
163
|
-
return 'starting';
|
|
164
|
-
case 'none':
|
|
165
|
-
return 'none';
|
|
166
|
-
default:
|
|
167
|
-
return 'unknown';
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
257
|
// SSE streaming mode
|
|
171
258
|
if (follow) {
|
|
172
259
|
reply.raw.writeHead(200, {
|
|
@@ -494,9 +581,18 @@ const serversPlugin = async (fastify) => {
|
|
|
494
581
|
reply.raw.write(': heartbeat\n\n');
|
|
495
582
|
}, 30000);
|
|
496
583
|
// Handle process completion
|
|
497
|
-
createProcess.on('close', (code) => {
|
|
584
|
+
createProcess.on('close', async (code) => {
|
|
498
585
|
clearInterval(heartbeat);
|
|
499
586
|
if (code === 0 && !hasError) {
|
|
587
|
+
await writeAuditLog({
|
|
588
|
+
action: AuditActionEnum.SERVER_CREATE,
|
|
589
|
+
actor: 'api:console',
|
|
590
|
+
targetType: 'server',
|
|
591
|
+
targetName: name,
|
|
592
|
+
status: 'success',
|
|
593
|
+
details: { type: type ?? null, version: version ?? null, memory: memory ?? null },
|
|
594
|
+
errorMessage: null,
|
|
595
|
+
});
|
|
500
596
|
reply.raw.write(`data: ${JSON.stringify({
|
|
501
597
|
type: 'server-create',
|
|
502
598
|
data: {
|
|
@@ -515,6 +611,15 @@ const serversPlugin = async (fastify) => {
|
|
|
515
611
|
const errorMessage = errorDetail
|
|
516
612
|
? `Server creation failed: ${errorDetail}`
|
|
517
613
|
: `Server creation failed with exit code ${code}`;
|
|
614
|
+
await writeAuditLog({
|
|
615
|
+
action: AuditActionEnum.SERVER_CREATE,
|
|
616
|
+
actor: 'api:console',
|
|
617
|
+
targetType: 'server',
|
|
618
|
+
targetName: name,
|
|
619
|
+
status: 'failure',
|
|
620
|
+
details: null,
|
|
621
|
+
errorMessage,
|
|
622
|
+
});
|
|
518
623
|
reply.raw.write(`data: ${JSON.stringify({
|
|
519
624
|
type: 'server-create',
|
|
520
625
|
data: {
|
|
@@ -547,6 +652,15 @@ const serversPlugin = async (fastify) => {
|
|
|
547
652
|
},
|
|
548
653
|
});
|
|
549
654
|
fastify.log.info({ stdout, stderr }, 'Server created');
|
|
655
|
+
await writeAuditLog({
|
|
656
|
+
action: AuditActionEnum.SERVER_CREATE,
|
|
657
|
+
actor: 'api:console',
|
|
658
|
+
targetType: 'server',
|
|
659
|
+
targetName: name,
|
|
660
|
+
status: 'success',
|
|
661
|
+
details: { type: type ?? null, version: version ?? null, memory: memory ?? null },
|
|
662
|
+
errorMessage: null,
|
|
663
|
+
});
|
|
550
664
|
return reply.code(201).send({
|
|
551
665
|
success: true,
|
|
552
666
|
server: {
|
|
@@ -565,6 +679,15 @@ const serversPlugin = async (fastify) => {
|
|
|
565
679
|
const errorMessage = errorDetail
|
|
566
680
|
? `Failed to create server: ${errorDetail}`
|
|
567
681
|
: (execError.message || 'Failed to create server');
|
|
682
|
+
await writeAuditLog({
|
|
683
|
+
action: AuditActionEnum.SERVER_CREATE,
|
|
684
|
+
actor: 'api:console',
|
|
685
|
+
targetType: 'server',
|
|
686
|
+
targetName: name,
|
|
687
|
+
status: 'failure',
|
|
688
|
+
details: null,
|
|
689
|
+
errorMessage,
|
|
690
|
+
});
|
|
568
691
|
return reply.code(500).send({
|
|
569
692
|
error: 'InternalServerError',
|
|
570
693
|
message: errorMessage,
|
|
@@ -628,6 +751,15 @@ const serversPlugin = async (fastify) => {
|
|
|
628
751
|
},
|
|
629
752
|
});
|
|
630
753
|
fastify.log.info({ stdout, stderr }, 'Server deleted');
|
|
754
|
+
await writeAuditLog({
|
|
755
|
+
action: AuditActionEnum.SERVER_DELETE,
|
|
756
|
+
actor: 'api:console',
|
|
757
|
+
targetType: 'server',
|
|
758
|
+
targetName: name,
|
|
759
|
+
status: 'success',
|
|
760
|
+
details: { force: force ?? false },
|
|
761
|
+
errorMessage: null,
|
|
762
|
+
});
|
|
631
763
|
return reply.send({
|
|
632
764
|
success: true,
|
|
633
765
|
server: name,
|
|
@@ -637,9 +769,19 @@ const serversPlugin = async (fastify) => {
|
|
|
637
769
|
catch (error) {
|
|
638
770
|
const execError = error;
|
|
639
771
|
fastify.log.error(error, 'Failed to delete server');
|
|
772
|
+
const errorMessage = execError.stderr || execError.message || 'Failed to delete server';
|
|
773
|
+
await writeAuditLog({
|
|
774
|
+
action: AuditActionEnum.SERVER_DELETE,
|
|
775
|
+
actor: 'api:console',
|
|
776
|
+
targetType: 'server',
|
|
777
|
+
targetName: name,
|
|
778
|
+
status: 'failure',
|
|
779
|
+
details: null,
|
|
780
|
+
errorMessage,
|
|
781
|
+
});
|
|
640
782
|
return reply.code(500).send({
|
|
641
783
|
error: 'InternalServerError',
|
|
642
|
-
message:
|
|
784
|
+
message: errorMessage,
|
|
643
785
|
});
|
|
644
786
|
}
|
|
645
787
|
});
|