workers-rcon 1.0.0
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/README.md +45 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +67 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# workers-rcon
|
|
2
|
+
|
|
3
|
+
Легкая библиотека для работы с Minecraft RCON в среде **Cloudflare Workers**.
|
|
4
|
+
Использует нативный API `cloudflare:sockets` (TCP), не требует тяжелых полифиллов Node.js.
|
|
5
|
+
|
|
6
|
+
## Установка
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install workers-rcon
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Использование в Cloudflare Workers
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
import { MinecraftRCON } from 'workers-rcon';
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
async fetch(request, env) {
|
|
19
|
+
const rcon = new MinecraftRCON({
|
|
20
|
+
host: 'your-server-ip.com',
|
|
21
|
+
port: 25575,
|
|
22
|
+
password: 'your_rcon_password'
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Выполнение команды
|
|
27
|
+
const response = await rcon.run('say Привет из Cloudflare Workers!');
|
|
28
|
+
return new Response(`Ответ сервера: ${response}`);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
return new Response(`Ошибка: ${err.message}`, { status: 500 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Особенности
|
|
37
|
+
- **Zero dependencies**: только чистый TypeScript.
|
|
38
|
+
- **Auto-connect**: библиотека сама управляет открытием и закрытием сокета.
|
|
39
|
+
- **Little-Endian**: корректная обработка бинарного протокола RCON.
|
|
40
|
+
|
|
41
|
+
## Важно
|
|
42
|
+
Для работы TCP в Workers не забудьте добавить флаг в ваш `wrangler.toml`:
|
|
43
|
+
```toml
|
|
44
|
+
compatibility_flags = [ "tcp_sockets" ]
|
|
45
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RCONConfig {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
password: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class MinecraftRCON {
|
|
7
|
+
private host;
|
|
8
|
+
private port;
|
|
9
|
+
private password;
|
|
10
|
+
private requestId;
|
|
11
|
+
constructor(config: RCONConfig);
|
|
12
|
+
run(command: string): Promise<string>;
|
|
13
|
+
private writePacket;
|
|
14
|
+
private readPacket;
|
|
15
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { connect } from 'cloudflare:sockets';
|
|
2
|
+
// Типы пакетов RCON
|
|
3
|
+
const SERVERDATA_AUTH = 3;
|
|
4
|
+
const SERVERDATA_EXECCOMMAND = 2;
|
|
5
|
+
const SERVERDATA_RESPONSE_VALUE = 0;
|
|
6
|
+
const SERVERDATA_AUTH_RESPONSE = 2;
|
|
7
|
+
export class MinecraftRCON {
|
|
8
|
+
host;
|
|
9
|
+
port;
|
|
10
|
+
password;
|
|
11
|
+
requestId = 1;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.host = config.host;
|
|
14
|
+
this.port = config.port;
|
|
15
|
+
this.password = config.password;
|
|
16
|
+
}
|
|
17
|
+
async run(command) {
|
|
18
|
+
const socket = connect({ hostname: this.host, port: this.port });
|
|
19
|
+
const writer = socket.writable.getWriter();
|
|
20
|
+
const reader = socket.readable.getReader();
|
|
21
|
+
try {
|
|
22
|
+
// 1. Авторизация
|
|
23
|
+
await this.writePacket(writer, SERVERDATA_AUTH, this.password);
|
|
24
|
+
// Читаем ответ авторизации
|
|
25
|
+
let authRes = await this.readPacket(reader);
|
|
26
|
+
if (authRes.id === -1) {
|
|
27
|
+
throw new Error('RCON Authentication failed: Invalid password');
|
|
28
|
+
}
|
|
29
|
+
// 2. Выполнение команды
|
|
30
|
+
await this.writePacket(writer, SERVERDATA_EXECCOMMAND, command);
|
|
31
|
+
const cmdRes = await this.readPacket(reader);
|
|
32
|
+
return cmdRes.body;
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
await writer.close();
|
|
36
|
+
socket.close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async writePacket(writer, type, body) {
|
|
40
|
+
const encoder = new TextEncoder();
|
|
41
|
+
const bodyBytes = encoder.encode(body);
|
|
42
|
+
// Длина: 4(id) + 4(type) + body + 2(null terminators)
|
|
43
|
+
const packetLength = 10 + bodyBytes.length;
|
|
44
|
+
const buffer = new ArrayBuffer(packetLength + 4); // +4 для самого поля длины
|
|
45
|
+
const view = new DataView(buffer);
|
|
46
|
+
view.setInt32(0, packetLength, true);
|
|
47
|
+
view.setInt32(4, this.requestId, true);
|
|
48
|
+
view.setInt32(8, type, true);
|
|
49
|
+
const uint8 = new Uint8Array(buffer);
|
|
50
|
+
uint8.set(bodyBytes, 12);
|
|
51
|
+
uint8[buffer.byteLength - 2] = 0;
|
|
52
|
+
uint8[buffer.byteLength - 1] = 0;
|
|
53
|
+
await writer.write(buffer);
|
|
54
|
+
}
|
|
55
|
+
async readPacket(reader) {
|
|
56
|
+
const { value, done } = await reader.read();
|
|
57
|
+
if (done || !value)
|
|
58
|
+
throw new Error('Connection closed by server');
|
|
59
|
+
const view = new DataView(value.buffer, value.byteOffset, value.byteLength);
|
|
60
|
+
const length = view.getInt32(0, true);
|
|
61
|
+
const id = view.getInt32(4, true);
|
|
62
|
+
const type = view.getInt32(8, true);
|
|
63
|
+
const bodyBytes = value.slice(12, 12 + (length - 10));
|
|
64
|
+
const body = new TextDecoder().decode(bodyBytes);
|
|
65
|
+
return { id, type, body };
|
|
66
|
+
}
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "workers-rcon",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Minecraft RCON client for Cloudflare Workers via cloudflare:sockets",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"cloudflare",
|
|
16
|
+
"workers",
|
|
17
|
+
"minecraft",
|
|
18
|
+
"rcon",
|
|
19
|
+
"tcp"
|
|
20
|
+
],
|
|
21
|
+
"author": "YourName",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@cloudflare/workers-types": "^4.20240000.0",
|
|
25
|
+
"typescript": "^5.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|