Why is a new instance of a object undefined? - javascript

I am unable to use the same instance of an object in another java-script file using nodejs.
I'm working on a bot for telegram. Because the file gets large and chaotic, i would like to split the functions of my bot into a few extra js files. But i don't know any way how to share the same instance of an object between multiple javascript files.
///////////////////////8Ball File
const {eightBall} = require("./main");
const ballBot = myAwseomeBot;
function eightBall() {
ballBot.onText(/\/8ball/, (msg, callback) => {
let ranNum = Math.floor(Math.random() * 15) + 1;
const chatId = msg.chat.id;
const reply_to_message_id = msg.message_id;
console.log(ranNum);
switch (ranNum) {
case 1:
ballBot.sendMessage(chatId, "Ja");
break;
}
})
}
//main file
let myAwesomeBot = new TelegramBot(botToken, {polling:true});
exports.myAwesomeBot = myAwesomeBot;
ballBot.onText(/\/8ball/, (msg, callback) => {
^
TypeError: Cannot read property 'onText' of undefined

It isn't shown in your code here, but you probably have a cyclic dependency, where A requires B, and B requires A.
The simplest solution relevant to your use case is to define and implement commands for your bot in additional files, and let your bot file attach / consume them:
8ball.js
import { telegram stuff } from 'wherever';
export myCommand1 = {
pattern: /\/8ball/,
eventName: 'ontext',
callback: (msg, msgCallback) => { /* use "this" as if it were the bot instance */};
};
main.js
import .... from ....;
import { myCommand1 } from '8ball';
...
bot.onText(myCommand1.pattern, myCommand1.callback.bind(bot));
...
There are probably other bot class methods more suited for attaching generic event handlers/listeners, and also other methods of specifying your module exports, but the idea is that your command files don't need to import the bot file. I have not researched the telegram bot API so it may have some manner of delegating the bot instance when attaching an event handler. If so, use it!

Did you check that ballBot was defined?
Try to remove the brackets when requiring the main file. I would also suggest using the Singleton pattern if you want to share the same instance across your code.

Could it be that there is a typo on line 2? Should be
myAwesomeBot not myAwseomeBot.
const ballBot = myAwseomeBot;

Related

Can you declare your own function in Discord JS?

Normally I just add to the command files or the index file easily but it's starting to look messy. Recently I got this leveling system working
if (!levels[message.author.id]) {
levels[message.author.id] = {
level: 1,
exp: 0
}
}
// Gives random EXP
let randomExp = Math.floor(Math.random() * 5 + 5);
// Adds the random EXP to their current EXP
levels[message.author.id].exp += randomExp;
// Checks their EXP and changes their level
for (x = 0; x < expLevels.length; x++) {
if (levels[message.author.id].exp > expLevels[x]) {
levels[message.author.id].level = x + 1;
message.channel.reply(`congratulations! You reached level ${levels[message.author.id].level + 1}!`);
}
}
fs.writeFile('./levels.json', JSON.stringify(levels), err => {
if (err) console.error(err);
});
if (levels[authorMessage.author.id].level >= 10) {
message.member.roles.remove('720109209479413761');
message.member.roles.add('719058151940292659');
}
I would like to be able to put this into its own function and then call it in the "message" section for every time someone sends a message. Is that possible to do? Or no since I need to have access to the "message" variable?
I'm used to C++ with functions where it's much easier to deal with. Does anyone know if it's possible to code a bot in C++ or is there no support? If there is a way if someone can point me in the right direction to start please let me know. Otherwise I can easily stay with JS.
I'm not sure if a discord framework for C++ exists, probably but I'm not sure.
You can of course define a function somewhere and call it in the onMessage event.
There are two ways that you could do that.
In the same file
In another file
Functions in the same file.
You can declare a function and then pass arguments to that function. You don't need to declare the type of argument that is being passed here. Source
function leveling(message) { // here you can include all parameters that you might need
// the rest of your code
}
Once you have a function you can call it like this.
leveling(message); // here we pass the values we need to the function
Functions in a different file.
The concept is the same, however we need to export the function in order to use it somewhere else. There are two ways to do this, either export only one function or export all functions, in the case of a dedicated functions file this is the easier option.
Note: In this example I name the file functions.js and place it in the same directory as the file I require it from.
module.exports = {
// we need to declare the name first, then add the function
leveling: function (message) {
// the rest of your code
}
// here we can add more functions, divided by a comma
}
// if you want to export only one function
// declare it normally and then export it
module.exports = leveling;
Calling functions.
To use this function we need to require it in the file we want to use it in. Here we also have two options.
Either require the whole file and get the function from there
const myfunctions = require('./functions.js'); // this is the relative path to the file
// get the function via the new constant
myfunctions.leveling(message);
Or use Object destructuring to get only what you need from the exported functions.
const { leveling } = require('./functions.js');
leveling(message);
Both of these options provide advantages and disadvantages but in the end they both do the same.

How do I code event/command handlers for my Discord.js bot?

I've started creating a Discord bot in Node.js using the Discord.js library. However, all the code is contained within a single index file.
How do I organize the commands and events each into separate files, and run them when needed?
An excellent, clean way to organize the code for your bot is to employ event and command handlers.
In simple terms.
You start out with a small index file to initialize the client and the rest of the code. An event handler keeps the files for each event, and calls on them when the event is emitted. Then, in your client's message event, you can avoid long if chains and switch/case altogether by running the code from the intended command's file.
What's a module?
The basic Node.js structure you'll need to understand is a module.
[A module is a] set of functions you want to include in your application.
Quoted from w3schools.com.
So, think of a module as a neatly taped up box containing pieces of code. You can take the package somewhere, open it up, and unpack the pieces. In JavaScript terms, you can require the module somewhere else in your program, and utilize the code contained within it. Modules can contain variables, classes, functions, etc. that you need to use throughout different locations across your code.
Working with modules and exports.
Now that you know what a module is, you have to understand how to work with them.
For the purpose of the handlers, you're only going to be using the exports property of the module object. By using require() for a module, module.exports is returned. Consider the following setups.
A single export.
Question.js
class Question {
constructor(author, details) {
this.author = author;
this.details = details;
this.answers = [];
}
}
module.exports = Question;
newQuestion.js
const Question = require('./Question.js');
const myQuestion = new Question('me', 'How to code event/command handlers?');
In Question.js, a new class, Question, is created and assigned to module.exports. Then, when Question.js is required in newQuestion.js, Question is declared as the exported class. It can be used just as usual.
Multiple exports.
Now, for example, if you needed to export multiple classes...
Posts.js
class Question {...}
class Answer {...}
module.exports = { Question, Answer };
// Alternatively...
// module.exports.Question = Question;
// module.exports.Answer = Answer;
newQuestion.js
const { Question } = require('./Posts.js');
const myQuestion = new Question(...);
In this way, module.exports is defined as an object, containing the created classes. This means that require() will return an object instead, so you can destructure the needed class from the object.
Creating the event handler.
You should start by creating a folder for your events, and create a file for each one. Name the files according to the name of the event. For example, for your client's message event, the file should be named message.js.
Setting up the event files.
Implementing what you now know about modules, you can code the event files. For example...
message.js
module.exports = (client, message) => {
// This code will be executed when
// the 'message' event is emitted.
};
Setting up the handler.
To make the actual handler, you can place the following code in a function to load events...
const requireAll = require('require-all'); // Don't forget to install!
const files = requireAll({ // Require all the files within your
dirname: `${__dirname}/events`, // event directory which have a name
filter: /^(?!-)(.+)\.js$/ // ending in '.js' NOT starting
}); // with '-' (a way to disable files).
client.removeAllListeners(); // Prevent duplicate listeners on reload.
// CAUTION: THIS REMOVES LISTENERS
// ATTACHED BY DISCORD.JS!
for (const name in files) { // Iterate through the files object
const event = files[name]; // and attach listeners to each
// event, passing 'client' as the
client.on(name, event.bind(null, client)); // first parameter, and the rest
// of the expected parameters
console.log(`Event loaded: ${name}`); // afterwards. Then, log the
} // successful load to the console.
Now, when your client emits one of the events you have a file for, the code inside of it is run.
Creating the command handler.
Just like for the event handler, you should start by creating a separate folder for your commands, and create files for each individual command.
Setting up the command files.
Instead of exporting just one function, you can export a "run" function and a configuration object.
help.js
module.exports.run = async (client, message, args) => {
// This code will be executed to
// run the 'help' command.
};
module.exports.config = {
name: 'help',
aliases: ['h'] // Even if you don't want an alias, leave this as an array.
};
Setting up the handler.
Just like the event handler, place this code in a function to load commands...
const requireAll = require('require-all'); // Using the same npm module...
const files = requireAll({ // Require all the files within your
dirname: `${__dirname}/commands`, // command directory which have a name
filter: /^(?!-)(.+)\.js$/ // ending in '.js' NOT starting
}); // with '-' (a way to disable files).
client.commands = new Map(); // Create new Maps for the corresponding
client.aliases = new Map(); // command names/commands, and aliases.
for (const name in files) { // Iterate through the files object
const cmd = files[name]; // and set up the 'commands' and
// 'aliases' Maps. Then, log the
client.commands.set(cmd.config.name, cmd); // successful load to the console.
for (const a of cmd.config.aliases) client.aliases.set(a, cmd.config.name);
console.log(`Command loaded: ${cmd.config.name}`);
}
In your client's message event, you can use the following code to run the commands...
const prefix = '!'; // Example
const [cmd, ...args] = message.content.trim().slice(prefix.length).split(/\s+/g);
const command = client.commands.get(cmd) || client.commands.get(client.aliases.get(cmd));
if (command) {
command.run(client, message, args);
console.log(`Executing ${command.config.name} command for ${message.author.tag}.`);
}
FAQ.
What if I have a database related or other variable I need to pass through events/commands?
For events, you can pass your variable in event.on(...), following client. Then in your actual events, your function must include that parameter after client.
For commands, you can pass your variable into the run function when calling it in the message event. Again, in your function, you need to include the properly placed parameter.
What if I want to have commands/events within subfolders?
Check out this answer to search recursively.
How do I use these handlers for a reload command?
If you placed the code for them inside of functions, you can set up a "reload" command that calls those functions, loading the events and commands again.
Related resources.
Node.js Documentation
MDN Documentation
W3Schools Tutorial
require-all Package
Discord.js Documentation
Edits...
client.removeAllListeners() will remove all listeners attached to the client, including those originating from client instantiation. This can cause voice connection related errors, specifically Voice connection not established within 15 seconds being thrown. To prevent this issue, keep track of every listener function and remove each individually using client.removeListener(listener).

Evalute JS file with template strings from another file

I would like to make use of a function called executeJavaScript() from the Electron webContents API. Since it is very close to eval() I will use this in the example.
The problem:
I have a decent sized script but it is contained in a template string.
Expanding this app, the script could grow a lot as a string.
I am not sure what the best practices are for this.
I also understand that eval() is dangerous, but I am interested in the principal of my question.
Basic eval example for my question:
// Modules
const fs = require('fs');
// CONSTANTS
const EXAMPLE_1 = 'EXAMPLE_1';
const EXAMPLE_2 = 'EXAMPLE_2';
const EXAMPLE_3 = 'EXAMPLE_3';
const exampleScriptFunction = require('./exampleScriptFunction');
const exampleScriptFile = fs.readFileSync('./exampleScriptFile.js');
// using direct template string
eval(`console.log(${EXAMPLE_1})`);
// using a method from but this doesnt solve the neatness issue.
eval(exampleScriptFunction(EXAMPLE_2));
// What I want is to just use a JS file because it is neater.
eval(`${exampleScriptFile}`);
exampleScriptFunction.js
module.exports = function(fetchType) {
return `console.log(${fetchType});`;
}
This will allow me to separate the script to a new file
what if I have many more then 1 variable???
exampleScriptFile.js:
console.log(${EXAMPLE_3});
This clearly does not work, but I am just trying to show my thinking.
back ticks are not present, fs loads as string, main file has back ticks.
This does not work. I do not know how else to show what I mean.
Because I am loading this will readFileSync, I figured the es6 template string would work.
This allows me to write a plain js file with proper syntax highlighting
The issue is the variables are on the page running the eval().
Perhaps I am completely wrong here and looking at this the wrong way. I am open to suggestions. Please do not mark me minus 1 because of my infancy in programming. I really do not know how else to ask this question. Thank you.
Assuming your source is stored in exampleScriptFile:
// polyfill
const fs = { readFileSync() { return 'console.log(`${EXAMPLE_3}`);'; } };
// CONSTANTS
const EXAMPLE_1 = 'EXAMPLE_1';
const EXAMPLE_2 = 'EXAMPLE_2';
const EXAMPLE_3 = 'EXAMPLE_3';
const exampleScriptFile = fs.readFileSync('./exampleScriptFile.js');
// What I want is to just use a JS file because it is neater.
eval(exampleScriptFile);
Update
Perhaps I wasn't clear. The ./exampleScriptFile.js should be:
console.log(`${EXAMPLE_3}`);
While what you're describing can be done with eval as #PatrickRoberts demonstrates, that doesn't extend to executeJavaScript.
The former runs in the caller's context, while the latter triggers an IPC call to another process with the contents of the code. Presumably this process doesn't have any information on the caller's context, and therefore, the template strings can't be populated with variables defined in this context.
Relevant snippets from electron/lib/browsers/api/web-contents.js:
WebContents.prototype.send = function (channel, ...args) {
// ...
return this._send(false, channel, args)
}
// ...
WebContents.prototype.executeJavaScript = function (code, hasUserGesture, callback) {
// ...
return asyncWebFrameMethods.call(this, requestId, 'executeJavaScript',
// ...
}
// ...
const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
return new Promise((resolve, reject) => {
this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
// ...
})
}
Relevant snippets from electron/atom/browser/api/atom_api_web_contents.cc
//...
void WebContents::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "WebContents"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
// ...
.SetMethod("_send", &WebContents::SendIPCMessage)
// ...
}

Load "Vanilla" Javascript Libraries into Node.js

There are some third party Javascript libraries that have some functionality I would like to use in a Node.js server. (Specifically I want to use a QuadTree javascript library that I found.) But these libraries are just straightforward .js files and not "Node.js libraries".
As such, these libraries don't follow the exports.var_name syntax that Node.js expects for its modules. As far as I understand that means when you do module = require('module_name'); or module = require('./path/to/file.js'); you'll end up with a module with no publicly accessible functions, etc.
My question then is "How do I load an arbitrary javascript file into Node.js such that I can utilize its functionality without having to rewrite it so that it does do exports?"
I'm very new to Node.js so please let me know if there is some glaring hole in my understanding of how it works.
EDIT: Researching into things more and I now see that the module loading pattern that Node.js uses is actually part of a recently developed standard for loading Javascript libraries called CommonJS. It says this right on the module doc page for Node.js, but I missed that until now.
It may end up being that the answer to my question is "wait until your library's authors get around to writing a CommonJS interface or do it your damn self."
Here's what I think is the 'rightest' answer for this situation.
Say you have a script file called quadtree.js.
You should build a custom node_module that has this sort of directory structure...
./node_modules/quadtree/quadtree-lib/
./node_modules/quadtree/quadtree-lib/quadtree.js
./node_modules/quadtree/quadtree-lib/README
./node_modules/quadtree/quadtree-lib/some-other-crap.js
./node_modules/quadtree/index.js
Everything in your ./node_modules/quadtree/quadtree-lib/ directory are files from your 3rd party library.
Then your ./node_modules/quadtree/index.js file will just load that library from the filesystem and do the work of exporting things properly.
var fs = require('fs');
// Read and eval library
filedata = fs.readFileSync('./node_modules/quadtree/quadtree-lib/quadtree.js','utf8');
eval(filedata);
/* The quadtree.js file defines a class 'QuadTree' which is all we want to export */
exports.QuadTree = QuadTree
Now you can use your quadtree module like any other node module...
var qt = require('quadtree');
qt.QuadTree();
I like this method because there's no need to go changing any of the source code of your 3rd party library--so it's easier to maintain. All you need to do on upgrade is look at their source code and ensure that you are still exporting the proper objects.
There is a much better method than using eval: the vm module.
For example, here is my execfile module, which evaluates the script at path in either context or the global context:
var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
context = context || {};
var data = fs.readFileSync(path);
vm.runInNewContext(data, context, path);
return context;
}
And it can be used like this:
> var execfile = require("execfile");
> // `someGlobal` will be a global variable while the script runs
> var context = execfile("example.js", { someGlobal: 42 });
> // And `getSomeGlobal` defined in the script is available on `context`:
> context.getSomeGlobal()
42
> context.someGlobal = 16
> context.getSomeGlobal()
16
Where example.js contains:
function getSomeGlobal() {
return someGlobal;
}
The big advantage of this method is that you've got complete control over the global variables in the executed script: you can pass in custom globals (via context), and all the globals created by the script will be added to context. Debugging is also easier because syntax errors and the like will be reported with the correct file name.
The simplest way is: eval(require('fs').readFileSync('./path/to/file.js', 'utf8'));
This works great for testing in the interactive shell.
AFAIK, that is indeed how modules must be loaded.
However, instead of tacking all exported functions onto the exports object, you can also tack them onto this (what would otherwise be the global object).
So, if you want to keep the other libraries compatible, you can do this:
this.quadTree = function () {
// the function's code
};
or, when the external library already has its own namespace, e.g. jQuery (not that you can use that in a server-side environment):
this.jQuery = jQuery;
In a non-Node environment, this would resolve to the global object, thus making it a global variable... which it already was. So it shouldn't break anything.
Edit:
James Herdman has a nice writeup about node.js for beginners, which also mentions this.
I'm not sure if I'll actually end up using this because it's a rather hacky solution, but one way around this is to build a little mini-module importer like this...
In the file ./node_modules/vanilla.js:
var fs = require('fs');
exports.require = function(path,names_to_export) {
filedata = fs.readFileSync(path,'utf8');
eval(filedata);
exported_obj = {};
for (i in names_to_export) {
to_eval = 'exported_obj[names_to_export[i]] = '
+ names_to_export[i] + ';'
eval(to_eval);
}
return exported_obj;
}
Then when you want to use your library's functionality you'll need to manually choose which names to export.
So for a library like the file ./lib/mylibrary.js...
function Foo() { //Do something... }
biz = "Blah blah";
var bar = {'baz':'filler'};
When you want to use its functionality in your Node.js code...
var vanilla = require('vanilla');
var mylibrary = vanilla.require('./lib/mylibrary.js',['biz','Foo'])
mylibrary.Foo // <-- this is Foo()
mylibrary.biz // <-- this is "Blah blah"
mylibrary.bar // <-- this is undefined (because we didn't export it)
Don't know how well this would all work in practice though.
I was able to make it work by updating their script, very easily, simply adding module.exports = where appropriate...
For example, I took their file and I copied to './libs/apprise.js'. Then where it starts with
function apprise(string, args, callback){
I assigned the function to module.exports = thus:
module.exports = function(string, args, callback){
Thus I'm able to import the library into my code like this:
window.apprise = require('./libs/apprise.js');
And I was good to go. YMMV, this was with webpack.
A simple include(filename) function with better error messaging (stack, filename etc.) for eval, in case of errors:
var fs = require('fs');
// circumvent nodejs/v8 "bug":
// https://github.com/PythonJS/PythonJS/issues/111
// http://perfectionkills.com/global-eval-what-are-the-options/
// e.g. a "function test() {}" will be undefined, but "test = function() {}" will exist
var globalEval = (function() {
var isIndirectEvalGlobal = (function(original, Object) {
try {
// Does `Object` resolve to a local variable, or to a global, built-in `Object`,
// reference to which we passed as a first argument?
return (1, eval)('Object') === original;
} catch (err) {
// if indirect eval errors out (as allowed per ES3), then just bail out with `false`
return false;
}
})(Object, 123);
if (isIndirectEvalGlobal) {
// if indirect eval executes code globally, use it
return function(expression) {
return (1, eval)(expression);
};
} else if (typeof window.execScript !== 'undefined') {
// if `window.execScript exists`, use it
return function(expression) {
return window.execScript(expression);
};
}
// otherwise, globalEval is `undefined` since nothing is returned
})();
function include(filename) {
file_contents = fs.readFileSync(filename, "utf8");
try {
//console.log(file_contents);
globalEval(file_contents);
} catch (e) {
e.fileName = filename;
keys = ["columnNumber", "fileName", "lineNumber", "message", "name", "stack"]
for (key in keys) {
k = keys[key];
console.log(k, " = ", e[k])
}
fo = e;
//throw new Error("include failed");
}
}
But it even gets dirtier with nodejs: you need to specify this:
export NODE_MODULE_CONTEXTS=1
nodejs tmp.js
Otherwise you cannot use global variables in files included with include(...).

Load and execute external js file in node.js with access to local variables?

Is it easy/possible to do a simple include('./path/to/file') type of command in node.js?
All I want to do is have access to local variables and run a script. How do people typically organize node.js projects that are bigger than a simple hello world? (A fully functional dynamic website)
For example I'd like to have directories like:
/models
/views
... etc
Just do a require('./yourfile.js');
Declare all the variables that you want outside access as global variables.
So instead of
var a = "hello" it will be
GLOBAL.a="hello" or just
a = "hello"
This is obviously bad. You don't want to be polluting the global scope.
Instead the suggest method is to export your functions/variables.
If you want the MVC pattern take a look at Geddy.
You need to understand CommonJS, which is a pattern to define modules. You shouldn't abuse GLOBAL scope that's always a bad thing to do, instead you can use the 'exports' token, like this:
// circle.js
var PI = 3.14; // PI will not be accessible from outside this module
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
And the client code that will use our module:
// client.js
var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));
This code was extracted from node.js documentation API:
http://nodejs.org/docs/v0.3.2/api/modules.html
Also, if you want to use something like Rails or Sinatra, I recommend Express (I couldn't post the URL, shame on Stack Overflow!)
If you are writing code for Node, using Node modules as described by Ivan is without a doubt the way to go.
However, if you need to load JavaScript that has already been written and isn't aware of node, the vm module is the way to go (and definitely preferable to eval).
For example, here is my execfile module, which evaluates the script at path in either context or the global context:
var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
var data = fs.readFileSync(path);
vm.runInNewContext(data, context, path);
}
Also note: modules loaded with require(…) don't have access to the global context.
If you are planning to load an external javascript file's functions or objects, load on this context using the following code – note the runInThisContext method:
var vm = require("vm");
var fs = require("fs");
var data = fs.readFileSync('./externalfile.js');
const script = new vm.Script(data);
script.runInThisContext();
// here you can use externalfile's functions or objects as if they were instantiated here. They have been added to this context.
Expanding on #Shripad's and #Ivan's answer, I would recommend that you use Node.js's standard module.export functionality.
In your file for constants (e.g. constants.js), you'd write constants like this:
const CONST1 = 1;
module.exports.CONST1 = CONST1;
const CONST2 = 2;
module.exports.CONST2 = CONST2;
Then in the file in which you want to use those constants, write the following code:
const {CONST1 , CONST2} = require('./constants.js');
If you've never seen the const { ... } syntax before: that's destructuring assignment.
Sorry for resurrection. You could use child_process module to execute external js files in node.js
var child_process = require('child_process');
//EXECUTE yourExternalJsFile.js
child_process.exec('node yourExternalJsFile.js', (error, stdout, stderr) => {
console.log(`${stdout}`);
console.log(`${stderr}`);
if (error !== null) {
console.log(`exec error: ${error}`);
}
});

Categories