@kzheart_/mc-pilot 0.2.0 → 0.2.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/package.json +1 -1
- package/dist/client/ClientManager.d.ts +0 -82
- package/dist/client/ClientManager.js +0 -221
- package/dist/commands/channel.d.ts +0 -2
- package/dist/commands/channel.js +0 -24
- package/dist/commands/effects.d.ts +0 -2
- package/dist/commands/effects.js +0 -16
- package/dist/server/ServerManager.d.ts +0 -63
- package/dist/server/ServerManager.js +0 -114
- package/dist/util/config.d.ts +0 -31
- package/dist/util/config.js +0 -59
package/package.json
CHANGED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { CommandContext } from "../util/context.js";
|
|
2
|
-
export interface ClientRuntimeState {
|
|
3
|
-
name: string;
|
|
4
|
-
version?: string;
|
|
5
|
-
account?: string;
|
|
6
|
-
server?: string;
|
|
7
|
-
wsPort: number;
|
|
8
|
-
headless: boolean;
|
|
9
|
-
pid: number;
|
|
10
|
-
startedAt: string;
|
|
11
|
-
logPath: string;
|
|
12
|
-
}
|
|
13
|
-
export interface LaunchClientOptions {
|
|
14
|
-
name: string;
|
|
15
|
-
version?: string;
|
|
16
|
-
account?: string;
|
|
17
|
-
server?: string;
|
|
18
|
-
wsPort?: number;
|
|
19
|
-
headless?: boolean;
|
|
20
|
-
}
|
|
21
|
-
export declare class ClientManager {
|
|
22
|
-
private readonly context;
|
|
23
|
-
constructor(context: CommandContext);
|
|
24
|
-
launch(options: LaunchClientOptions): Promise<ClientRuntimeState>;
|
|
25
|
-
stop(name: string): Promise<{
|
|
26
|
-
stopped: boolean;
|
|
27
|
-
name: string;
|
|
28
|
-
pid?: undefined;
|
|
29
|
-
} | {
|
|
30
|
-
stopped: boolean;
|
|
31
|
-
name: string;
|
|
32
|
-
pid: number;
|
|
33
|
-
}>;
|
|
34
|
-
list(): Promise<{
|
|
35
|
-
defaultClient: string | undefined;
|
|
36
|
-
clients: ({
|
|
37
|
-
running: boolean;
|
|
38
|
-
detached: boolean;
|
|
39
|
-
name: string;
|
|
40
|
-
version?: string;
|
|
41
|
-
account?: string;
|
|
42
|
-
server?: string;
|
|
43
|
-
wsPort: number;
|
|
44
|
-
headless: boolean;
|
|
45
|
-
pid: number;
|
|
46
|
-
startedAt: string;
|
|
47
|
-
logPath: string;
|
|
48
|
-
} | {
|
|
49
|
-
running: boolean;
|
|
50
|
-
stale: boolean;
|
|
51
|
-
name: string;
|
|
52
|
-
version?: string;
|
|
53
|
-
account?: string;
|
|
54
|
-
server?: string;
|
|
55
|
-
wsPort: number;
|
|
56
|
-
headless: boolean;
|
|
57
|
-
pid: number;
|
|
58
|
-
startedAt: string;
|
|
59
|
-
logPath: string;
|
|
60
|
-
} | {
|
|
61
|
-
running: boolean;
|
|
62
|
-
name: string;
|
|
63
|
-
version?: string;
|
|
64
|
-
account?: string;
|
|
65
|
-
server?: string;
|
|
66
|
-
wsPort: number;
|
|
67
|
-
headless: boolean;
|
|
68
|
-
pid: number;
|
|
69
|
-
startedAt: string;
|
|
70
|
-
logPath: string;
|
|
71
|
-
})[];
|
|
72
|
-
}>;
|
|
73
|
-
waitReady(name: string, timeoutSeconds: number): Promise<{
|
|
74
|
-
connected: boolean;
|
|
75
|
-
url: string;
|
|
76
|
-
}>;
|
|
77
|
-
getClient(name?: string): Promise<ClientRuntimeState>;
|
|
78
|
-
getWsUrl(wsPort: number): string;
|
|
79
|
-
private getSnapshot;
|
|
80
|
-
private writeSnapshot;
|
|
81
|
-
private isWsReachable;
|
|
82
|
-
}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, openSync } from "node:fs";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { MctError } from "../util/errors.js";
|
|
6
|
-
import { getListeningPids, isProcessRunning, killProcessTree } from "../util/process.js";
|
|
7
|
-
import { WebSocketClient } from "./WebSocketClient.js";
|
|
8
|
-
function getLaunchScriptPath() {
|
|
9
|
-
const thisFile = fileURLToPath(import.meta.url);
|
|
10
|
-
// dist/client/ClientManager.js -> scripts/launch-fabric-client.mjs
|
|
11
|
-
return path.resolve(path.dirname(thisFile), "..", "..", "scripts", "launch-fabric-client.mjs");
|
|
12
|
-
}
|
|
13
|
-
const CLIENT_STATE_FILE = "clients.json";
|
|
14
|
-
function getDefaultSnapshot() {
|
|
15
|
-
return {
|
|
16
|
-
clients: {}
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
export class ClientManager {
|
|
20
|
-
context;
|
|
21
|
-
constructor(context) {
|
|
22
|
-
this.context = context;
|
|
23
|
-
}
|
|
24
|
-
async launch(options) {
|
|
25
|
-
const snapshot = await this.getSnapshot();
|
|
26
|
-
const existing = snapshot.clients[options.name];
|
|
27
|
-
if (existing && isProcessRunning(existing.pid)) {
|
|
28
|
-
throw new MctError({
|
|
29
|
-
code: "CLIENT_ALREADY_RUNNING",
|
|
30
|
-
message: `Client ${options.name} is already running`,
|
|
31
|
-
details: existing
|
|
32
|
-
}, 3);
|
|
33
|
-
}
|
|
34
|
-
const configured = this.context.config.clients[options.name] ?? {};
|
|
35
|
-
const wsPort = options.wsPort ?? configured.wsPort;
|
|
36
|
-
if (!wsPort) {
|
|
37
|
-
throw new MctError({
|
|
38
|
-
code: "INVALID_PARAMS",
|
|
39
|
-
message: `Client ${options.name} requires wsPort`
|
|
40
|
-
}, 4);
|
|
41
|
-
}
|
|
42
|
-
const listeningPids = getListeningPids(wsPort);
|
|
43
|
-
for (const pid of listeningPids) {
|
|
44
|
-
killProcessTree(pid);
|
|
45
|
-
}
|
|
46
|
-
if (listeningPids.length > 0) {
|
|
47
|
-
const deadline = Date.now() + 10_000;
|
|
48
|
-
while (Date.now() < deadline) {
|
|
49
|
-
if (getListeningPids(wsPort).length === 0) {
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const launchCommand = configured.launchArgs
|
|
56
|
-
? [process.execPath, getLaunchScriptPath(), ...configured.launchArgs]
|
|
57
|
-
: configured.launchCommand;
|
|
58
|
-
if (!launchCommand || launchCommand.length === 0) {
|
|
59
|
-
throw new MctError({
|
|
60
|
-
code: "INVALID_PARAMS",
|
|
61
|
-
message: `Client ${options.name} requires launchArgs (or launchCommand) in config`
|
|
62
|
-
}, 4);
|
|
63
|
-
}
|
|
64
|
-
const cwd = configured.workingDir
|
|
65
|
-
? path.resolve(this.context.cwd, configured.workingDir)
|
|
66
|
-
: this.context.cwd;
|
|
67
|
-
mkdirSync(path.join(this.context.state.getRootDir(), "logs"), { recursive: true });
|
|
68
|
-
const logPath = path.join(this.context.state.getRootDir(), "logs", `client-${options.name}.log`);
|
|
69
|
-
const stdout = openSync(logPath, "a");
|
|
70
|
-
const child = spawn(launchCommand[0], launchCommand.slice(1), {
|
|
71
|
-
cwd,
|
|
72
|
-
detached: true,
|
|
73
|
-
stdio: ["ignore", stdout, stdout],
|
|
74
|
-
env: {
|
|
75
|
-
...process.env,
|
|
76
|
-
...configured.env,
|
|
77
|
-
MCT_CLIENT_NAME: options.name,
|
|
78
|
-
MCT_CLIENT_VERSION: options.version ?? configured.version ?? "",
|
|
79
|
-
MCT_CLIENT_ACCOUNT: options.account ?? configured.account ?? "",
|
|
80
|
-
MCT_CLIENT_SERVER: options.server ?? configured.server ?? "",
|
|
81
|
-
MCT_CLIENT_WS_PORT: String(wsPort),
|
|
82
|
-
MCT_CLIENT_HEADLESS: String(options.headless ?? configured.headless ?? false)
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
child.unref();
|
|
86
|
-
const clientState = {
|
|
87
|
-
name: options.name,
|
|
88
|
-
version: options.version ?? configured.version,
|
|
89
|
-
account: options.account ?? configured.account,
|
|
90
|
-
server: options.server ?? configured.server,
|
|
91
|
-
wsPort,
|
|
92
|
-
headless: options.headless ?? configured.headless ?? false,
|
|
93
|
-
pid: child.pid ?? 0,
|
|
94
|
-
startedAt: new Date().toISOString(),
|
|
95
|
-
logPath
|
|
96
|
-
};
|
|
97
|
-
snapshot.defaultClient ??= options.name;
|
|
98
|
-
snapshot.clients[options.name] = clientState;
|
|
99
|
-
await this.writeSnapshot(snapshot);
|
|
100
|
-
return clientState;
|
|
101
|
-
}
|
|
102
|
-
async stop(name) {
|
|
103
|
-
const snapshot = await this.getSnapshot();
|
|
104
|
-
const client = snapshot.clients[name];
|
|
105
|
-
if (!client) {
|
|
106
|
-
return {
|
|
107
|
-
stopped: false,
|
|
108
|
-
name
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
if (isProcessRunning(client.pid)) {
|
|
112
|
-
killProcessTree(client.pid);
|
|
113
|
-
}
|
|
114
|
-
for (const pid of getListeningPids(client.wsPort)) {
|
|
115
|
-
if (pid !== client.pid) {
|
|
116
|
-
killProcessTree(pid);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
delete snapshot.clients[name];
|
|
120
|
-
if (snapshot.defaultClient === name) {
|
|
121
|
-
snapshot.defaultClient = Object.keys(snapshot.clients)[0];
|
|
122
|
-
}
|
|
123
|
-
await this.writeSnapshot(snapshot);
|
|
124
|
-
return {
|
|
125
|
-
stopped: true,
|
|
126
|
-
name,
|
|
127
|
-
pid: client.pid
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
async list() {
|
|
131
|
-
const snapshot = await this.getSnapshot();
|
|
132
|
-
const clients = await Promise.all(Object.values(snapshot.clients).map(async (client) => {
|
|
133
|
-
const running = isProcessRunning(client.pid);
|
|
134
|
-
if (!running) {
|
|
135
|
-
const wsReachable = await this.isWsReachable(client.wsPort, 1);
|
|
136
|
-
if (wsReachable) {
|
|
137
|
-
return {
|
|
138
|
-
...client,
|
|
139
|
-
running: true,
|
|
140
|
-
detached: true
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
...client,
|
|
145
|
-
running: false,
|
|
146
|
-
stale: true
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
return {
|
|
150
|
-
...client,
|
|
151
|
-
running: true
|
|
152
|
-
};
|
|
153
|
-
}));
|
|
154
|
-
return {
|
|
155
|
-
defaultClient: snapshot.defaultClient,
|
|
156
|
-
clients
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
async waitReady(name, timeoutSeconds) {
|
|
160
|
-
const client = await this.getClient(name);
|
|
161
|
-
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
162
|
-
while (Date.now() < deadline) {
|
|
163
|
-
try {
|
|
164
|
-
const ws = new WebSocketClient(this.getWsUrl(client.wsPort));
|
|
165
|
-
return await ws.ping(1);
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
await new Promise((resolve) => {
|
|
169
|
-
setTimeout(resolve, 500);
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
throw new MctError({
|
|
174
|
-
code: "TIMEOUT",
|
|
175
|
-
message: `Timed out waiting for client ${name} to open WebSocket on ${this.getWsUrl(client.wsPort)}`
|
|
176
|
-
}, 2);
|
|
177
|
-
}
|
|
178
|
-
async getClient(name) {
|
|
179
|
-
const snapshot = await this.getSnapshot();
|
|
180
|
-
const resolvedName = name ?? snapshot.defaultClient;
|
|
181
|
-
if (!resolvedName) {
|
|
182
|
-
throw new MctError({
|
|
183
|
-
code: "CLIENT_NOT_FOUND",
|
|
184
|
-
message: "No client is configured or running"
|
|
185
|
-
}, 3);
|
|
186
|
-
}
|
|
187
|
-
const client = snapshot.clients[resolvedName];
|
|
188
|
-
if (!client) {
|
|
189
|
-
throw new MctError({
|
|
190
|
-
code: "CLIENT_NOT_FOUND",
|
|
191
|
-
message: `Client ${resolvedName} was not found`
|
|
192
|
-
}, 3);
|
|
193
|
-
}
|
|
194
|
-
if (!isProcessRunning(client.pid) && !(await this.isWsReachable(client.wsPort, 1))) {
|
|
195
|
-
throw new MctError({
|
|
196
|
-
code: "CLIENT_NOT_RUNNING",
|
|
197
|
-
message: `Client ${resolvedName} is not running`
|
|
198
|
-
}, 3);
|
|
199
|
-
}
|
|
200
|
-
return client;
|
|
201
|
-
}
|
|
202
|
-
getWsUrl(wsPort) {
|
|
203
|
-
return `ws://127.0.0.1:${wsPort}`;
|
|
204
|
-
}
|
|
205
|
-
async getSnapshot() {
|
|
206
|
-
return this.context.state.readJson(CLIENT_STATE_FILE, getDefaultSnapshot());
|
|
207
|
-
}
|
|
208
|
-
async writeSnapshot(snapshot) {
|
|
209
|
-
await this.context.state.writeJson(CLIENT_STATE_FILE, snapshot);
|
|
210
|
-
}
|
|
211
|
-
async isWsReachable(wsPort, timeoutSeconds) {
|
|
212
|
-
try {
|
|
213
|
-
const ws = new WebSocketClient(this.getWsUrl(wsPort));
|
|
214
|
-
await ws.ping(timeoutSeconds);
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
catch {
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
package/dist/commands/channel.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { createRequestAction, parseJson, withTransportTimeoutBuffer } from "./request-helpers.js";
|
|
3
|
-
export function createChannelCommand() {
|
|
4
|
-
const command = new Command("channel").description("Plugin Channel");
|
|
5
|
-
command
|
|
6
|
-
.command("send")
|
|
7
|
-
.description("发送频道消息")
|
|
8
|
-
.argument("<channel>", "频道名称")
|
|
9
|
-
.requiredOption("--data <json>", "JSON 数据")
|
|
10
|
-
.action(createRequestAction("channel.send", ({ args, options }) => ({
|
|
11
|
-
channel: args[0],
|
|
12
|
-
data: parseJson(String(options.data), "data")
|
|
13
|
-
})));
|
|
14
|
-
command
|
|
15
|
-
.command("listen")
|
|
16
|
-
.description("监听频道消息")
|
|
17
|
-
.argument("<channel>", "频道名称")
|
|
18
|
-
.option("--timeout <seconds>", "等待超时秒数", Number)
|
|
19
|
-
.action(createRequestAction("channel.listen", ({ args, options }) => ({
|
|
20
|
-
channel: args[0],
|
|
21
|
-
timeout: options.timeout
|
|
22
|
-
}), ({ options }, context) => withTransportTimeoutBuffer(options.timeout ? Number(options.timeout) : undefined, context.config.timeout.default)));
|
|
23
|
-
return command;
|
|
24
|
-
}
|
package/dist/commands/effects.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { createRequestAction } from "./request-helpers.js";
|
|
3
|
-
export function createEffectsCommand() {
|
|
4
|
-
const command = new Command("effects").description("音效与粒子事件");
|
|
5
|
-
command
|
|
6
|
-
.command("sounds")
|
|
7
|
-
.description("获取音效事件")
|
|
8
|
-
.option("--last <count>", "最近条数", Number)
|
|
9
|
-
.action(createRequestAction("effects.sounds", ({ options }) => ({ last: options.last ?? 10 })));
|
|
10
|
-
command
|
|
11
|
-
.command("particles")
|
|
12
|
-
.description("获取粒子事件")
|
|
13
|
-
.option("--last <count>", "最近条数", Number)
|
|
14
|
-
.action(createRequestAction("effects.particles", ({ options }) => ({ last: options.last ?? 10 })));
|
|
15
|
-
return command;
|
|
16
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { CommandContext } from "../util/context.js";
|
|
2
|
-
export interface ServerRuntimeState {
|
|
3
|
-
pid: number;
|
|
4
|
-
jar: string;
|
|
5
|
-
dir: string;
|
|
6
|
-
port: number;
|
|
7
|
-
startedAt: string;
|
|
8
|
-
logPath: string;
|
|
9
|
-
}
|
|
10
|
-
export interface StartServerOptions {
|
|
11
|
-
jar?: string;
|
|
12
|
-
dir?: string;
|
|
13
|
-
port?: number;
|
|
14
|
-
eula?: boolean;
|
|
15
|
-
}
|
|
16
|
-
export declare class ServerManager {
|
|
17
|
-
private readonly context;
|
|
18
|
-
constructor(context: CommandContext);
|
|
19
|
-
start(options: StartServerOptions): Promise<{
|
|
20
|
-
pid: number;
|
|
21
|
-
jar: string;
|
|
22
|
-
dir: string;
|
|
23
|
-
port: number;
|
|
24
|
-
startedAt: string;
|
|
25
|
-
logPath: string;
|
|
26
|
-
running: boolean;
|
|
27
|
-
}>;
|
|
28
|
-
stop(): Promise<{
|
|
29
|
-
running: boolean;
|
|
30
|
-
stopped: boolean;
|
|
31
|
-
pid?: undefined;
|
|
32
|
-
} | {
|
|
33
|
-
running: boolean;
|
|
34
|
-
stopped: boolean;
|
|
35
|
-
pid: number;
|
|
36
|
-
}>;
|
|
37
|
-
status(): Promise<{
|
|
38
|
-
running: boolean;
|
|
39
|
-
} | {
|
|
40
|
-
pid: number;
|
|
41
|
-
jar: string;
|
|
42
|
-
dir: string;
|
|
43
|
-
port: number;
|
|
44
|
-
startedAt: string;
|
|
45
|
-
logPath: string;
|
|
46
|
-
running: boolean;
|
|
47
|
-
stale: boolean;
|
|
48
|
-
} | {
|
|
49
|
-
pid: number;
|
|
50
|
-
jar: string;
|
|
51
|
-
dir: string;
|
|
52
|
-
port: number;
|
|
53
|
-
startedAt: string;
|
|
54
|
-
logPath: string;
|
|
55
|
-
running: boolean;
|
|
56
|
-
}>;
|
|
57
|
-
waitReady(timeoutSeconds: number): Promise<{
|
|
58
|
-
reachable: boolean;
|
|
59
|
-
host: string;
|
|
60
|
-
port: number;
|
|
61
|
-
}>;
|
|
62
|
-
getState(): Promise<ServerRuntimeState | null>;
|
|
63
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, openSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { MctError } from "../util/errors.js";
|
|
5
|
-
import { waitForTcpPort } from "../util/net.js";
|
|
6
|
-
import { isProcessRunning, killProcessTree } from "../util/process.js";
|
|
7
|
-
const SERVER_STATE_FILE = "server.json";
|
|
8
|
-
export class ServerManager {
|
|
9
|
-
context;
|
|
10
|
-
constructor(context) {
|
|
11
|
-
this.context = context;
|
|
12
|
-
}
|
|
13
|
-
async start(options) {
|
|
14
|
-
const existing = await this.getState();
|
|
15
|
-
if (existing && isProcessRunning(existing.pid)) {
|
|
16
|
-
throw new MctError({
|
|
17
|
-
code: "SERVER_ALREADY_RUNNING",
|
|
18
|
-
message: "Server is already running",
|
|
19
|
-
details: existing
|
|
20
|
-
}, 5);
|
|
21
|
-
}
|
|
22
|
-
const jar = options.jar ?? this.context.config.server.jar;
|
|
23
|
-
if (!jar) {
|
|
24
|
-
throw new MctError({
|
|
25
|
-
code: "INVALID_PARAMS",
|
|
26
|
-
message: "Server jar is required"
|
|
27
|
-
}, 4);
|
|
28
|
-
}
|
|
29
|
-
const dir = path.resolve(this.context.cwd, options.dir ?? this.context.config.server.dir);
|
|
30
|
-
const port = options.port ?? this.context.config.server.port;
|
|
31
|
-
mkdirSync(dir, { recursive: true });
|
|
32
|
-
mkdirSync(path.join(this.context.state.getRootDir(), "logs"), { recursive: true });
|
|
33
|
-
if (options.eula) {
|
|
34
|
-
writeFileSync(path.join(dir, "eula.txt"), "eula=true\n", "utf8");
|
|
35
|
-
}
|
|
36
|
-
const logPath = path.join(this.context.state.getRootDir(), "logs", "paper-server.log");
|
|
37
|
-
const stdout = openSync(logPath, "a");
|
|
38
|
-
const child = spawn("java", [...this.context.config.server.jvmArgs, "-jar", path.resolve(this.context.cwd, jar), "nogui"], {
|
|
39
|
-
cwd: dir,
|
|
40
|
-
detached: true,
|
|
41
|
-
stdio: ["ignore", stdout, stdout],
|
|
42
|
-
env: {
|
|
43
|
-
...process.env,
|
|
44
|
-
MCT_SERVER_PORT: String(port)
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
child.unref();
|
|
48
|
-
const state = {
|
|
49
|
-
pid: child.pid ?? 0,
|
|
50
|
-
jar: path.resolve(this.context.cwd, jar),
|
|
51
|
-
dir,
|
|
52
|
-
port,
|
|
53
|
-
startedAt: new Date().toISOString(),
|
|
54
|
-
logPath
|
|
55
|
-
};
|
|
56
|
-
await this.context.state.writeJson(SERVER_STATE_FILE, state);
|
|
57
|
-
return {
|
|
58
|
-
running: true,
|
|
59
|
-
...state
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
async stop() {
|
|
63
|
-
const state = await this.getState();
|
|
64
|
-
if (!state) {
|
|
65
|
-
return {
|
|
66
|
-
running: false,
|
|
67
|
-
stopped: false
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
if (isProcessRunning(state.pid)) {
|
|
71
|
-
killProcessTree(state.pid);
|
|
72
|
-
}
|
|
73
|
-
await this.context.state.remove(SERVER_STATE_FILE);
|
|
74
|
-
return {
|
|
75
|
-
running: false,
|
|
76
|
-
stopped: true,
|
|
77
|
-
pid: state.pid
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
async status() {
|
|
81
|
-
const state = await this.getState();
|
|
82
|
-
if (!state) {
|
|
83
|
-
return {
|
|
84
|
-
running: false
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
const running = isProcessRunning(state.pid);
|
|
88
|
-
if (!running) {
|
|
89
|
-
await this.context.state.remove(SERVER_STATE_FILE);
|
|
90
|
-
return {
|
|
91
|
-
running: false,
|
|
92
|
-
stale: true,
|
|
93
|
-
...state
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
running: true,
|
|
98
|
-
...state
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
async waitReady(timeoutSeconds) {
|
|
102
|
-
const state = await this.getState();
|
|
103
|
-
if (!state) {
|
|
104
|
-
throw new MctError({
|
|
105
|
-
code: "SERVER_NOT_RUNNING",
|
|
106
|
-
message: "Server is not running"
|
|
107
|
-
}, 5);
|
|
108
|
-
}
|
|
109
|
-
return waitForTcpPort("127.0.0.1", state.port, timeoutSeconds);
|
|
110
|
-
}
|
|
111
|
-
async getState() {
|
|
112
|
-
return this.context.state.readJson(SERVER_STATE_FILE, null);
|
|
113
|
-
}
|
|
114
|
-
}
|
package/dist/util/config.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export declare const DEFAULT_WS_PORT_BASE = 25580;
|
|
2
|
-
export interface MctConfig {
|
|
3
|
-
server: {
|
|
4
|
-
jar?: string;
|
|
5
|
-
dir: string;
|
|
6
|
-
port: number;
|
|
7
|
-
jvmArgs: string[];
|
|
8
|
-
};
|
|
9
|
-
clients: Record<string, {
|
|
10
|
-
version?: string;
|
|
11
|
-
account?: string;
|
|
12
|
-
wsPort?: number;
|
|
13
|
-
server?: string;
|
|
14
|
-
headless?: boolean;
|
|
15
|
-
launchCommand?: string[];
|
|
16
|
-
launchArgs?: string[];
|
|
17
|
-
workingDir?: string;
|
|
18
|
-
env?: Record<string, string>;
|
|
19
|
-
}>;
|
|
20
|
-
screenshot: {
|
|
21
|
-
outputDir: string;
|
|
22
|
-
};
|
|
23
|
-
timeout: {
|
|
24
|
-
serverReady: number;
|
|
25
|
-
clientReady: number;
|
|
26
|
-
default: number;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export declare function resolveConfigPath(configPath: string | undefined, cwd: string): string;
|
|
30
|
-
export declare function loadConfig(configPath: string | undefined, cwd: string): Promise<MctConfig>;
|
|
31
|
-
export declare function writeConfig(configPath: string | undefined, cwd: string, config: MctConfig): Promise<void>;
|
package/dist/util/config.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
export const DEFAULT_WS_PORT_BASE = 25580;
|
|
4
|
-
function createDefaultConfig() {
|
|
5
|
-
return {
|
|
6
|
-
server: {
|
|
7
|
-
dir: "./server",
|
|
8
|
-
port: 25565,
|
|
9
|
-
jvmArgs: []
|
|
10
|
-
},
|
|
11
|
-
clients: {},
|
|
12
|
-
screenshot: {
|
|
13
|
-
outputDir: "./screenshots"
|
|
14
|
-
},
|
|
15
|
-
timeout: {
|
|
16
|
-
serverReady: 120,
|
|
17
|
-
clientReady: 60,
|
|
18
|
-
default: 10
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
export function resolveConfigPath(configPath, cwd) {
|
|
23
|
-
if (!configPath) {
|
|
24
|
-
return path.join(cwd, "mct.config.json");
|
|
25
|
-
}
|
|
26
|
-
return path.isAbsolute(configPath) ? configPath : path.resolve(cwd, configPath);
|
|
27
|
-
}
|
|
28
|
-
export async function loadConfig(configPath, cwd) {
|
|
29
|
-
const resolvedPath = resolveConfigPath(configPath, cwd);
|
|
30
|
-
const defaultConfig = createDefaultConfig();
|
|
31
|
-
try {
|
|
32
|
-
await access(resolvedPath);
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return defaultConfig;
|
|
36
|
-
}
|
|
37
|
-
const raw = await readFile(resolvedPath, "utf8");
|
|
38
|
-
const parsed = JSON.parse(raw);
|
|
39
|
-
return {
|
|
40
|
-
server: {
|
|
41
|
-
...defaultConfig.server,
|
|
42
|
-
...parsed.server
|
|
43
|
-
},
|
|
44
|
-
clients: parsed.clients ?? defaultConfig.clients,
|
|
45
|
-
screenshot: {
|
|
46
|
-
...defaultConfig.screenshot,
|
|
47
|
-
...parsed.screenshot
|
|
48
|
-
},
|
|
49
|
-
timeout: {
|
|
50
|
-
...defaultConfig.timeout,
|
|
51
|
-
...parsed.timeout
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
export async function writeConfig(configPath, cwd, config) {
|
|
56
|
-
const resolvedPath = resolveConfigPath(configPath, cwd);
|
|
57
|
-
await mkdir(path.dirname(resolvedPath), { recursive: true });
|
|
58
|
-
await writeFile(resolvedPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
59
|
-
}
|