Error when tryign to start the bot with node-fetch - javascript

I'm currently setting up a premium queue bot from previous code but I need to switch from snekfetch to node fetch
I've tried using the get function yet to no avail it comes out as nonexistent
run(msg, { user }) {
fetch.get('https://api.2b2t.dev/prioq').then(r => {
fetch.get('https://2b2t.io/api/queue').then(qwerty => {
let entry = r.body[1]
let response = qwerty.body[0][1]
client.user.setActivity("Queue: " + response + " PrioQueue: " + entry);
if(message.channel.id === 598643633398349854) {
message.delete().catch(O_o=>{});
message.author.send("The owner has disabled this command in this channel!")
return
}
const queueembed = new RichEmbed()
.setColor("#32CD32")
.addField('Regular Queue:', response, true)
.addField('Priority Queue:', entry, true)
.addField('Regular Queue Time:', Math.round(response * 0.7) + " minutes.", true)
.addField('Priority Queue Time:', Math.round(entry * 0.7) + " minutes.", true)
.setThumbnail('https://i.redd.it/jyvrickfyuly.jpg')
.setFooter("https://discordapp.com/invite/uGfHNVQ")
message.channel.send(queueembed).then(msg => {
var timerID = setInterval(function() {
const queueembed = new RichEmbed()
.setColor("#32CD32")
.addField('Regular Queue:', response, true)
.addField('Priority Queue:', entry, true)
.addField('Regular Queue Time:', Math.round(response * 0.7) + " minutes.", true)
.addField('Priority Queue Time:', Math.round(entry * 0.7) + " minutes.", true)
.setThumbnail('https://i.redd.it/jyvrickfyuly.jpg')
.setFooter("https://discordapp.com/invite/uGfHNVQ")
message.channel.edit(msg)
}, 5 * 1000);
})})
})
}
}
Usually the bot would start but this error pops up
I have tried switching around fetch and removing get but I am confused
on what do to next
"TypeError: Cannot read property 'get' of undefined"

Looks like there are two problems:
1) fetch is undefined (Do you need to install/require it?)
2) get is not part of the fetch API
For a GET request you can just do fetch('<url>').
Putting the two together:
const fetch = require('node-fetch')
fetch('https://api.2b2t.dev/prioq').then(r => {
fetch('https://2b2t.io/api/queue').then(qwerty => {
// ...rest
})
})
https://github.com/bitinn/node-fetch#api
EDIT
You also need to make the rest of your code fetch-compliant. As per the fetch spec, the body exposed by the response is a ReadableStream, which is probably causing your error. As you can see from its interface it also exposes text() and json() methods:
interface mixin Body {
readonly attribute ReadableStream? body;
readonly attribute boolean bodyUsed;
[NewObject] Promise<ArrayBuffer> arrayBuffer();
[NewObject] Promise<Blob> blob();
[NewObject] Promise<FormData> formData();
[NewObject] Promise<any> json();
[NewObject] Promise<USVString> text();
};
https://fetch.spec.whatwg.org/#body-mixin
I presume the response is JSON so you'll want to use response.json():
fetch('https://api.2b2t.dev/prioq').then(r => r.json()).then(r => {
fetch('https://2b2t.io/api/queue').then(qwerty => qwerty.json()).then(qwerty => {
// ...rest
})

Related

Not finding an easy solution to unban command for Discord Bot

I have been trying to get the unban command to work for the past 2 days, but I haven't found an easy solution for it, I keep getting errors like ".find()" isn't a function, or can't define "id". And I just don't get what I need to do. PS.: I am a noobie when it comes to code.
It's also worth mentioning that I have gone through many variations of this code and I have ended at this, probably previous iterations of the code were closer to the actual solution.
const Discord = require('discord.js');
const client = new Discord.Client();
const prefix = "+";
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
const { content } = msg;
if (!content.startsWith(prefix)) return;
const args = content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
switch(command) {
case "ping" : {
let latency = Date.now() - msg.createdTimestamp;
let latencyOfAPI = Math.round(client.ws.ping);
msg.reply("This is the latency between the message and the response: " + latency + "." + "\nThis is the API latency: " + latencyOfAPI + ".");
break;
}
case "pong" : {
msg.reply("ping");
break
}
case "ban" : {
const user = msg.mentions.members.first();
if (user) {
msg.guild.members.ban(user);
msg.reply("The user " + user + " has been banned.")
} else {
return msg.reply("There is no one to ban.").catch(console.error);
}
break
}
case "unban" : {
const user = client.users.cache.find(user => user.username == "").id;
let banList = msg.guild.fetchBans();
if(banList = 0) {
return msg.reply("This user isn't in the community, or he is not banned.");
} else {
banList.find(user)
msg.guild.members.unban(user);
msg.reply("User " + user + " has been unbanned.")
}
break
}
}
});
client.login('.....');
Try this:
case "unban" : {
const user = client.users.fetch(args[1]).catch((err) => console.log(err));
user.then((u) => {
if (!args[1]) {
return msg.reply("Enter ID to unban")
} else {
if (u) {
msg.guild.members.unban(u).then(() => {
msg.reply("The user " + u.username + " has been unbanned.")
}).catch((err) => console.log(err))
} else {
return msg.reply("Cannot Find User")
}
}
})
break
Usage: [prefix]unban [ID] e.g [prefix]unban 3426743678738 (type in text channel)
Tip #1: Try to use .then() & .catch() on function which return a promise. You can use .then() to confirm that you've successfully unbanned a user and .catch() to see why there was a issue with unbanning a user.
Tip #2: Make an if statement which checks if the user running this command has the right permissions before trying the code i.e BAN_MEMBERS & ADMINISTRATOR
Also Note: .fetchBans() returns a collection and Promise

Send another message if are more than 25 field Discord NodeJS

I am making a discord bot (Here is the original one) in javascript of my GTA V RP server, the bot has a command that tells you the name, id and ping of the players but when there are more than 25 players an error occurs ( RangeError: RichEmbeds may not exceed 25 fields.). I have thought about the idea of ​​having more than 25 players send the others in another message.
Here´s the code:
exports.run = async (client, message, args) => {
var util = require("../fivem");
message.delete();
if (servers[message.guild.id].guild === message.guild.id) {
try {
var arg = `${servers[message.guild.id].ip}`
/* var args = `${servers[message.guild.id].ip}` */
let api = `http://${arg}/players.json`
let api2 = `http://${arg}/info.json`
/* if (!args) {return util.embed("Please Specify a Direct-IP address ex: `"+config.prefix+"players thatziv.ddns.net:30120`")}
if (!message.content.includes(":")) {return util.embed("Please Specify a port ex: **"+config.prefix+"players thatziv.ddns.net__:30120__**")} */
req(api2, function (err, response, main) {
req(api, function (err, response, body) {
if (err) {
util.zembed("That server is offline or does not exist... \n**Console:**\n```js\n" + err + "```")
}
else {
try {
var start = JSON.parse(body)
var start2 = JSON.parse(main)
if (start == null || start == []) {
var e = 0
} else {
var e = start.length;
}
var embed = new Discord.RichEmbed()
.setColor(color)
.setAuthor(state, icon)
.setThumbnail(icon)
.setDescription(`__**FamousLifeRP Players**__\n(First 25 players)\n**${e}** out of **${start2.vars.sv_maxClients}** Players.`)
start.forEach(function (element) {
var sv = `**${element.name}**\nID: **${element.id}** Ping: **${element.ping}**`;
embed.addField(`**${element.name}**`, `ID: **${element.id}** Ping: **${element.ping}**`)
})
message.channel.send({ embed: embed });
log(`Used Command [PLAYERS] in ${message.guild.name}`)
} catch (err) {
util.embed("That server is offline or does not exist...\n**Console:**\n```js\n" + err + "```")
}
}
})
})
} catch (err) {
util.embed("That server does not exist. \n**Console:**\n```js\n" + err + "```");
}
} else {
return util.embed("Please **set** a Direct-Address for this server. ex: `" + config.prefix + "set thatziv.ddns.net:30120`\n***__Please make sure to include the address with port.__***")
}
};
var exampleJSON = [
{
"endpoint": "[::ffff:5.15.226.104]:27594",
"id": 294,
"identifiers": [
"steam:110000114ff0dc9",
"license:12eaf8ef61955729188ff56b08e820c8a61bcbc3",
"ip:5.15.226.104"
],
"name": "Leonadro Di la Londra",
"ping": 165
}
]
And here´s the error:
"That server is offline or does not exist...
Console:
RangeError: RichEmbeds may not exceed 25 fields."
create an array of embeds, loop through your array. Use a counter inside the loop. Add fields to the embed as normal. Once counter hits 25, push a new embed object into the array of embeds, then redirect your new fields to the newly added embed. Repeat until you finish adding all fields. Then you can send all of the embeds to the channel.
(might wanna watch out for message ratelimit if you have a ton of data)
I'm not going to write all the code for you but it should look something like this:
const embeds = [];
let counter = 0;
start.forEach(e => {
if(!embeds[Math.floor(counter/25)]) { //checks if the embed exists in array
embeds.push(new Discord.MessageEmbed();
//add embed, do whatever you need to title, etc. here
}
embeds[Math.floor(counter/25)].addField("",""); // whatever you need to add
counter++;
}
embeds.forEach(e => {
message.channel.send(e);
//might watch out for this too because they dont send synchronously
//you could try Promise.all or something
}
Another thing to note is that your code snippet seems to be using a deprecated version of Discord.js, please use the latest version (12.5.1)

Angular&rxjs testing performance of API with multiple requests

I want to check response time for multiple requests sent to API, than display it on chart with help of chart.js I already have done it, but I am not sure if I am doing it right, because responses could not come and my code is adding point on chart only when client receive equal amount of responses that user entered.
here is function responsible for sending request to API and returning response time and data weight:
testRequests(numOfRequests, numOfRecords, db): Subject<any> {
const subject = new Subject();
for (let i = 1; i <= numOfRequests; i++) {
const start_time = performance.now();
this.http.get(BASE_URL + DATABASE + db + LIMIT + numOfRecords, {observe: 'response'}).subscribe((response) => {
subject.next({
time: performance.now() - start_time,
weight: response.headers.get('Content-Length')
});
});
}
return subject;
}
and here is func, that receives results and when it have same amount responses that user requested it adds point to chart:
makeTest(requestsAmount = 1, requestDB = 'aurora') {
const arrOfResults = [];
this.subscription = this.api.testRequests(requestsAmount, 5, requestDB).subscribe(
result => {
arrOfResults.push(result);
if (arrOfResults.length === +requestsAmount) {
this.lineChartData[0].data.push(arrOfResults[arrOfResults.length - 1].time);
this.lineChartData[1].data.push(arrOfResults[arrOfResults.length - 1].weight * arrOfResults.length / 1024);
this.lineChartLabels.push(arrOfResults.length + ' - ' + (requestDB === 'aurora' ? 'Aurora' : 'DynamoDB'));
this.chart.chart.update();
}
},
err => console.error(err),
() => console.log('completed')
);
}
as I heard that there is no guarantee that request will produce response, and responses can get lost, I would like to improve my code, so its generate point on chart in case there are some responses missing.
The subscribe method is not called when there is an unhandled error. You need to use a catch listener for error events.
The below example catches all errors and converts them into a null value. Now subscribe will receive either a response or null.
this.http.get(BASE_URL + DATABASE + db + LIMIT + numOfRecords, {observe: 'response'})
.catch((error, resp) => null)
.subscribe((response) => {
subject.next({
time: performance.now() - start_time,
weight: response ? response.headers.get('Content-Length') : 0
});
});

Create a cell range output dynamically

In my add-in I am making an HTTP request and receiving an output. I want to place that output into a binding and have it expand the binding if necessary because the user won't necessarily know how many rows x columns the output will be. How would I go about doing this? Currently I am binding to a range, but if that range does not match the size of the [[]] that I am providing, then the data is not displayed in the sheet. So, this ends up requiring the user to know the size of the output.
What I'm doing currently using Angular is as follows (the problem with this being that the output isn't always the same size as the Office.BindingType.Matrix that the user selected in the spreadsheet):
I create the binding to where the output should be placed as follows:
inputBindFromPrompt(parameterId: number): Promise<IOfficeResult> {
let bindType: Office.BindingType;
if(this.inputBindings[parameterId].type != 'data.frame' && this.inputBindings[parameterId].type != 'vector') {
bindType = Office.BindingType.Text;
} else {
bindType = Office.BindingType.Matrix;
}
return new Promise((resolve, reject) => {
this.workbook.bindings.addFromPromptAsync(bindType, { id: this.inputBindings[parameterId].name },
(addBindingResult: Office.AsyncResult) => {
if(addBindingResult.status === Office.AsyncResultStatus.Failed) {
reject({
error: 'Unable to bind to workbook. Error: ' + addBindingResult.error.message
});
} else {
this.inputBindings[parameterId].binding = addBindingResult.value;
resolve({
success: 'Created binding ' + addBindingResult.value.type + ' on ' + addBindingResult.value.id
});
}
})
})
}
Then when the user submits via a button, the inputs are passed to a HTTP request service which then receives an output that I process into an array of arrays so that it can go into an Office.BindingType.Matrix:
this.isBusy = true;
this.feedback = 'submitted';
// Grab the values from the form
// Send as a POST and receive an output
// Put the output in the Excel sheet
this.webServicesService.postWebServices(this.service, this.inputParameters)
.subscribe(
(data: any) => {
// Correctly received data
// Access the data by name while looping through output parameters
this.error = false;
this.feedback = 'received data';
let i = 0;
this.outputParameters.forEach(element => {
// temporary name to identify the parameter
let name = element.name;
// Set the data value in the parameter
if(element.type == 'data.frame') {
let parameter = data[name];
this.feedback = parameter;
let excelData = [];
for(var key in parameter) {
if(parameter.hasOwnProperty(key)) {
var val = parameter[key];
excelData.push(val);
}
}
element.value = excelData;
}
else {
element.value = data[name];
}
// Set value in the form
let param = (<FormArray>this.serviceForm.controls['outputParameters']).at(i);
param.patchValue({
value: element.value
});
// Set value in the spreadsheet
this.excelService.outputSetText(i, element.value)
.then((result: IOfficeResult) => {
this.onResult(result);
i++;
});
}, (result: IOfficeResult) => {
this.onResult(result);
});
},
(error) => {
if(error.status == 400 || error.status == 401) {
// Return user to authentication page
this.authService.logout();
this.router.navigate(['/']);
} else {
// Tell user to try again
this.error = true;
}
}
);
The line above that is setting the value to the Office.Matrix.Binding is this.excelService.outputSetText(i, element.value), which calls this method in the Excel Service:
outputSetText(parameterId: number, data: any): Promise<IOfficeResult> {
return new Promise((resolve, reject) => {
if(this.outputBindings[parameterId].binding) {
this.outputBindings[parameterId].binding.setDataAsync(data, function (result: Office.AsyncResult) {
if(result.status == Office.AsyncResultStatus.Failed) {
reject({ error: 'Failed to set value. Error: ' + result.error.message });
} else {
let test: Office.Binding;
resolve({
success: 'successfully set value'
});
}
})
} else {
reject({
error: 'binding has not been created. bindFromPrompt must be called'
});
}
})
}
It's essentially using addFromPromptAsync() to set an output spot for the HTTP request. Then the user submits which sends the request, receives the data back and processes it into an array of arrays [[]] so that it can be the correct data format for Office.BindingType.Matrix. However, unless this is the same number of rows and columns as the binding originally selected, it won't display in the sheet. So, is there a binding type that will dynamically grow based on the data I give it? Or would I just need to release the current binding and make a new binding according to the size of the HTTP response data?
So long as you're using the "shared" (Office 2013) APIs, you will have this issue.
However, in the host-specific (2016+) APIs, you can easily solve the problem by resizing the range to suit your needs. Or more precisely, getting the binding, then asking for its range, then getting just the first (top-left) cell, and then resizing it:
await Excel.run(async (context) => {
let values = [
["", "Price"],
["Apple", 0.99],
["Orange", 1.59],
];
let firstCell = context.workbook.bindings.getItem("TestBinding").getRange().getCell(0, 0);
let fullRange = firstCell.getResizedRange(
values.length - 1, values[0].length - 1);
fullRange.values = values;
await context.sync();
});
You can try this snippet live in literally five clicks in the new Script Lab (https://aka.ms/getscriptlab). Simply install the Script Lab add-in (free), then choose "Import" in the navigation menu, and use the following GIST URL: https://gist.github.com/Zlatkovsky/5a2fc743bc9c8556d3eb3234e287d7f3. See more info about importing snippets to Script Lab.

Appending property to ArrayBuffer sent over DataChannel

I am currently receiving chunks from a stream of a video that I send over the DataChannel to a peer who will then reconstruct the video on the other end.
I have this part working just fine but I would like to add which chunk # it was that was received so that it doesn't matter if they happen to arrive in a different order than intended.
Initially I thought that adding a parameter chunkId would work but when I do .data.chunkId on the receiver side, it is undefined.
Then I tried to stringify the ArrayBuffer along with the chunkId using JSON.stringify({ "chunkId": chunkId, "data": chunk }) but it causes problems when I parse it on the other end (Unexpected end of JSON input and Unexpected token , in JSON at position #)
DataChannels also accept blobs so I thought I would try that but the sender is using node.js which apparently can't do that. I wasn't quite able to figure out how to get around that.
The last thing I tried was to simply append the chunkId to the beginning/end of the ArrayBuffer itself but when I try to create a new array I get the error source is too large when trying to add the chunk itself.
What is the correct way of achieving this?
You should be able to intermingle sending text and ArrayBuffers, and check for them on reception:
var pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
pc1.oniceconnectionstatechange = e => log(pc1.iceConnectionState);
pc1.onnegotiationneeded = e =>
pc1.createOffer().then(d => pc1.setLocalDescription(d))
.then(() => pc2.setRemoteDescription(pc1.localDescription))
.then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
.then(() => pc1.setRemoteDescription(pc2.localDescription))
.catch(e => log(e));
var dc1 = pc1.createDataChannel("chat", {negotiated: true, id: 0});
var dc2 = pc2.createDataChannel("chat", {negotiated: true, id: 0});
dc2.binaryType = "arraybuffer";
dc2.onmessage = e => {
if (e.data instanceof ArrayBuffer) {
log("Got ArrayBuffer!");
} else if (e.data instanceof Blob) {
log("Got Blob!");
} else {
log("> " + e.data);
}
}
button.onclick = e => dc1.send(new ArrayBuffer(8));
chat.onkeypress = e => {
if (e.keyCode != 13) return;
dc1.send(chat.value);
chat.value = "";
};
var log = msg => div.innerHTML += "<br>" + msg;
Chat: <input id="chat"><button id="button">Send ArrayBuffer</button><br>
<div id="div"></div>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
So why not send the chunk id ahead of each ArrayBuffer?

Categories

Resources