Skip to content

Commit

Permalink
1.2.0: Switched from Buffer to Uint8Array, changed argument names, mu…
Browse files Browse the repository at this point in the history
…ltiple changes

- ⚙️ Changed `disableSrv` and `disableJSONParse` to `SRVLookup` and `JSONParse` respectively, changing their default values to true.
- ⚙️ Changed all `Buffer`s to `Uint8Array`s, improving compatibility throughout runtimes.
- ⚙️ Bumped the default protocol version from `764` (1.20.2) to `767` (1.21.1)
- 🛠️ Added hard limit on port property
- 🛠️ Changed uncompiled `.js` imports to `.ts`, making it work with Deno.
- 🛠️ Added jsr.json file
- 🛠️ Fixed SRV lookups not being prevented when port wasn't set 25565/was an IP
- ➖ Removed (previously dysfunctional) soft block on localhost addresses when looking up SRV. Code will initiate a SRV lookup with any local address, has to be disabled with `SRVLookup`,
  • Loading branch information
woodendoors7 committed Nov 24, 2024
1 parent 5b9eb5a commit 7d6d64d
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 104 deletions.
10 changes: 6 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@

<h2>v1.2.0</h2>

[NPM](https://www.npmjs.com/package/minecraftstatuspinger/v/1.2.0)
<sup>[NPM](https://www.npmjs.com/package/minecraftstatuspinger/v/1.2.0) | [JSR](https://jsr.io/@minecraft/minecraftstatuspinger@1.2.0)</sup>

- ⚙️ Changed `disableSrv` and `disableJSONParse` to `SRVLookup` and `JSONParse` respectively, changing their default values to true.
- ⚙️ Changed all `Buffer`s to `Uint8Array`s, improving compatibility throughout runtimes.
- ⚙️ Bumped the default protocol version from `764` (1.20.2) to `767` (1.21.1)
- 🛠️ Added hard limit on port property
- 🛠️ Changed uncompiled `.js` imports to `.ts`, making it work with Deno.
- 🛠️ Added jsr.json file
- 🛠️ Fixed SRV lookups not being prevented when port wasn't set 25565/was an IP
- ➖ Removed (previously disfunctional) soft block on localhost addresses when looking up SRV. Code will initiate a SRV lookup with any localhost address, unless disabled with `SRVLookup`.
- ➖ Removed (previously dysfunctional) soft block on localhost addresses when looking up SRV. Code will initiate a SRV lookup with any local address, has to be disabled with `SRVLookup`.

<h2>v1.1.5</h2>

[NPM](https://www.npmjs.com/package/minecraftstatuspinger/v/1.1.5)
<sup>[NPM](https://www.npmjs.com/package/minecraftstatuspinger/v/1.1.5) | [JSR](https://jsr.io/@minecraft/minecraftstatuspinger@1.1.5)</sup>

- 🛠️ Fixed latency being returned as `null` instead of zero.

Expand Down Expand Up @@ -53,4 +55,4 @@
- 🟢 Added lookup option `disableJSONParse` to completely skip parsing JSON.
- ⚙️ Renamed primary lookup option `hostname` to `host`, `hostname` stays as an alias.

[all versions](https://www.npmjs.com/package/minecraftstatuspinger?activeTab=versions)
All versions: [NPM](https://www.npmjs.com/package/minecraftstatuspinger?activeTab=versions) | [JSR](https://jsr.io/@minecraft/minecraftstatuspinger/versions)
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[![GitHub Link badge](https://badgen.net/badge/icon/GitHub?icon=github&label&color=010409)](https://github.com/woodendoors7/minecraftstatuspinger)
[![NPM link badge](https://badgen.net/badge/icon/NPM?icon=JS&label&color=a00a0b)](https://www.npmjs.com/package/minecraftstatuspinger)
[![JSR link badge](https://badgen.net/badge/color/JSR/?label=&color=d2a404)](https://jsr.io/@minecraft/minecraftstatuspinger)
[![Deno link badge](https://badgen.net/badge/icon/Deno?icon=JS&label&color=00a84b)](https://deno.land/x/minecraftstatuspinger)
[![Web link badge](https://badgen.net/badge/icon/Web?icon=JS&label)](https://pinger.floppa.hair)






<div align="center">
Expand All @@ -7,6 +16,13 @@

<hr>


![NPM Version](https://badgen.net/npm/v/minecraftstatuspinger)
![TS Types](https://badgen.net/npm/types/minecraftstatuspinger)
![License](https://badgen.net/npm/license/minecraftstatuspinger)
![NPM Downloads](https://badgen.net/npm/dy/minecraftstatuspinger/?color=00a600)
![Maintained?](https://badgen.net/static/Maintained%3F/Yes/00a600)

### What can this be used for?

- Getting server **Latency (ping)**
Expand Down Expand Up @@ -34,8 +50,6 @@ let result = await mc.lookup({ host: "mc.hypixel.net" })
console.log(result);
```



<details>
<summary><h3>Advanced Example</h3></summary>
<br>
Expand All @@ -47,7 +61,7 @@ let result = await mc.lookup({
host: "mc.hypixel.net",
port: 25565,
ping: true,
protocolVersion: 764,
protocolVersion: 767,
timeout: 10000,
throwOnParseError: true,
SRVLookup: true,
Expand All @@ -57,7 +71,6 @@ let result = await mc.lookup({
console.log(result);
```


</details>

## Docs
Expand Down Expand Up @@ -109,7 +122,7 @@ console.log(result);
### Changelog

**[View Changelog](https://pinger.floppa.hair/changelog/)**,
Latest version: <b><i><code>v1.1.5</code></i></b>
Latest version: <b><i><code>v1.2.0</code></i></b>



Expand Down
5 changes: 0 additions & 5 deletions deno.json

This file was deleted.

3 changes: 2 additions & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "@minecraft/minecraftstatuspinger",
"version": "1.2.0",
"exports": "./src/index.ts"
"exports": "./src/index.ts",
"compilerOptions":{"strictNullChecks": false}
}
51 changes: 0 additions & 51 deletions src/better-varint.ts

This file was deleted.

11 changes: 8 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,42 @@ async function lookup(options?: ServerStatusOptions): Promise<ServerStatus> {
return new Promise<ServerStatus>(async (resolve, reject) => {

let hostname = options.host || options.hostname;
if (!hostname) return reject(new Error("No hostname was provided!"))
if (!hostname) return reject(new Error("No hostname was provided!"));

let port = options.port != null ? options.port : 25565;
if(port < 0 || port > 65535) return reject(new Error("Port number must be between 0 and 25565!"));

let timeout = options.timeout != null ? options.timeout : 10000;
let ping = options.ping != null ? options.ping : true;
let protocolVersion = options.protocolVersion != null ? options.protocolVersion : 767;
let throwOnParseError = options.throwOnParseError != null ? options.throwOnParseError : true;
let SRVLookup = options.SRVLookup != null ? options.SRVLookup : true;
let JSONParse = options.JSONParse != null ? options.JSONParse : true;
console.log(port)
if (SRVLookup) ({ hostname, port } = await processSRV(hostname, port))
// Default port of 25565, default timeout of 10 seconds.
// Ping is sent by default.

let portal = net.createConnection({ port: port, host: hostname, lookup: customLookup }, async () => {
// Send first the handshake, and then the status request to the server.
let handshake = await packetGen.craftHandshake(hostname, port, protocolVersion);

let statusRequest = await packetGen.craftEmptyPacket(0);

portal.write(handshake);
portal.write(statusRequest);

})

let packet = new Packet();
portal.on("data", async (chunk) => {
portal.on("data", async (_chunk) => {

/*
Pass every new chunk of data sent from the server into the pipeline,
and also pass the packet object in, which holds the current state of the request.
The pipeline returns the packet object, with changes made from processing the data chunk.
*/

let chunk = new Uint8Array(<any>_chunk);
packet = await packetDec.packetPipeline(chunk, packet)
if (packet.Error) {
clearTimeout(timeoutFunc)
Expand Down
10 changes: 5 additions & 5 deletions src/packetDecoder.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import varint from "./better-varint.ts"
import varint from "./utils-varint.ts"
import { Packet } from "./types.ts";


async function packetPipeline(chunk: Buffer, packet: Packet) {
async function packetPipeline(chunk: Uint8Array, packet: Packet) {
// Wait for and Collect all the data coming from the server.
if (packet.status.pingSent) return await craftLatency(packet);

packet.dataBuffer = await Buffer.concat([
packet.dataBuffer = await varint.concatUI8([
packet.dataBuffer,
chunk
])

if (Buffer.byteLength(packet.dataBuffer) > 102400) {
if (packet.dataBuffer.length > 102400) {
packet.Error = new Error("Maximum buffer size of 100 Kilobytes reached.\nThe status packet should be smaller than 20 Kilobytes.")
return packet;
}
Expand Down Expand Up @@ -41,7 +41,7 @@ async function craftData(packet: Packet) {
packet.fieldsBuffer = packet.dataBuffer.slice(packet.meta.metaLength)
let fieldLength = varint.decode(packet.fieldsBuffer)
packet.fieldsBuffer = packet.fieldsBuffer.slice(varint.encodingLength(fieldLength));
packet.crafted.data = packet.fieldsBuffer.toString();
packet.crafted.data = new TextDecoder().decode(packet.fieldsBuffer);
packet.status.handshakeBaked = true;
return packet;
}
Expand Down
49 changes: 21 additions & 28 deletions src/packetGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
import varint from "./better-varint.ts"
import varint from "./utils-varint.ts"


async function craftHandshake(hostname: String, port: number, protocolVersion: number) {
async function craftHandshake(hostname: string, port: number, protocolVersion: number) {
let packetBody = await craftHandshakeBody(hostname, port, protocolVersion);

// Field 1: Length of the entire object, (VarInt)
// Field 2: PacketID, (VarInt)
// Field 3: The body of the request
const packetID = 0;

let packetLengthBuffer = Buffer.from(varint.encode(varint.encodingLength(packetID) + packetBody.length));
let packetIDBuffer = Buffer.from(varint.encode(packetID));
let packetLengthBuffer = varint.encode(varint.encodingLength(packetID) + packetBody.length);
let packetIDBuffer = varint.encode(packetID);

let craftedHandshake = Buffer.concat([
let craftedHandshake = varint.concatUI8([
packetLengthBuffer,
packetIDBuffer,
packetBody,
packetBody
])

return craftedHandshake
}

async function craftHandshakeBody(hostname: String, port: number, protocolVersion: number) {
async function craftHandshakeBody(hostname: string, port: number, protocolVersion: number) {
// Field 1: The Protocol Version, (VarInt)
// Field 2: The hostname of the server, (String) prefixed with it's length (VarInt)
// Field 3: The port of the server, (UInt16)
// Field 4: Next expected state, whether to get the status (1) or login (2), (VarInt)
let protocolVersionBuffer = Buffer.from(varint.encode(protocolVersion));
let hostnamePrefixBuffer = Buffer.from(varint.encode(hostname.length));
let hostnameBuffer = Buffer.from(hostname, "utf8");
let portBuffer = Buffer.allocUnsafe(2)
portBuffer.writeUInt16BE(port, 0)
let nextStateBuffer = Buffer.from(varint.encode(1))

let packetBody = Buffer.concat([
let protocolVersionBuffer = varint.encode(protocolVersion);
let hostnamePrefixBuffer = varint.encode(hostname.length);
let hostnameBuffer = new TextEncoder().encode(hostname);
let portBuffer = varint.craftUInt16BE(port);
let nextStateBuffer = varint.encode(1)

let packetBody = varint.concatUI8([
protocolVersionBuffer,
hostnamePrefixBuffer,
hostnameBuffer,
Expand All @@ -46,10 +45,10 @@ async function craftHandshakeBody(hostname: String, port: number, protocolVersio

async function craftEmptyPacket(packetID: number) {

let packetLengthBuffer = Buffer.from(varint.encode(varint.encodingLength(packetID)));
let packetIDBuffer = Buffer.from(varint.encode(packetID));
let packetLengthBuffer = varint.encode(varint.encodingLength(packetID));
let packetIDBuffer = varint.encode(packetID);

let craftedPacket = Buffer.concat([
let craftedPacket = varint.concatUI8([
packetLengthBuffer,
packetIDBuffer
])
Expand All @@ -66,12 +65,12 @@ async function craftPingPacket() {
// The time of when the ping request was sent is stored in a variable.
const packetID = 1;

let longBuffer = await makeLongBuffer(Date.now())
let longBuffer = varint.craftInt64BE(BigInt(Date.now()));

let packetLengthBuffer = Buffer.from(varint.encode(varint.encodingLength(packetID) + longBuffer.length));
let packetIDBuffer = Buffer.from(varint.encode(packetID));
let packetLengthBuffer = varint.encode(varint.encodingLength(packetID) + longBuffer.length);
let packetIDBuffer = varint.encode(packetID);

let craftedPacket = Buffer.concat([
let craftedPacket = varint.concatUI8([
packetLengthBuffer,
packetIDBuffer,
longBuffer
Expand All @@ -81,11 +80,5 @@ async function craftPingPacket() {
}


async function makeLongBuffer(longNumber: number) {
let buf = Buffer.allocUnsafe(8);
buf.writeBigInt64BE(BigInt(longNumber))

return buf;
}

export default { craftHandshake, craftEmptyPacket, craftPingPacket }
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export class Packet {
fullLength: null,
metaLength: null,
}
dataBuffer = Buffer.alloc(0);
fieldsBuffer = Buffer.alloc(0);
dataBuffer: Uint8Array;
fieldsBuffer: Uint8Array;
crafted: PacketCrafted = {
data: null,
latency: null,
Expand Down
Loading

0 comments on commit 7d6d64d

Please sign in to comment.