Nodejs execute exported function from string - javascript

I want to know if it's possible to run a function that is named a string in nodejs. All this code is running on the server side with no browser appearance at all.
Assuming I export a file test.js with the following code
module.exports.test = function(x)
{
console.log(x*5);
}
Can I do this somehow?
main.js
imp = require('test.js');
toExecute = "test";
// somehow call imp.test using toExecute`

Sure:
imp[toExecute](5);
Logs 25.

Related

Running python script from MagicMirror module

I am currently developing a custom module for my magic mirror.
I want this module to execute a python script.
This python script fetches data from a web server and creates a .json file in the module folder with the data.
I then want the module to import this datafile inside javascript and display it on screen.
However i cant get the magic mirror module to run the python script.
I have very little javascript knowledge so any help is appreciated.
This is the code i have so far
defaults: {
},
start: function () {
var timer = setInterval(()=>{
const spawn = require('child_process').spawn;
const childPython = spawn('python3', ['./modules/MMM-Test/bussavganger.py']);
this.updateDom()
}, 5000)
},
getDom: function() {
var element = document.createElement("div")
element.className = "myContent"
element.innerHTML = "Hello, everybody!"
return element
}
})
Currently i am just trying to run the module to see if the .json file is created. it is not.
If i run the python script separately the file is created, so i know the .py file is not the problem.
You tried calling the python script via your module's js file, but instead you should use to call the python script via the node_helper.js file.
So use the socketNotification function of the MagicMirror to call the noder_helper and in return the node_helper then calls your python script, you can do something with it and at the end send back a socketNotification to your module's js file, e. g. the result of your python program or the exit code, etc.
In your start: function() you could call the node_helper via this command, so that your python program is being started by the module helper later directly after booting up your module (doing that from now on every interval):
var self = this;
setInterval(function() {
self.sendSocketNotification('DO_PYTHON', <transmit data for your node_helper here>);
self.updateDom();
}, 5000);
Create a node_helper.js file in your module folder with the following:
var NodeHelper = require("node_helper");
const spawn = require("child_process").spawn;
module.exports = NodeHelper.create({
init() {
},
start() {
},
stop() {
},
// If notification of the main.js file is received, the node_helper will do this here:
socketNotificationReceived(notification, payload) {
if (notification === "DO_PYTHON") {
// this.config = payload;
this.yourOwnMethod();
} else {
// ...
}
},
yourOwnMethod() {
var self = this;
var process = spawn("python3", ["/absolute/path/to/modules/MMM-Test/bussavganger.py"]);
// do something else here
this.sendSocketNotification("PYTHON_DONE", <e. g. exit state as your payload>)
},
You can read in your json file with fs in the node_helper.js as well and parse it there and send it back via the sendSocketNotification.
Be sure to have included the two beginning lines in the node_helper.js and (!) important use always absolute paths.

How to use multiple js files with Duktape?

I'm using Duktape in embedded MCU. For test case i have:
main.js file:
(function(){
test();
})();
test.js file:
(function test(){
print("func");
})
Both compiled as global default code and main.js is executed with duk_call(ctx, 0);
The problem is it throws error when calling a test() function.
I've also tried using just
function test() {
print("test");
}
in test.js code, but it does not work either.
What I understand is that both files have separate execution context. That is why function is inaccessible.
But what is the right way to split code into multiple files for Duktape?
P.S. I am aiming to avoid using global context, because in documentation it is said that accessing variables is slow this way, that's why main.js looks that way.
P.P.S. I'm sure that test() function is unreachable, but I don't know how to write js code so that everything works.
P.P.P.S print() is a C function that outputs to serial port of esp32 and it works. even main.js works without a test() function call.
Basically, what you want is file import functionality. You can implement that in two ways:
Provide a function in your backend and export that to JS, to allow loading a file dynamically at runtime.
Implement module handling like in Node.js (which essentially also boils down to an import function).
The second idea is what is used most and implements a well defined approach to include other files in your JS application. Duktape comes with an extra file that implements the require command, just like in Node.js. You only have to provide your own functions for resolving a module and to load it from disk (as duktape has not file I/O support).
I implemented this approach in the MGA tool in MySQL Workbench. The duktape file for implementing node module handling is here. The function to resolve modules (which includes handling of nested node_modules folders etc.) is implemented in the ScriptingContext class. The relevant part of it is this:
/**
* Part of the module loading machinery. JS interfacing is done by the duk_module_node code.
* But we have to do the file work here. On the stack we get the value passed to `require()` as a "module ID" and
* the ID of the calling script (which is empty for the main script).
*/
duk_ret_t ScriptingContext::resolveModule(duk_context *ctx) {
// stack: [ requested_id parent_id ]
std::string requestedID = duk_get_string(ctx, 0);
std::string callingID = duk_get_string(ctx, 1);
std::string parentPath = FS::isDir(callingID) ? callingID : Path::dirname(callingID);
// Module resolution strategy in Node.js style: https://nodejs.org/api/modules.html#modules_all_together
auto modules = getInternalModules();
if (modules.find(requestedID) != modules.end()) {
duk_push_string(ctx, requestedID.c_str());
return 1;
}
ScriptingContext *context = ScriptingContext::fromDuktapeContext(ctx);
std::string resolvedID;
std::string cwd = Process::cwd();
try {
if (Path::isAbsolute(requestedID) || Utilities::hasPrefix(requestedID, ".")) {
std::string temp;
if (Path::isAbsolute(requestedID)) {
temp = Path::relative(cwd, requestedID);
} else
temp = Path::join({ parentPath, requestedID });
resolvedID = resolveFile(temp);
if (resolvedID.empty())
resolvedID = resolveFolder(context, temp);
}
} catch (std::runtime_error &e) {
// Triggered for parse errors in package.json.
context->throwScriptingError(ScriptingError::Syntax, e.what());
return 0;
}
// No files found so far. Check node modules.
if (resolvedID.empty()) {
for (auto &folder : moduleFolders(parentPath)) {
std::string path = Path::join({ folder, requestedID });
std::string temp = resolveFile(path);
if (!temp.empty()) {
resolvedID = temp;
break;
}
temp = resolveFolder(context, path);
if (!temp.empty()) {
resolvedID = temp;
break;
}
}
}
if (resolvedID.empty()) {
context->throwScriptingError(ScriptingError::Error, Utilities::format("Cannot resolve module %s", requestedID.c_str()));
return 0;
}
duk_push_string(ctx, resolvedID.c_str());
return 1; // Use result on stack.
}

Can I run JavaScript inside Swift code?

I need to include JavaScript code in Swift code to be able to call a signalR chat, is that possible? If not, can I convert it?
sendmessage is a button.
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (name, message) {
// some code
};
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send('name', 'message');
});
});
});
and the signalr code is:
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
}
Update #1:
changed question a little bit so it is not confusing per #MartinR
Last tested with Swift 5.1
Here is an example you can run in Playground to get you started:
import JavaScriptCore
let jsSource = "var testFunct = function(message) { return \"Test Message: \" + message;}"
var context = JSContext()
context?.evaluateScript(jsSource)
let testFunction = context?.objectForKeyedSubscript("testFunct")
let result = testFunction?.call(withArguments: ["the message"])
result would be Test Message: the message.
You also can run JavaScript code within a WKWebView calling evaluate​Java​Script(_:​completion​Handler:​).
You can also run JavaScript within a UIWebView by calling string​By​Evaluating​Java​Script(from:​), but note that that method has been deprecated and is marked as iOS 2.0–12.0.
Using JavaScriptCore framework include JavaScript code in Swift code.
The class that you’ll be dealing the most with, is JSContext. This class is the actual environment (context) that executes your JavaScript code.
All values in JSContext, are JSValue objects, as the JSValue class represents the datatype of any JavaScript value. That means that if you access a JavaScript variable and a JavaScript function from Swift, both are considered to be JSValue objects.
I strongly advise you to read the official documentation regarding the JavaScriptCore framework. 
import JavaScriptCore
var jsContext = JSContext()
// Specify the path to the jssource.js file.
if let jsSourcePath = Bundle.main.path(forResource: "jssource", ofType: "js") {
do {
// Load its contents to a String variable.
let jsSourceContents = try String(contentsOfFile: jsSourcePath)
// Add the Javascript code that currently exists in the jsSourceContents to the Javascript Runtime through the jsContext object.
self.jsContext.evaluateScript(jsSourceContents)
}
catch {
print(error.localizedDescription)
}
}
more details refer this tutorial

Set a Javascript function to be all the code in another .js file

I have a file doSomething.js that contains some code that needs to be run both from the command line (eg: node doSomething.js) and also from a nodejs-based queue worker
queueWorker.js
var worker = client.worker(['example']);
worker.register({
doSomething: function (params, callback) {
// run the code contained in doSomething.js
}
});
worker.start();
doSomething.js
console.log('Hello world')
Question: Is there a way to let the main code remain in doSomething.js and just include a reference to doSomething.js in queueWorker.js? I dont want to have 2 copies of the same code in 2 different files.
So if I understand you correctly you've some code in a project that you want to be used by a command-line node script and by a worker. You don't mention how you deploy this code, so I'm going to assume that the stuff running the worker is the same codebase as the command line.
In which case I would assume that one solution is to make your doSomething.js use the standard NodeJS module system, i.e. something like
doSomething.js
module.exports = function() {
console.log('Hello, world');
}
queueWorker.js
Your worker would become something like:
var worker = client.worker(['example']);
var doSomething = require('path/to/doSomething');
worker.register({
doSomething: function (params, callback) {
doSomething();
}
});
worker.start();
doSomethingCli.js
Your command line script would be a totally separate script to the above (assuming that's okay), looking something similar to the worker:
var doSomething = require('path/to/doSomething');
doSomething();
While you stated you wanted to have doSomething.js callable from the command line that isn't a great solution - you'll find yourself starting to put cli stuff into doSomething.js which will break your queue worker. Keep the common code separate.
I assume you are using node for both cases.
queueWorker.js
var doSomething = require('./doSomething');
var worker = client.worker(['example']);
worker.register({
doSomething: function (params, callback) {
doSomething(params, callback);
}
});
worker.start();
doSomething.js
module.exports = functionv(params, callback) {
console.log('Hello world');
}
Javascript is a dynamic language and it's always possible to eval a string containing code. For example you can do this
// file1.js -------------------------
function foo() {
console.log("Hello, world.");
}
// file2.js -------------------------
eval(require('fs').readFileSync("file1.js", "utf-8"));
foo();
Of course node.js contains a much better approach if the code is indeed static and you just want to share it between different projects (the idea of modules).

How can I run two files in javascript with node?

I am new to javascript and Node.js and having problems testing some code I wrote recently. I am trying to test code written in a file called "compareCrowe.js" with "testCrowe.js" using Node.js.
Here are the contents of testCrowe.js:
var compareCrowe = required['./compareCrowe'];
console.log('begin test');
var connection = {Type:1, Label:"label", linkTo:null};
var table1 = {name:"table1", body:"description1", out:[connection]};
var table2 = {name:"table2", body:"description2", out:null};
connection.linkTo = table2;
var crowe = [table1, table2];
var result = compareCrowe.compareCrowesFoot(crowe, crowe);
console.log(result.feedback);
where the function "compareCrowesFoot" is defined in compareCrowe.js. From the console on an Ubuntu virtual machine I ran:
node compareCrowe.js testCrowe.js
however, nothing was printed. There were no errors or warnings or explanation of any kind. It didn't even print the "begin test" line I placed at the top of testCrowe.js. If I run the command:
node testCrowe.js
it complains that compareCrowesFoot is undefined. How can I test the contents of compareCrowe.js?
Welcome to the party of JS.
I'm not sure where you're learning from, but a few of the resources that have helped me and many others are superherojs.com, nodeschool.io, the MDN developer docs, Node.js API docs, and Youtube (seriously).
The basic idea of Node.js is that it operates with modules (chunks of reusable code), which is what NPM is made up of. These can then be included in other modules and used anywhere else in your application.
So for a basic example, say you had compareCrowe.js, to make it includable/reusable in another file, you could write something like:
module.exports = function() {
var compareCrowesFoot = function(crowe1, crowe2) { /* compare crows feet and return something here */ }
return { compareCrowesFoot: compareCrowesFoot };
// return an object with a property of whatever you want to access it as , and the value as your function name
// e.g. - you could return { compare: compareCrowesFoot };
}
Then in testCrowe.js you could require compareCrowe like this:
var compareCrowe = require("./compareCrowe");
/* your code here... */
var result = compareCrowe.compareCrowesFoot(crowe1, crowe2);
// if your returned object was { compare: compareCrowesFoot };
// this would be compareCrowe.compare(crowe1, crowe1);
And to run your tests, you could then run node testCrowe.js from the command line.
In your case it seems like you've got your syntax a little messed up. It should be more like:
var compareCrowe = require('./compareCrowe.js');
That would make any methods you've exported in compareCrowe.js, such as your compareCrowe.compareCrowesFoot function, available to testCrowe.js.
Then, in your terminal, you would run the following:
node testCrowe.js
And that should do the trick provided you don't have any further errors in your code.

Categories

Resources