R integration with node script using r-script - r

I have two very simple files to test my integration setup. First the r script inside test.R:
print('hello')
Then the index.js calling that file:
var R = require("r-script");
var out = R("./test.R")
.data()
.callSync();
And this is what my console is telling me:
$ node index.js
/home/user/index.js:3
.data()
^
TypeError: Cannot read property 'data' of undefined
Currently, I am running Ubuntu 18.04 and if I run only Rscript test.R it works with no problem. Any help?

I fix my similar issue with https://github.com/joshkatz/r-script/issues/19
If you still feeling lazy to pull the git, you can directly update the source code ./node_modules/r-script/index.js , then edit the function init as
function init(path) {
var obj = new R(path);
_.bindAll(obj, "data", "call", "callSync");
return obj;
}
I hope you may find this helpful.

$ cd node_modules/r-script
$ rm node_modules
$ npm install underscore#1.8.3
in my case, downgrade underscore works

Related

How to call a Meteor method from the command line

I have a Meteor app and want to call a server method from the command line, so that I can write a bash script to perform scheduled operations.
Is there any way to either call a method directly, or submit a form which will then trigger server-side code?
I've tried using curl to call a method, but either it's not possible or I'm missing something basic. This doesn't work:
curl "http://localhost:3000/Meteor.call('myMethod')"
nor does:
curl -s -d "http://localhost:3000/imports/api/test.js" > out.html
where test.js:
var test = function(){
console.log('hello');
}
I thought of using a form but I can't think how to create a submit event because the Meteor client uses template events that then call server methods.
I'll be very grateful for any help! This feels like it should be a simple thing but has me stumped.
Edit: I've also tried phantomjs and slimerjs as run through casperjs.
phantomjs is no longer maintained and generates an error:
TypeError: Attempting to change the setter of an unconfigurable property.
https://github.com/casperjs/casperjs/issues/1935
slimerjs errors with Firefox 60 and I can't figure out how to 'downgrade' back to the supported 59, and the option to disable automatic updates of Firefox no longer seems to exist. The error is:
c is undefined
https://github.com/laurentj/slimerjs/issues/694
You could make use of the node ddp package to call the Meteor method in an own js file that you created with a specific script. From there you can pipe all outs to wherever you want.
Let's assume the following Meteor method:
Meteor.methods({
'myMethod'() {
console.log("hello console")
return "hello result"
}
})
The upcoming steps will let you call this method from another shell, assuming your Meteor application is running.
1. Install ddp in your global npm directory
$ meteor npm install -g ddp
2. Create the script to call your method in your test directory
$ mkdir -p ddptest
$ cd ddptest
$ touch ddptest.js
Place the ddp script code into the file with the editor or command of your choice.
(The follwing code is freely taken from the package's readme. Feel free to configure to your needs.)
ddptest/ddptest.js
var DDPClient = require(process.env.DDP_PATH);
var ddpclient = new DDPClient({
// All properties optional, defaults shown
host : "localhost",
port : 3000,
ssl : false,
autoReconnect : true,
autoReconnectTimer : 500,
maintainCollections : true,
ddpVersion : '1', // ['1', 'pre2', 'pre1'] available
// uses the SockJs protocol to create the connection
// this still uses websockets, but allows to get the benefits
// from projects like meteorhacks:cluster
// (for load balancing and service discovery)
// do not use `path` option when you are using useSockJs
useSockJs: true,
// Use a full url instead of a set of `host`, `port` and `ssl`
// do not set `useSockJs` option if `url` is used
url: 'wss://example.com/websocket'
});
ddpclient.connect(function(error, wasReconnect) {
// If autoReconnect is true, this callback will be invoked each time
// a server connection is re-established
if (error) {
console.log('DDP connection error!');
console.error(error)
return;
}
if (wasReconnect) {
console.log('Reestablishment of a connection.');
}
console.log('connected!');
setTimeout(function () {
/*
* Call a Meteor Method
*/
ddpclient.call(
'myMethod', // namyMethodme of Meteor Method being called
['foo', 'bar'], // parameters to send to Meteor Method
function (err, result) { // callback which returns the method call results
console.log('called function, result: ' + result);
ddpclient.close();
},
function () { // callback which fires when server has finished
console.log('updated'); // sending any updated documents as a result of
console.log(ddpclient.collections.posts); // calling this method
}
);
}, 3000);
});
The code assumes that your app runs on localhost:3000, note that there is no conncection close on errors or undesired behavior.
As you can see at the top, the file imports your globally installed ddp package. Now in order to get it's path without using additional tools, just pass an environment variable (process.env.DDP_PATH) and let your shell handle the path resolving.
In order to get the installation path you can use npm root with the global flag.
Finally call your script via:
$ DDP_PATH=$(meteor npm root -g)/ddp meteor node ddptest.js
Which will give you the following output:
connected!
updated
undefined
called function, result: hello result
And logs hello console to the open session that is running your meteor app.
Edit: A note on using this in production
If you want to use this script in production you have to use the shell commands without the meteor command but using your installation of node and npm.
If you get in trouble with paths use process.execPath to find your node binary and npm root -g to find your global npm modules.
You can check out this documentation: Command Line | meteor shell.
While your meteor app is running, you can execute meteor shell to start an interactive console. In the console, you can do Meteor.call(...).
So if you want to write a script with using meteor shell, you might need to pipe the script file for meteor shell. Like,
$ meteor shell < script_file
See also the answer of "How can I pipe a command into the meteor shell?"

Cloud functions for Firebase /usr/bin/env: node not found

My question is: how can I make node available to a shell script on Cloud functions for Firebase when I use an npm package like xml2json?
Context:
I am moving a piece of software from short-living Docker containers to Cloud functions for Firebase. The software processes large XML files and converts parts to JSON.
Due to the memory consumption, I use xmllint and xml2json via the shell.
var cmd = './xmllint --xpath "//OrderData" ' + this.filename + ' | ' + __dirname + '/node_modules/xml2json/bin/xml2json';
exec(cmd, function(error, stdout, stderr) { ... }
Xmllint works as expected (distributed in the npm package that I added to package.json in the functions directory)
"#niekoost/convertini": "file:niekoost-convertini-1.0.1.tgz"
But the pipe through xml2json produces the problem:
The first line of xml2json is causing my issue
#!/usr/bin/env node
This leads to an error in the Cloud Functions log in the Firebase console
Error: Command failed: ./xmllint --xpath "//OrderData"
/tmp/kdjf6kv9hku86xw4h392j4i.xml | /user_code/node_modules/xml2json/bin/xml2json
/usr/bin/env: node: No such file or directory
Where is node located on Cloud functions for Firebase? Can I make it available to /usr/bin/env? Or should I fork the xml2json npm package and change that code.
After some additional searches I have found a solution for my situation, without having to change the npm package that is provided for xml2json.
Since xml2json is used in a command that is being executed by 'exec', we only need to make the path to the Node binary available in the environment of that exec. This path can be derived from 'process.execPath':
var exec = require('child_process').exec;
var process = require('process');
// get path where the node binary is located from within the code that
// is being executed by the node runtime provided by Firebase
var nodePath = process.execPath;
nodePath = nodePath.split('/');
nodePath = nodePath.splice(0, nodePath.length-1).join('/');
// add path to the environment
process.env.PATH += ':' + nodePath;
var cmd = './xmllint --xpath "//OrderData" /xyz.xml | /user_code/node_modules/xml2json/bin/xml2json';
// call the command and provide the extended env
exec(cmd, {env: process.env}, function(error, stdout, stderr) {
...
});

Is there a way to get version from package.json in Meteor code?

This answer explains how to read the package.json "version" from a npm started application. Is there an env variable in Meteor (1.3+) with this info?
Well, there is not npm_package_version environment value in process object.
But you get the value of version using following code :
var pjson = require('/package.json');
console.log(pjson.version); // This will print the version

ScalaJs PhantomJsEnv doesn't work when phantomjs is installed from npm

I am trying to use phantomjs as installed via npm to perform my unit tests for ScalaJS.
When I run the tests I am getting the following error:
/usr/bin/env: node: No such file or directory
I believe that is because of how phatomjs when installed with npm loads node:
Here is the first line from phantomjs:
#!/usr/bin/env node
If I change that first line to hardcode to the node executable (this involves modifying a file installed by npm so it's only a temporary solution at best):
#!/home/bjackman/cgta/opt/node/default/bin/node
Everything works.
I am using phantom.js btw because moment.js doesn't work in the NodeJSEnv.
Work Around:
After looking through the plugin source is here the workaround:
I am forwarding the environment from sbt to the PhantomJSEnv:
import scala.scalajs.sbtplugin.ScalaJSPlugin._
import scala.scalajs.sbtplugin.env.nodejs.NodeJSEnv
import scala.scalajs.sbtplugin.env.phantomjs.PhantomJSEnv
import scala.collection.JavaConverters._
val env = System.getenv().asScala.toList.map{case (k,v)=>s"$k=$v"}
olibCross.sjs.settings(
ScalaJSKeys.requiresDOM := true,
libraryDependencies += "org.webjars" % "momentjs" % "2.7.0",
ScalaJSKeys.jsDependencies += "org.webjars" % "momentjs" % "2.7.0" / "moment.js",
ScalaJSKeys.postLinkJSEnv := {
if (ScalaJSKeys.requiresDOM.value) new PhantomJSEnv(None, env)
else new NodeJSEnv
}
)
With this I am able to use moment.js in my unit tests.
UPDATE: The relevant bug in Scala.js (#865) has been fixed. This should work without a workaround.
This is indeed a bug in Scala.js (issue #865). For future reference; if you would like to modify the environment of a jsEnv, you have two options (this applies to Node.js and PhantomJS equally):
Pass in additional environment variables as argument (just like in #KingCub's example):
new PhantomJSEnv(None, env)
// env: Map[String, String]
Passed-in values will take precedence over default values.
Override getVMEnv:
protected def getVMEnv(args: RunJSArgs): Map[String, String] =
sys.env ++ additionalEnv // this is the default
This will allow you to:
Read/Modify the environment provided by super.getVMEnv
Make your environment depend on the arguments to the runJS method.
The same applies for arguments that are passed to the executable.

Why does Meteor complain that an insert method for a collection is already defined?

Can anyone tell me why the code below throws the following error? :
Error: A method named '/players/insert' is already defined
I'm new to Meteor and coffeescript so I may be overlooking something simple.
Here's my port of the leaderboard example to coffeescript:
###
Set up a collection to contain player information. On the server,
it is backed by a MongoDB collection named "players."
###
Players = new Meteor.Collection("players")
if Meteor.is_client
Template.leaderboard.players = ->
Players.find({}, {sort: {score: -1, name: 1}})
Template.leaderboard.selected_name = ->
player = Players.findOne(Session.get "selected_player")
player and player.name
Template.player.selected = -> if Session.equals("selected_player", this._id) then "selected" else ''
Template.leaderboard.events = {
'click input.inc': ->
Players.update(Session.get("selected_player"), {$inc: {score: 5}})
}
Template.player.events = {
'click': ->
Session.set("selected_player", this._id)
}
# On server startup, create some players if the database is empty.
if Meteor.is_server
Meteor.startup ->
if Players.find().count() is 0
names = [
"Ada Lovelace"
"Grace Hopper"
"Marie Curie"
"Carl Friedrich Gauss"
"Nikola Tesla"
"Claude Shannon"
]
Players.insert({name: name, score: Math.floor(Math.random()*10)*5}) for name in names
The full stack trace is as follows:
[[[[[ ~/dev/meteor/leaderboard ]]]]]
Running on: http://localhost:3000/
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: A method named '/players/insert' is already defined
at app/packages/livedata/livedata_server.js:744:15
at Function.<anonymous> (app/packages/underscore/underscore.js:84:24)
at [object Object].methods (app/packages/livedata/livedata_server.js:742:7)
at new <anonymous> (app/packages/mongo-livedata/collection.js:111:13)
at app/leaderboard.js:4:11
at /Users/alex/dev/meteor/leaderboard/.meteor/local/build/server/server.js:109:21
at Array.forEach (native)
at Function.<anonymous> (/Users/alex/dev/meteor/leaderboard/.meteor/local/build/server/underscore.js:76:11)
at /Users/alex/dev/meteor/leaderboard/.meteor/local/build/server/server.js:95:7
Exited with code: 1
I'm running Meteor version 0.4.0 (8f4045c1b9)
Thanks in advance for assistance!
You would also get this error, regardless of using coffeescript or plain javascript, if you duplicated your files. For example, copying your sources files to a subdirectory named Backup would produce this error, because Meteor merges files from subdirectories.
This appears to be a configuration issue with coffeelint (installed globally with npm).
I originally installed coffeelint to check that my coffeescript code was correct and had no errors.
I installed coffeelint as per the instructions with:
sudo npm install -g coffeelint
coffeelint worked fine when run stand-alone against .coffee files.
However, when running any Meteor project with coffeescript package added I got the above error.
On a whim, I thought the error might be due to conflict with my exisiting node install.
I decided to uninstall coffeelint first with:
sudo npm uninstall -g coffeelint
and then deleted the previously meteor-generated leaderboard.js file.
After re-starting meteor the coffeescript example above worked as expected without errors.
try moving (ie copying and deleting the original )
Players = new Meteor.Collection("players")
one time below if Meteor.is_client
and another time below if Meteor.is_server
I don't know exactly why, as I'm new to Meteor too, but that worked for me, I assume that the server side needs it's own reference,as well as the client,
although declaring outside the scope should do the same (maybe a bug, remember they're still at 0.5.0 preview , which makes me think you might wanna upgrade and try some new smart packages that are with the new version, it looks like you're using 0.4), but when the files in my server wouldn't recognize anything I defined the root directory of meteor (which pushes these files to both client and server), I defined the server's own reference, and I got the same error, and until I moved the 'public' declaration of the reference to give the server and the client each their own copy, nothing worked.
Hopefully that helps...

Resources