How to get value from modified object in Node.js - javascript

how to get modified value of object? index.js is called before index2.js
object.js
var object = {
size:'5'
};
var setSize = function(size) {
object.size = size;
}
exports.object = object;
exports.setSize = setSize;
index.js
var obj = require('path/object');
obj.setSize('10');
console.log(obj.object.size); //--> 10
index2.js
I want the result to be 10.
var obj = require('path/object');
console.log(obj.object.size); //--> 5

If you run node index.js separately from node index2.js, there is no way for index2.js to "know" what happened in the last process of index.js. You have to apply all your actions in a single process run. As #Andrew Li stated in his comment, you would have to require index.js in your index2.js. Simply requiring it, will have it's code executed and the changes to obj.object will be saved in Nodes module caching mechanism.
var obj = require('path/object');
require('./index');
// code inside index.js gets executed, changing obj.size to '10'
// note that this will also log '10' in the console, since a console.log(obj.size)
// is part of your code in index.js
console.log(obj.object.size) //--> 10
If you need to have index.js and index2.js executed in different processes but still be able to access a coherent value of obj, you need to store that value somewhere outside of the process space, like in a database or in the filesystem.

Related

Discord bot Command That changes Value of a different command

I'm looking for a way to change a text string or a value in one command by typing the new value in a different command. For example I have Discord js v12 and I'm using module commands with each command being in its own .js file.
module.exports = {
name: 'calc',
cooldown: 1000,
run: async(client, message, args) => {
if (!message.member.hasPermission("ADMINISTRATOR")) return await message.delete();
await message.delete();
var multiply = args[0] * (100 - percalc) / 100;
var calculation = multiply.toFixed(2);
if(!args[0]) return await message.channel.send('Specify a Value');
await message.channel.send(changableValue);
await message.channel.send(calculation < 5 ? 5 : calculation);
}
and I have the consts in the config file like
const percalc = 50;
const changableValue = 'Text example';
Right now the command _calc {number} puts out a calculation in percentage based on the percalc const and a text that comes with it in the changableValue part.
I'd like to make a command let's say _calcset {Value} that will save the provided value and will send it in place of the changableValue const.
First of all, note that the only reason the keyword const exists is because it stands for constant and constant variables can never be changed once initialized. So make sure you change the variable declaration keyword to just var or let.
Method 1 - If you don't need data to persist
Now, if you only want the variable to be changed per session, and you're fine with it going back to what you defined it as when you shut down the bot, you can just update the variable using functions exported from the js file. But to get the dynamic variable you'll also need to use a getter function that you export as well. Example:
config.js
var changeableValue = "foo";
function getValue() {
return changeableValue;
}
function updateValue(newValue) {
changeableValue = newValue;
}
module.exports = {
getValue,
updateValue
}
command.js
const { getValue, updateValue } = require("config.js");
console.log(getValue()); // logs "foo"
updateValue("bar");
console.log(getValue()); // logs "bar"
Unfortunately, as I mentioned, the changeableValue var will be reset back to "foo" every time you shut off the bot. If that's okay with you, then the above works fine.
Method 2 - If you need data to persist through sessions
If you want to persist the changeableValue variable through sessions, then it gets a little more complicated. Your two most likely options are either to write the value to a JSON file using the fs module (so it will be saved to your disk), or save the value in some other database, like MongoDB. I would recommend using another database provider because there are more problems you can run into when writing to your own disk, for example, if you make two write requests at the same time (like if two users use the command at the same time), you can corrupt the file when the requests try to write at the same time. However setting up an external database is outside of the scope of this question, so here's how you would set up writing to a JSON file:
config.json
{
"changeableValue": "foo"
}
command.js
const fs = require("fs");
var { changeableValue } = require("config.json");
console.log(changeableValue) // logs "foo"
var updatedValueJSON = JSON.stringify({ changeableValue: "bar" }); // necessary because the JSON object must be converted to a string
fs.writeFile("config.json", updatedValueJSON, "utf8", () => {
// this is the callback function called when the file write completes
let { changeableValue } = require("config.json");
console.log(changeableValue); // logs "bar", and now if you restart the bot and import changeableValue, it will still be bar
});

Cross-module variable in node.js

this question might have been asked already but all I find are specific case and I can't find a way to use the answers to solve my own problem.
What I want is a variable than has a single instance and is shared between modules/files
Let's say I have app.js and module.js
app.js:
var mymodule = require('./modules/mymodule.js');
var testVar = 'test';
...
mymodule.js:
var mymodule = {count:0}
var logCount = function() {console.log(mymodule.count);}
module.exports = mymodule;
Then with this code when app execute mymodule.count = 1, if after mymodules.js run logCount() it will log 1, this means that app and mymodule are sharing the exact same instance of mymodule.count
Now how can mymodule.js access to the same instance as testVar used by app.js in a way that if app.js change it's value, mymodule will have the same new value.
For exemple in normal javascript, if you include two scripts in an html page, as long as the variable isn't inside a function, every javascript file can access the variable, because it works as if all the script would have been pasted inside a single file, isn't there a way to obtain the same result in node?

Creating Node.JS Module

I have been creating software in NodeJS for years, but I have rarely ever looked into the module side of it, since I've never needed to do that stuff myself.
I have created a test.js file, which is my module, all it contains is this (i've tried this.host, self.host, var host ... nothing is working)
var tests = function () {
this.host = "http://127.0.0.1/";
};
exports = tests;
In my server.js I try and use it and I can never get host to actually output
var tests = require('./test.js');
console.log(tests);
console.log(tests.host);
I always get this output, saying that tests variable has no properties ... which I set in the module.
sudo node server.js
{}
undefined
The host variable as you defined it in the tests function is not accessible through tests's prototype.
This means that in order to access it, you should be creating a new instance of tests, using the new operator :
var Tests = require('./tests');
var instance = new Tests();
// Now you can access `instance.host`
Also, as David said, use module.exports to export your function.
Don't do exports = tests. Either do exports.tests = tests or module.exports = tests.
Basically, you have to first decide if you want your module to just have properties that can be directly accessed or if you want it to have a constructor function that creates an object when it is called that then has properties or it could even just be a regular function that you call that returns a value. You have mixed and matched the first two schemes (pieces of each) and thus it does not work. I will show you both schemes:
Here's the scheme where your module exports a constructor function from which you can create an object (when you new it):
// test.js module
var tests = function () {
this.host = "http://127.0.0.1/";
};
module.exports = tests;
// main module server.js
var Tests = require('./test.js');
var t = new Tests();
console.log(t.host);
And, here's the scheme where you just directly export properties:
// test.js module
module.exports = {
host: "http://127.0.0.1/"
};
// main module server.js
var tests = require('./test.js');
console.log(tests);
console.log(tests.host);
Keep in mind that whatever you assign to module.exports is what require() will return after it loads your module. So, in your first case, you're assigning a function that is intended to be a constructor function so you have to use it as a constructor function in order for it to work properly.
In my second example, I assign an object to module.exports so you can then treat it just like an object after loading the module with require(). That means you can then just directly access its properties as you would for an object.
console.log(tests()); will work if the you add return statement inside the function.

Can we do anything without using Sync methods, or in some cases, we must use Sync methods in node.js?

For instance, I have app.js to have a Module object:M by loading(require) a file:_core.js, then properties of M are to add by loading(require) files under a directory: ./Project_Functions/
var Project_FunctionsDIR = './Project_Functions/';
var Project_coreFile = '_core.js';
var M = require(Project_FunctionsDIR + Project_coreFile);
require("fs")
.readdir(Project_FunctionsDIR,
function(err, files)
{
files.forEach(function(file)
{
if (file !== Project_coreFile)
{
var name = file.split('.js')[0];
var filepath = Project_FunctionsDIR + file;
M[name] = require(filepath);
}
});
});
console.log('module.exports');
module.exports = M;
Here, the constructed moduleObject:M is exported by module.exports.
Please note the fs.readdir is async, so module.exports = M; is evaluated before M properties are constructed in app.js.
Now, I want to test this object M in test.js,
var expect = require('chai').expect;
var M = require('./app.js');
//........
On var M = require('./app.js'); line, the app.js is evaluated, which indicates that the M object is exported before the whole properties are constructed.
In fact, I inserted setTimeout at the fs.readdir callback, the test fails obviously the M object is not ready yet.
Firstly, I thought module.exports = M; should be put within the fs.readdir callback, but if I do that, now var M = require(Project_FunctionsDIR + Project_coreFile); part fails, probably because module.exports = M; is not exposed to read properly.
Yes, this can be resolved simply by using fs.readdirSync and actually, I have been doing so when I encounter this sort of problem, however, I always feel uncomfortable to use node Sync methods and rather try to seek a smarter work-around.
So, here's my question; is it possible by not using Sync method for this issue? or impossible?
Furthermore, I'd like to ask more in general.
Can we do anything without using Sync methods, or in some cases, we must use Sync methods in node.js?
In functional programming scheme, Sync methods should be avoided if possible since the Sync concept depends on not function(callback) but time.
Thanks for your thought.
EDIT:
I've just found a related topic here:
Asynchronous initialization of Node.js module
The conclusion is we must use Sync method to correspond a Sync method. In this case, require is a sync method.
A common pattern is for the module to expose an asynchronous initialize method that does the asynchronous work. For your module, it would look like this:
var Project_FunctionsDIR = './Project_Functions/';
var Project_coreFile = '_core.js';
var M = require(Project_FunctionsDIR + Project_coreFile);
M.initialize = function(next) {
require("fs")
.readdir(Project_FunctionsDIR,
function(err, files)
{
files.forEach(function(file)
{
if (file !== Project_coreFile)
{
var name = file.split('.js')[0];
var filepath = Project_FunctionsDIR + file;
M[name] = require(filepath);
}
});
next();
});
}
module.exports = M;
Then you can test it with:
var M = require('./app.js');
M.initialize(function() {
//........
}
This is a useful pattern because many asynchronous methods don't have synchronous versions, and it allows you to run many of these asynchronous initializes in parallel, drastically reducing startup time for larger apps.
node.js uses CommonJS module pattern, which by definition export their exposed objects synchronously on load. What you're trying to do is not possible asynchronously, although you can do it just by exposing the other files into your 'main' export. If you want to dynamically expose all files in a directory from one object, just use the synchronous readdir, it'll only be executed on start up.

Nodejs set command line argument as constant

I want to get an argv from my command line when I am going to start my server and then I want to set it as a constant for a module.
For example I want to define my log file path from commandline:
My starter.js looks like:
var optimist = require("optimist");
var server = require("./start_server");
var argv = optimist.describe('logpath', 'logptah for info').argv;
server.init({logpath:argv.logpath});
My start_server.js looks like:
var restify = require('restify');
var server = restify.createServer({
name: 'dummy-project'
});
module.exports.logpath = null;
function init(args){
server.listen(1234, function() {
console.log("inside logs");
console.log(args.logpath);
module.exports.logpath = args.logpath;
console.log('%s listening at %s', server.name, server.url);
});
};
module.exports.init = init;
var fun = require('./common/loghandler');
My loghandler.js looks like:
var server = require('./../start_server');
console.log("inside log handler");
var LOGPATH = server.logpath;
console.log(LOGPATH);
When I am running node starter.js --logpath='../../custom/info.txt'
I am not getting the logpath inside my loghandler.
Seems logpath handler is called before the server.listen.
The console output looks like:
node starter.js --logpath='../../custom/info.txt'
inside log handler
null
inside log handler
../../custom/info.txt
dummy-project listening at http://0.0.0.0:1234
How I can overcome it and pass my log path as command line argument?
Thanks in advance.
Your init() function is executed after starter.js uses require('./start_server'). When you use require(), the file and all its dependencies are loaded. That means during this process, you also executed require('./common/loghandler'), which completes before server.init() is run in starter.js. Since server.logpath hasn't been set by this time, you get a null value.
Aside from that, module.exports is set at require time and changing the values later have no effect. To fix the problems you're having, you should avoid using functions before your application has fully loaded, and put return values in your modules.

Categories

Resources