workers-rcon 1.0.4 → 1.0.5
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/index.d.ts +16 -0
- package/dist/index.js +85 -0
- package/package.json +21 -5
- package/src/index.ts +0 -119
- package/tsconfig.json +0 -16
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface RCONConfig {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
password: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class RCON {
|
|
7
|
+
private host;
|
|
8
|
+
private port;
|
|
9
|
+
private password;
|
|
10
|
+
private requestId;
|
|
11
|
+
private readBuffer;
|
|
12
|
+
constructor(config: RCONConfig);
|
|
13
|
+
run(command: string): Promise<string>;
|
|
14
|
+
private writePacket;
|
|
15
|
+
private readPacket;
|
|
16
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { connect } from 'cloudflare:sockets';
|
|
2
|
+
const SERVERDATA_AUTH = 3;
|
|
3
|
+
const SERVERDATA_EXECCOMMAND = 2;
|
|
4
|
+
const SERVERDATA_RESPONSE_VALUE = 0;
|
|
5
|
+
const SERVERDATA_AUTH_RESPONSE = 2;
|
|
6
|
+
export class RCON {
|
|
7
|
+
host;
|
|
8
|
+
port;
|
|
9
|
+
password;
|
|
10
|
+
requestId = 1;
|
|
11
|
+
readBuffer = new Uint8Array(0);
|
|
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
|
+
await this.writePacket(writer, SERVERDATA_AUTH, this.password);
|
|
23
|
+
let authRes1 = await this.readPacket(reader);
|
|
24
|
+
let authRes2 = null;
|
|
25
|
+
if (authRes1.type === SERVERDATA_RESPONSE_VALUE) {
|
|
26
|
+
authRes2 = await this.readPacket(reader);
|
|
27
|
+
}
|
|
28
|
+
const finalAuth = authRes2 || authRes1;
|
|
29
|
+
if (finalAuth.id === -1) {
|
|
30
|
+
throw new Error('RCON Authentication failed: Invalid password');
|
|
31
|
+
}
|
|
32
|
+
await this.writePacket(writer, SERVERDATA_EXECCOMMAND, command);
|
|
33
|
+
const cmdRes = await this.readPacket(reader);
|
|
34
|
+
return cmdRes.body;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
writer.releaseLock();
|
|
38
|
+
reader.releaseLock();
|
|
39
|
+
await socket.close();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async writePacket(writer, type, body) {
|
|
43
|
+
const encoder = new TextEncoder();
|
|
44
|
+
const bodyBytes = encoder.encode(body);
|
|
45
|
+
const packetLength = 10 + bodyBytes.length;
|
|
46
|
+
const buffer = new ArrayBuffer(packetLength + 4);
|
|
47
|
+
const view = new DataView(buffer);
|
|
48
|
+
view.setInt32(0, packetLength, true);
|
|
49
|
+
view.setInt32(4, this.requestId, true);
|
|
50
|
+
view.setInt32(8, type, true);
|
|
51
|
+
const uint8 = new Uint8Array(buffer);
|
|
52
|
+
uint8.set(bodyBytes, 12);
|
|
53
|
+
uint8[buffer.byteLength - 2] = 0;
|
|
54
|
+
uint8[buffer.byteLength - 1] = 0;
|
|
55
|
+
await writer.write(buffer);
|
|
56
|
+
}
|
|
57
|
+
async readPacket(reader) {
|
|
58
|
+
const decoder = new TextDecoder();
|
|
59
|
+
while (true) {
|
|
60
|
+
if (this.readBuffer.length >= 4) {
|
|
61
|
+
const view = new DataView(this.readBuffer.buffer, this.readBuffer.byteOffset, this.readBuffer.byteLength);
|
|
62
|
+
const length = view.getInt32(0, true);
|
|
63
|
+
const totalPacketLength = length + 4;
|
|
64
|
+
if (this.readBuffer.length >= totalPacketLength) {
|
|
65
|
+
const id = view.getInt32(4, true);
|
|
66
|
+
const type = view.getInt32(8, true);
|
|
67
|
+
const bodyBytes = this.readBuffer.subarray(12, totalPacketLength - 2);
|
|
68
|
+
const body = decoder.decode(bodyBytes);
|
|
69
|
+
this.readBuffer = this.readBuffer.slice(totalPacketLength);
|
|
70
|
+
return { id, type, body };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const { value, done } = await reader.read();
|
|
74
|
+
if (done) {
|
|
75
|
+
throw new Error('Connection closed by RCON server unexpectedly');
|
|
76
|
+
}
|
|
77
|
+
if (value) {
|
|
78
|
+
const newBuffer = new Uint8Array(this.readBuffer.length + value.length);
|
|
79
|
+
newBuffer.set(this.readBuffer);
|
|
80
|
+
newBuffer.set(value, this.readBuffer.length);
|
|
81
|
+
this.readBuffer = newBuffer;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workers-rcon",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Легкая библиотека для работы с Minecraft RCON в среде Cloudflare Workers",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
4
11
|
"author": "fjk-dev",
|
|
12
|
+
"license": "MIT",
|
|
5
13
|
"repository": {
|
|
6
14
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/fjk-dev/workers-rcon
|
|
15
|
+
"url": "https://github.com/fjk-dev/workers-rcon"
|
|
8
16
|
},
|
|
9
17
|
"bugs": {
|
|
10
|
-
"url": "https://github.com/fjk-dev/workers-rcon
|
|
18
|
+
"url": "https://github.com/fjk-dev/workers-rcon"
|
|
11
19
|
},
|
|
12
|
-
"homepage": "https://github.com/fjk-dev/workers-rcon
|
|
20
|
+
"homepage": "https://github.com/fjk-dev/workers-rcon",
|
|
13
21
|
"keywords": [
|
|
14
22
|
"cloudflare",
|
|
15
23
|
"workers",
|
|
16
24
|
"minecraft",
|
|
17
25
|
"rcon",
|
|
18
26
|
"tcp"
|
|
19
|
-
]
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@cloudflare/workers-types": "^4.20260528.1",
|
|
34
|
+
"typescript": "^5.4.5"
|
|
35
|
+
}
|
|
20
36
|
}
|
package/src/index.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { connect } from 'cloudflare:sockets';
|
|
2
|
-
|
|
3
|
-
const SERVERDATA_AUTH = 3;
|
|
4
|
-
const SERVERDATA_EXECCOMMAND = 2;
|
|
5
|
-
const SERVERDATA_RESPONSE_VALUE = 0;
|
|
6
|
-
const SERVERDATA_AUTH_RESPONSE = 2;
|
|
7
|
-
|
|
8
|
-
export interface RCONConfig {
|
|
9
|
-
host: string;
|
|
10
|
-
port: number;
|
|
11
|
-
password: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface RCONPacket {
|
|
15
|
-
id: number;
|
|
16
|
-
type: number;
|
|
17
|
-
body: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class RCON {
|
|
21
|
-
private host: string;
|
|
22
|
-
private port: number;
|
|
23
|
-
private password: string;
|
|
24
|
-
private requestId = 1;
|
|
25
|
-
private readBuffer = new Uint8Array(0);
|
|
26
|
-
|
|
27
|
-
constructor(config: RCONConfig) {
|
|
28
|
-
this.host = config.host;
|
|
29
|
-
this.port = config.port;
|
|
30
|
-
this.password = config.password;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async run(command: string): Promise<string> {
|
|
34
|
-
const socket = connect({ hostname: this.host, port: this.port });
|
|
35
|
-
const writer = socket.writable.getWriter();
|
|
36
|
-
const reader = socket.readable.getReader();
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
await this.writePacket(writer, SERVERDATA_AUTH, this.password);
|
|
40
|
-
|
|
41
|
-
let authRes1 = await this.readPacket(reader);
|
|
42
|
-
let authRes2: RCONPacket | null = null;
|
|
43
|
-
|
|
44
|
-
if (authRes1.type === SERVERDATA_RESPONSE_VALUE) {
|
|
45
|
-
authRes2 = await this.readPacket(reader);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const finalAuth = authRes2 || authRes1;
|
|
49
|
-
if (finalAuth.id === -1) {
|
|
50
|
-
throw new Error('RCON Authentication failed: Invalid password');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await this.writePacket(writer, SERVERDATA_EXECCOMMAND, command);
|
|
54
|
-
const cmdRes = await this.readPacket(reader);
|
|
55
|
-
|
|
56
|
-
return cmdRes.body;
|
|
57
|
-
} finally {
|
|
58
|
-
writer.releaseLock();
|
|
59
|
-
reader.releaseLock();
|
|
60
|
-
await socket.close();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private async writePacket(writer: WritableStreamDefaultWriter, type: number, body: string) {
|
|
65
|
-
const encoder = new TextEncoder();
|
|
66
|
-
const bodyBytes = encoder.encode(body);
|
|
67
|
-
const packetLength = 10 + bodyBytes.length;
|
|
68
|
-
|
|
69
|
-
const buffer = new ArrayBuffer(packetLength + 4);
|
|
70
|
-
const view = new DataView(buffer);
|
|
71
|
-
|
|
72
|
-
view.setInt32(0, packetLength, true);
|
|
73
|
-
view.setInt32(4, this.requestId, true);
|
|
74
|
-
view.setInt32(8, type, true);
|
|
75
|
-
|
|
76
|
-
const uint8 = new Uint8Array(buffer);
|
|
77
|
-
uint8.set(bodyBytes, 12);
|
|
78
|
-
uint8[buffer.byteLength - 2] = 0;
|
|
79
|
-
uint8[buffer.byteLength - 1] = 0;
|
|
80
|
-
|
|
81
|
-
await writer.write(buffer);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private async readPacket(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<RCONPacket> {
|
|
85
|
-
const decoder = new TextDecoder();
|
|
86
|
-
|
|
87
|
-
while (true) {
|
|
88
|
-
if (this.readBuffer.length >= 4) {
|
|
89
|
-
const view = new DataView(this.readBuffer.buffer, this.readBuffer.byteOffset, this.readBuffer.byteLength);
|
|
90
|
-
const length = view.getInt32(0, true);
|
|
91
|
-
const totalPacketLength = length + 4;
|
|
92
|
-
|
|
93
|
-
if (this.readBuffer.length >= totalPacketLength) {
|
|
94
|
-
const id = view.getInt32(4, true);
|
|
95
|
-
const type = view.getInt32(8, true);
|
|
96
|
-
|
|
97
|
-
const bodyBytes = this.readBuffer.subarray(12, totalPacketLength - 2);
|
|
98
|
-
const body = decoder.decode(bodyBytes);
|
|
99
|
-
|
|
100
|
-
this.readBuffer = this.readBuffer.slice(totalPacketLength);
|
|
101
|
-
|
|
102
|
-
return { id, type, body };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const { value, done } = await reader.read();
|
|
107
|
-
if (done) {
|
|
108
|
-
throw new Error('Connection closed by RCON server unexpectedly');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (value) {
|
|
112
|
-
const newBuffer = new Uint8Array(this.readBuffer.length + value.length);
|
|
113
|
-
newBuffer.set(this.readBuffer);
|
|
114
|
-
newBuffer.set(value, this.readBuffer.length);
|
|
115
|
-
this.readBuffer = newBuffer;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ESNext"],
|
|
7
|
-
"types": ["@cloudflare/workers-types"],
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"outDir": "./dist",
|
|
10
|
-
"rootDir": "./src",
|
|
11
|
-
"strict": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"skipLibCheck": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*"]
|
|
16
|
-
}
|