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