Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@bochilteam/scraper/lib/esm/others/minecraft.js
1126 views
1
// import dgram, { Socket } from 'dgram'
2
import EventEmitter from 'events';
3
import net from 'net';
4
import { ScraperError } from '../utils.js';
5
// TODO
6
export async function statusBedrock(ip, port, opts = { timeout: 5 * 1000 }) { }
7
// TODO: fix connection timeout
8
export function statusJava(ip, port = 25565, opts = { timeout: 5 * 1000 }) {
9
// eslint-disable-next-line no-async-promise-executor
10
return new Promise(async (resolve, reject) => {
11
var _a;
12
setTimeout(() => reject(new ScraperError('timeout')), opts.timeout);
13
// reference https://github.com/PassTheMayo/minecraft-server-util/blob/master/src/status.ts
14
const socket = new TCPsocket(ip, port, opts, reject);
15
// https://wiki.vg/Server_List_Ping#Handshake
16
socket.writeVarInt(0x00);
17
socket.writeVarInt(47);
18
socket.writeStringVarInt(ip);
19
socket.writeUnsignedShort(port);
20
socket.writeVarInt(1);
21
await socket.send();
22
// https://wiki.vg/Server_List_Ping#Request
23
socket.writeVarInt(0x00);
24
socket.send();
25
await socket.waitForResponse();
26
socket.readVarInt();
27
const responseId = socket.readVarInt();
28
// eslint-disable-next-line eqeqeq
29
if (responseId == -1)
30
reject(new Error('Premature end of stream'));
31
// eslint-disable-next-line eqeqeq
32
if (responseId != 0x00)
33
reject(new Error('Invalid responseId'));
34
// https://wiki.vg/Protocol#Response
35
const response = JSON.parse(socket.readStringVarInt());
36
// https://wiki.vg/Server_List_Ping#Ping
37
socket.writeVarInt(0x01);
38
const ping = Date.now();
39
socket.writeVarLong(ping);
40
socket.send();
41
await socket.waitForResponse();
42
const pong = Date.now() - ping;
43
socket.close();
44
resolve({
45
ip,
46
port,
47
description: response.description.extra.map(({ text }) => text.trim()).join(' ').trim(),
48
descriptionText: response.description.text.trim(),
49
players: {
50
max: response.players.max,
51
online: response.players.online,
52
sample: response.players.sample.map(({ name }) => name.trim())
53
},
54
version: {
55
name: response.version.name,
56
protocol: response.version.protocol
57
},
58
favicon: (_a = response.favicon) !== null && _a !== void 0 ? _a : null,
59
ping: pong,
60
originalResponse: response
61
});
62
});
63
}
64
// class UDPsocket extends EventEmitter {
65
// public socket: Socket;
66
// constructor (public ip: string, public port: number, public opts: object) {
67
// super()
68
// this.socket = dgram.createSocket('udp4')
69
// }
70
// connect () {
71
// if (!this.socket) return
72
// this.socket.bind(this.port, this.ip)
73
// }
74
// }
75
class TCPsocket extends EventEmitter {
76
constructor(ip, port, opts, reject) {
77
super();
78
this.ip = ip;
79
this.port = port;
80
this.opts = opts;
81
this.reject = reject;
82
this.data = Buffer.alloc(0);
83
this.response = Buffer.alloc(0);
84
}
85
connect(opts) {
86
this.socket = net.createConnection({
87
host: this.ip,
88
port: this.port,
89
timeout: this.opts.timeout,
90
...opts
91
});
92
this.socket.on('data', (data) => {
93
this.response = Buffer.concat([this.response, data]);
94
this.emit('data', data, this.response);
95
});
96
this.socket.on('connect', () => {
97
this.emit('connect');
98
});
99
this.socket.on('close', () => {
100
// this.reject(new ScraperError('Connection closed'));
101
this.emit('close');
102
});
103
this.socket.on('error', () => {
104
this.reject(new ScraperError('Connection error'));
105
this.emit('error');
106
});
107
this.socket.on('timeout', () => {
108
this.reject(new ScraperError('Connection timeout'));
109
this.emit('timeout');
110
});
111
}
112
write(data) {
113
return (this.data = Buffer.concat([this.data, data]));
114
}
115
writeVarInt(value, save = true) {
116
const buffer = Buffer.alloc(5);
117
let i = 0;
118
do {
119
buffer[i++] = value & 0x7f | 0x80;
120
value >>= 7;
121
} while (value > 0);
122
buffer[i - 1] &= 0x7f;
123
const result = buffer.slice(0, i);
124
if (save)
125
this.write(result);
126
return result;
127
}
128
writeVarLong(value) {
129
const buffer = Buffer.alloc(9);
130
let i = 0;
131
do {
132
buffer[i++] = value & 0x7f | 0x80;
133
value >>= 7;
134
} while (value > 0);
135
buffer[i - 1] &= 0x7f;
136
const result = buffer.slice(0, i);
137
this.write(result);
138
return result;
139
}
140
writeStringVarInt(value) {
141
this.writeVarInt(value.length);
142
this.write(Buffer.from(value, 'utf8'));
143
}
144
writeUnsignedShort(value) {
145
this.write(Buffer.from([value >> 8, value & 0xff]));
146
}
147
readVarInt() {
148
let result = 0;
149
let i = 0;
150
let b;
151
do {
152
b = this.response[i++];
153
result |= (b & 0x7f) << (7 * i);
154
} while (b & 0x80);
155
this.response = this.response.slice(i);
156
return result;
157
}
158
readVarLong() {
159
let result = 0;
160
let i = 0;
161
let b;
162
do {
163
b = this.response[i++];
164
result |= (b & 0x7f) << (7 * i);
165
} while (b & 0x80);
166
this.response = this.response.slice(i);
167
return result;
168
}
169
readStringVarInt() {
170
let length = 0;
171
let i = 0;
172
let b;
173
do {
174
b = this.response[i++];
175
length |= (b & 0x7f) << (7 * i);
176
} while (b & 0x80);
177
// @ts-ignore
178
const result = this.response.slice(i, i + length).toString('utf8');
179
this.response = this.response.slice(i + length);
180
return result;
181
}
182
readInt64BE() {
183
// @ts-ignore
184
const result = this.response.slice(0, 8).readBigInt64BE(0);
185
this.response = this.response.slice(8);
186
return result;
187
}
188
send() {
189
if (!this.socket)
190
this.connect();
191
return new Promise((resolve, reject) => {
192
var _a, _b;
193
this.response = Buffer.alloc(0);
194
// https://gist.github.com/zh32/7190955#file-serverlistping17-java-L92
195
// https://github.com/PassTheMayo/minecraft-server-util/blob/68a7a16beb48226cdd5b63c45604fd3bea6c12ca/src/structure/TCPClient.ts#L464
196
const data = Buffer.concat([this.writeVarInt(this.data.byteLength, false), this.data]);
197
(_b = (_a = this.socket) === null || _a === void 0 ? void 0 : _a.write) === null || _b === void 0 ? void 0 : _b.call(_a, data, (err) => {
198
if (err)
199
return reject(err);
200
resolve();
201
});
202
this.data = Buffer.alloc(0);
203
});
204
}
205
close() {
206
var _a, _b, _c, _d, _e, _f;
207
(_b = (_a = this.socket) === null || _a === void 0 ? void 0 : _a.end) === null || _b === void 0 ? void 0 : _b.call(_a);
208
(_d = (_c = this.socket) === null || _c === void 0 ? void 0 : _c.destroy) === null || _d === void 0 ? void 0 : _d.call(_c);
209
(_f = (_e = this.socket) === null || _e === void 0 ? void 0 : _e.removeAllListeners) === null || _f === void 0 ? void 0 : _f.call(_e);
210
}
211
waitForResponse() {
212
return new Promise((resolve) => {
213
const timeout = setTimeout(resolve, 250);
214
this.on('data', () => {
215
// @ts-ignore
216
timeout.refresh();
217
});
218
});
219
}
220
}
221
//# sourceMappingURL=minecraft.js.map
222