So I followed the dynamic command handler guide on the discord.js guide site, and it turns out every time I try to let it execute a command, it says that the execute function is undefined, no matter how I tried to fix it. To make sure that my code is supposed to be working, I downloaded the example code they had on the guide and ran it, which also didn’t work for some reason. My discord.js and node.js are all up to date.
Since I do not know your current files/code, I can provide an example.
Also, in this example, I will be assuming that you have named your bot variable client.
First, make sure you have a folder named commands.
On the top of your bot code (index.js or whatever it's called), add this line:
const fs = require("fs");
In your bot code, after the bot definition (var client = new Discord.Client()), add these lines:
client.commands = new Discord.Collection();
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for(let file of commandFiles) {
let command = require('./commands/' + file);
client.commands.set(command.name, command);
}
And on your message event listener (assuming that you already have made some commands in the folder), replace your command if statement(s) with this:
// you can use other expressions to check if the command is there
// the commandname in the client.commands.get is the filename without .js
if(message.content.startsWith("commandname")) client.commands.get("commandname").execute(message, args);
Creating commands will be the process of creating JavaScript files in your commands folder. So in your commands folder, create a file (filename will be like "commandname.js" or something) and the content will be:
module.exports = {
name: "commandname",
description: "Command description here.",
execute(message, args) {
// Now you can do your command logic here
}
}
I hope this helped! If it isn't clear, feel free to downvote.
Related
Using child_process (spawn) to open a new BASH terminal and execute the commands in each file.
I want to add all of my .sh files, that I'm going to spawn, into a folder to clean up my project directory.
PROBLEM:
I can't figure out how to change the directory the scripts run from, and the docs are a little to heavy for me at this point.
SIMPLE TEST EXAMPLE, WITH MY FIRST TWO FILES FOR CONNECTING (each .sh file would be in the project folder):
const { spawn } = require('node:child_process');
const bat = spawn('cmd.exe', ['/c', 'connect.sh']);
/*
<connect.sh> // 1st .sh file
#!/usr/bin/env bash //to make it bash
HTTP_PORT=3002 P2P_PORT=5002 PEERS=ws://localhost:5001 npm run dev
<connect1.sh> // 2nd .sh file
#!/usr/bin/env bash //to make it bash
HTTP_PORT=3003 P2P_PORT=5003 PEERS=ws://localhost:5002,ws://localhost:5001 npm run dev
*/
I have 9 of these files to connect up to 10 peers. And I would like to put them in a folder to simplify my project structure.
This is my actual API call below....
// Uses length to determine which file to run
app.post("/peers/connect", async function (req, res) {
const peerInfo = await peers.info();
// no peers yet
if (typeof peerInfo === "string") {
let bat = spawn("cmd.exe", ["/c", "connect.sh"]);
res.json("A new terminal has opened! You are now connected!");
} else {
// peers exist
let length = peerInfo.peers;
// console.log(length);
let bat = spawn("cmd.exe", ["/c", `connect${length}.sh`]);
res.json("A new terminal has opened! You are now connected!");
}
});
My file structure here...you can see why I want a folder for these!
RECAP:
Help my put all of these files into a folder (shellScripts) and have the code still work :)
Thanks! (just realized we might have to cd back into project folder before "npm run dev" in each file?)
You are using the cmd.exe utility to run a .sh file, but that wont work. You have to install a bash interpreter on your windows device or install WSL. (If necessary add bash.exe to the windows path) Then change your code to this:
const { spawn } = require('node:child_process');
const bat = spawn('bash.exe',['connect.sh']);
I hope this answer helped
For running multiple files:
const { spawn } = require('node:child_process');
const fs = require("node:fs")
const dir = "" // Replace this with the location of the directory containing connect shellscripts
let entrys = fs.readdirSync(dir)
entrys = entrys.filter(v => v.startsWith("connect"))
for (let ent of entrys) {
const bat = spawn('bash.exe',[ent]);
// your code here
}
Figured out the answer on me own. Thanks to everyone that tried to help :)
And to those saying my above code doesn't work, it works perfectly fine.
I've provided a picture to clarify. 1st is what the code below produces. 2nd is manually pasting it into GIT BASH.
// test.js in project structure pic above
var exec = require('child_process').exec;
var path = require('path')
var parentDir = path.resolve(process.cwd(), 'shellScripts');
exec('my.sh', {cwd: parentDir}, function (error, stdout, stderr) {
// if you also want to change current process working directory:
process.chdir(parentDir);
});
This is what the code produces.
And this is opening a GIT BASH in project folder and pasting the command in
I'm a new developer and this is my first Stack Overflow post. I've tried to stick to the format as best as possible. It's a difficult issue for me to explain, so please let me know if there's any problems with this post!
Problem
I'm working on a vscode extension specifically built for Next.js applications and running into issues on an event listener for the onDidChangeText() method. I'm looking to capture data from a JSON file that will always be located in the root of the project (this is automatically generated/updated on each refresh of the test node server for the Next.js app).
Expected Results
The extension is able to look for updates on the file using onDidChangeText(). However, the issue I'm facing is on the initial run of the application. In order for the extension to start listening for changes to the JSON file, the user has to be in the JSON file. It's supposed to work no matter what file the user has opened in vscode. After the user visits the JSON file while the extension is on, it begins to work from every file in the Next.js project folder.
Reproducing this issue is difficult because it requires an extension, npm package, and a next.js demo app, but the general steps are below. If needed, I can provide code for the rest.
1. Start debug session
2. Open Next.js application
3. Run application in node dev
4. Do not open the root JSON file
What I've Tried
Console logs show we are not entering the onDidTextDocumentChange() block until the user opens the root JSON file.
File path to the root folder is correctly generated at all times, and prior to the promise being reached.
Is this potentially an async issue? Or is the method somehow dependent on the Active Window of the user to start looking for changes to that document?
Since the file is both created and updated automatically, we've tested for both, and neither are working until the user opens the root JSON file in their vscode.
Relevant code snippet (this will not work alone but I can provide the rest of the code if necessary. ).
export async function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "Next Step" is now active!');
setupExtension();
const output = vscode.window.createOutputChannel('METRICS');
// this is getting the application's root folder filepath string from its uri
if (!vscode.workspace.workspaceFolders) {
return;
}
const rootFolderPath = vscode.workspace.workspaceFolders[0].uri.path;
// const vscode.workspace.workspaceFolders: readonly vscode.WorkspaceFolder[] | undefined;
// this gives us the fileName - we join the root folder URI with the file we are looking for, which is metrics.json
const fileName = path.join(rootFolderPath, '/metrics.json');
const generateMetrics = vscode.commands.registerCommand(
'extension.generateMetrics',
async () => {
console.log('Succesfully entered registerCommand');
toggle = true;
vscode.workspace.onDidChangeTextDocument(async (e) => {
if (toggle) {
console.log('Succesfully entered onDidChangeTextDocument');
if (e.document.uri.path === fileName) {
// name the command to be called on any file in the application
// this parses our fileName to an URI - we need to do this for when we run openTextDocument below
const fileUri = vscode.Uri.parse(fileName);
// open the file at the Uri path and get the text
const metricData = await vscode.workspace
.openTextDocument(fileUri)
.then((document) => {
return document.getText();
});
}
}
});
});
}
Solved this by adding an "openTextDocument" call inside the "registerCommand" block outside of the "onDidChangeTextDocument" function. This made the extension aware of the 'metrics.json' file without it being open in the user's IDE.
As there are things called 'callback hell'. It was the only way I can get a file from a server to my vps pc, and upload it. The process was simple:
Download a .json file from the ftp server
Edit the .json file on the pc
Upload the .json file and delete the pc's copy.
However my problem was this: Although it downloads once, it returns the upload based on how many times I command it during 1 session (command #1, does it once, command#2, does it twice, etc).
I tried to run it as imperative, but gets nullified. Had to resort to callback hell to run the code almost properly. The trigger works to initialize the command, but the command and session goof'd.
(( //declaring my variables as parameters
ftp=new (require('ftp'))(),
fs=require('fs'),
serverFolder='./Path/Of/Server/',
localFolder='./Path/Of/Local/',
file='some.json',
{log}=console
)=>{
//run server if its ready
ftp.on('ready',()=>{
//collect a list of files from the server folder
ftp.list(serverFolder+file,(errList,list)=>
errList|| typeof list === 'object' &&
list.forEach($file=>
//if the individual file matches, resume to download the file
$file.name===file&&(
ftp.get(serverFolder+file,(errGet,stream)=>
errGet||(
log('files matched! cdarry onto the operation...'),
stream.pipe(fs.createReadStream(localFolder+file)),
stream.once('close',()=>{
//check if the file has a proper size
fs.stat(localFolder+file,(errStat,stat)=>
errStat || stat.size === 0
//will destroy server connection if bytes = 0
?(ftp.destroy(),log('the file has no value'))
//uploads if the file has a size, edits, and ships
:(editThisFile(),
ftp.put(
fs.createReadStream(localFolder+file),
serverFolder+file,err=>err||(
ftp.end(),log('process is complete!')
))
//editThisFile() is a place-holder editor
//edits by path, and object
)
})
)
)
)
)
);
});
ftp.connect({
host:'localHost',
password:'1Forrest1!',
port:'21',
keepalive:0,
debug: console.log.bind(console)
});
})()
The main problem is: it'll return a copy of the command over and over as 'carry over' for some reason.
Edit: although the merits of "programming style" is different than common meta. It all leads to the same issue of callback hell. Any recommendations are needed.
For readability, I had help editing my code to ease difficulty. Better Readability version
The ftp modules API leads to the callback hell. It also hasn't been maintained for a while and is buggy. Try a module with promises like basic-ftp.
With promises the code flow becomes much easier to reason with and errors don't require specific handling, unless you want to.
const ftp = require('basic-ftp')
const fsp = require('fs').promises
async function updateFile(localFile, serverFile){
const client = new ftp.Client()
await client.access({
host: 'localHost',
password: '1Forrest1!',
})
await client.downloadTo(localFile, serverFile)
const stat = await fsp.stat(localFile)
if (stat.size === 0) throw new Error('File has no size')
await editThisFile(localFile)
await client.uploadFrom(localFile, serverFile)
}
const serverFolder = './Path/Of/Server'
const localFolder = './Path/Of/Local'
const file = 'some.json'
updateFile(localFolder + file, serverFolder + file).catch(console.error)
I'm building a script that reads log files, handles what needs to be handled then writes them to a database
Some caveats :
Some log files have a lot of input, multiple times a second
Some log files have few to no input at all
What I try in simple words:
Reading the first line of a file, then deleting this line to go to the next one, while I handle the first line, other lines could be added..
Issues I'm facing
When I try reading a file then processing it, then deleting the
files, some lines have been added
When the app crashes while
handling multiple lines at once for any reason, I can't know what
lines have been processed.
Tried so far
fs.readdir('logs/', (err, filenames) => {
filenames.forEach((filename) => {
fs.readFile('logs/'+filename, 'utf-8', (err, content) => {
//processing all new lines (can take multiple ms)
//deleting file
fs.unlink('logs/'+filename)
});
});
});
Is there not a (native or not) method to 'take' first line(s), or take all lines, from a file at once?
Something similar to what the Array.shift() method does to arrays..
Why you are reading the file at once. Instead you can use the node.js streams.
https://nodejs.org/api/fs.html#fs_class_fs_readstream
This will read the files and output to console
var fs = require('fs');
var readStream = fs.createReadStream('myfile.txt');
readStream.pipe(process.stdout);
You can also go for the npm package node-tail to read the content of a files while new content written to it.
https://github.com/lucagrulla/node-tail
If your log files has been writen as rotate logs. Example: Each hours has each log file, 9AM.log, 10AM.log....When you process the log files, you can skip current file and process another files. ex: now is 10:30 AM o’clock, skip file 10AM.log, solve another files.
Bot used to work flawlessly but I thought it would be good to split my code since it was getting too large. I've fixed most of the mistakes that pop up but however I could not. for the life of me, get the called modules to write to file. The modules seem to have a cached values if it's like a counter (like in the slots game I made), however something like profile would still show the value in the stored values in the json file, unaffected by the game (although the count in the game is changing). When I reset the bot, the value in the game reverts back to the value on the json, so I'm assuming the fs.writeFile I placed in the module isn't successful n the module is only rendering a temporary cache.
const Discord = require('discord.js');
const fs = require("fs");
let points = JSON.parse(fs.readFileSync("./points.json", "utf8"));
let extrasettings = JSON.parse(fs.readFileSync("./extra.json", "utf8"));
let tempgamefiles = JSON.parse(fs.readFileSync("./temporarygamefiles.json", "utf8"));
module.exports = (bot, message, args) => {
// asynchronous method of writing to file, however not really working
fs.writeFile("./extra.json", JSON.stringify(extrasettings), (err) => {if (err) console.error(err)});
}
file path is correct and the exact code used to work fine in 1 single ginormous file.. don't know how moduling would break it.