Skip to content

Commit

Permalink
🔧 Added promises and removed callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
daniscript18 committed Jul 3, 2023
1 parent e9b0c91 commit f9ab24f
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 170 deletions.
293 changes: 124 additions & 169 deletions best-samp-query.js
Original file line number Diff line number Diff line change
@@ -1,192 +1,147 @@
const dgram = require("dgram");
const iconv = require("iconv-lite")

const error = (text) => {
new Error(text);
}
function query (options) {
return new Promise((resolve, reject) => {
let response = { online: 0 };

const query = async function (options, callback) {
let self = this;
let response = { online: 0 };
options.port = options.port || 7777;
options.timeout = options.timeout || 1000;

options.port = options.port || 7777;
options.timeout = options.timeout || 1000;
if(!options.host) return reject("Invalid \"host\" passed");
if(!isFinite(options.port) || options.port < 1 || options.port > 65535) return reject(`Invalid port "${options.port}". Port mus"t be larger than 1 and less than 65535`);

if(!options.host) return callback.apply(options, [ "Invalid \"host\" passed" ]);
if(!isFinite(options.port) || options.port < 1 || options.port > 65535) return callback.apply(options, [ `Invalid port "${options.port}". Port mus"t be larger than 1 and less than 65535` ]);

request.call(self, options, "i", async function (error, information) {
if(error) return callback.apply(options, [ error ])

response.address = options.host;
response.port = options.port;
response.hostname = information.hostname;
response.gamemode = information.gamemode;
response.mapname = information.mapname;
response.passworded = Boolean(information.passworded);
response.maxplayers = information.maxplayers;
response.online = information.players;

request.call(self, options, "r", async function (error, rules) {
if(error) return callback.apply(options, [ error ])

rules.lagcomp = rules.lagcomp === "On" ? true : false;
rules.weather = parseInt(rules.weather, 10);
response.rules = rules;

if(response.online > 100) {
response.players = []

return callback.apply(options, [ false, response ])
}
else {
request.call(self, options, "d", function(error, players) {
if(error) return callback.apply(options, [ error ])

response.players = players;
request(options, "i").then((information) => {
response.address = options.host;
response.port = options.port;
response.hostname = information.hostname;
response.gamemode = information.gamemode;
response.mapname = information.mapname;
response.passworded = Boolean(information.passworded);
response.maxplayers = information.maxplayers;
response.online = information.players;

request(options, "r").then((rules) => {
rules.lagcomp = rules.lagcomp === "On" ? true : false;
rules.weather = parseInt(rules.weather, 10);
response.rules = rules;

return callback.apply(options, [ false, response ])
});
}
if(response.online > 100) {
response.players = []
return resolve(response);
}
else {
request(options, "d").then((players) => {
response.players = players;
return resolve(response);
}).catch((e) => {
return reject(e);
});
}
}).catch((e) => {
return reject(e);
});
}).catch((e) => {
return reject(e);
});
});
};

const request = function (options, opcode, callback) {
let socket = dgram.createSocket("udp4");
let packet = Buffer.alloc(11);

packet.write("SAMP");

for(let i = 0; i < 4; ++i) packet[i + 4] = options.host.split(".")[i];

packet[8] = options.port & 0xff;
packet[9] = (options.port >> 8) & 0xff;
packet[10] = opcode.charCodeAt(0);

try {
socket.send(packet, 0, packet.length, options.port, options.host, function (error, bytes) {
if(error) return callback.apply(options, [error]);
});
} catch (error) {
return callback.apply(options, [error]);
}

let controller = undefined;

let onTimeOut = () => {
socket.close();
return callback.apply(options, ["Socket timed out."]);
};

controller = setTimeout(onTimeOut, options.timeout);

socket.on("message", function (message) {
if(controller) clearTimeout(controller);
if(message.length < 11) return callback.apply(options, ["Socket invalid"]);
else {
function request (options, opcode) {
return new Promise((resolve, reject) => {
let socket = dgram.createSocket("udp4");
let packet = Buffer.alloc(11);

packet.write("SAMP");

for(let i = 0; i < 4; ++i) packet[i + 4] = options.host.split(".")[i];

packet[8] = options.port & 0xff;
packet[9] = (options.port >> 8) & 0xff;
packet[10] = opcode.charCodeAt(0);

try {
socket.send(packet, 0, packet.length, options.port, options.host, function (error, bytes) {
if(error) return reject(error);
});
} catch (error) {
return reject(error);
}

let controller = undefined;

let onTimeOut = () => {
socket.close();

message = message.slice(11);

let object = {};
let array = [];
let strlen = 0;
let offset = 0;

try {
if(opcode == "i") {
object.passworded = message.readUInt8(offset);
offset += 1;

object.players = message.readUInt16LE(offset);
offset += 2;

object.maxplayers = message.readUInt16LE(offset);
offset += 2;

strlen = message.readUInt16LE(offset);
offset += 4;

object.hostname = decode(message.slice(offset, (offset += strlen)));

strlen = message.readUInt16LE(offset);
offset += 4;

object.gamemode = decode(message.slice(offset, (offset += strlen)));

strlen = message.readUInt16LE(offset);
offset += 4;

object.mapname = decode(message.slice(offset, (offset += strlen)));

return callback.apply(options, [false, object]);
}

if(opcode == "r") {
let rulecount = message.readUInt16LE(offset);
offset += 2;

let property,
value = undefined;

while(rulecount) {
strlen = message.readUInt8(offset);
++offset;

property = decode(message.slice(offset, (offset += strlen)));

strlen = message.readUInt8(offset);
++offset;

value = decode(message.slice(offset, (offset += strlen)));

object[property] = value;

--rulecount;
return reject("Socket timed out.");
};

controller = setTimeout(onTimeOut, options.timeout);

socket.on("message", function (message) {
if(controller) clearTimeout(controller);
if(message.length < 11) return reject("Socket invalid");
else {
socket.close();

message = message.slice(11);

let object = {};
let array = [];
let strlen = 0;
let offset = 0;

try {
if(opcode == "i") {
object.passworded = message.readUInt8(offset); offset += 1;
object.players = message.readUInt16LE(offset); offset += 2;
object.maxplayers = message.readUInt16LE(offset); offset += 2;
strlen = message.readUInt16LE(offset); offset += 4;
object.hostname = decode(message.slice(offset, (offset += strlen)));
strlen = message.readUInt16LE(offset); offset += 4;
object.gamemode = decode(message.slice(offset, (offset += strlen)));
strlen = message.readUInt16LE(offset); offset += 4;
object.mapname = decode(message.slice(offset, (offset += strlen)));
return resolve(object);
}

return callback.apply(options, [false, object]);
}

if (opcode == "d") {
let playercount = message.readUInt16LE(offset);
offset += 2;

let player = undefined;

while(playercount) {
player = {};

player.id = message.readUInt8(offset);
++offset;

strlen = message.readUInt8(offset);
++offset;

player.name = decode(message.slice(offset, (offset += strlen)));

player.score = message.readUInt32LE(offset);
offset += 4;

player.ping = message.readUInt16LE(offset);
offset += 4;

array.push(player);

--playercount;
if(opcode == "r") {
let rulecount = message.readUInt16LE(offset); offset += 2;
let property, value = undefined;

while(rulecount) {
strlen = message.readUInt8(offset); ++offset;
property = decode(message.slice(offset, (offset += strlen)));
strlen = message.readUInt8(offset); ++offset;
value = decode(message.slice(offset, (offset += strlen)));
object[property] = value;
--rulecount;
}
return resolve(object);
}

return callback.apply(options, [false, array]);
if (opcode == "d") {
let playercount = message.readUInt16LE(offset); offset += 2;
let player = undefined;

while(playercount) {
player = {};
player.id = message.readUInt8(offset); ++offset;
strlen = message.readUInt8(offset); ++offset;
player.name = decode(message.slice(offset, (offset += strlen)));
player.score = message.readUInt32LE(offset); offset += 4;
player.ping = message.readUInt16LE(offset); offset += 4;
array.push(player); --playercount;
}
return resolve(array);
}
} catch (exception) {
return reject(exception);
}
} catch (exception) {
return callback.apply(options, [exception]);
}
}
});
});
};

const decode = (buffer) => {
function decode (buffer) {
return iconv.decode(buffer, "win1251");
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "best-samp-query",
"description": "Simplified Query API for SAMP: Efficient and easy retrieval of information from the server 🔥",
"version": "1.0.0",
"version": "1.1.0",
"main": "best-samp-query.js",
"license": "MIT",
"author": "daniscript18",
Expand Down

0 comments on commit f9ab24f

Please sign in to comment.