Can I use other node.js libraries in Meteor? - meteor

I was playing around with an idea and wanted to get some json from another site. I found with node.js people seem to use http.get to accomplish this however I discovered it wasn't that easy in Meteor. Is there another way to do this or a way to access http so I can call get? I wanted an interval that could collect data from an external source to augment the data the clients would interact with.

Looks like you can get at require this way:
var http = __meteor_bootstrap__.require('http');
Note that this'll probably only work on the server, so make sure it's protected with a check for Meteor.is_server.

This is much easier now with Meteor.http. First run meteor add http, then you can do something like this:
// common code
stats = new Meteor.Collection('stats');
// server code: poll service every 10 seconds, insert JSON result in DB.
Meteor.setInterval(function () {
var res = Meteor.http.get(SOME_URL);
if (res.statusCode === 200)
stats.insert(res.data);
}, 10000);

You can use Meteor.http if you want to handle http. To add other node.js libraries you can use meteorhacks:npm
meteor add meteorhacks:npm
Create apacakges.json file and add all the required packages name and versions.
{
"redis": "0.8.2",
"github": "0.1.8"
}

Related

Reading JS library from CDN within Mirth

I'm doing some testing around Mirth-Connect. I have a test channel that the datatypes are Raw for the source and one destination. The destination is not doing anything right now. In the source, the connector type is JavaScript Reader, and the code is doing the following...
var url = new java.net.URL('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.fp.min.js');
var conn = url.openConnection();
conn.setRequestMethod('GET');
if(conn.getResponseCode() === 200) {
var body = org.apache.commons.io.IOUtils.toString(conn.getInputStream(), 'UTF-8');
logger.debug('CONTENT: ' + body);
globalMap.put('_', body);
}
conn.disconnect();
// This code is in source but also tested in destination
logger.debug('FROM GLOBAL: ' + $('_')); // library was found
var arr = [1, 2, 3, 4];
var _ = $('_');
var newArr = _.chunk(arr, 2);
The error I'm getting is: TypeError: Cannot find function chunk in object.
The reason I want to do this is to build custom/internal libraries with unit test and serve them with an internal/company CDN and allow Mirth to consume them.
How can I make the library available to Mirth?
Rhino actually has commonjs support, but mirth doesn't have it enabled by default. Here's how you can use it in your channel.
channel deploy script
with (JavaImporter(
org.mozilla.javascript.Context,
org.mozilla.javascript.commonjs.module.Require,
org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider,
org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider,
java.net.URI
)) {
var require = new Require(
Context.getCurrentContext(),
this,
new SoftCachingModuleScriptProvider(new UrlModuleSourceProvider([
// Search path. You can add multiple URIs to this array
new URI('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/')
],null)),
null,
null,
true
);
} // end JavaImporter
var _ = require('lodash.min');
require('lodash.fp.min')(_); // convert lodash to fp
$gc('_', _);
Note: There's something funky with the cdnjs lodash fp packages that don't detect the environment correctly and force that weird two stage import. If you use https://cdn.jsdelivr.net/npm/lodash#4.17.15/ instead you only need to do var _ = require('fp'); and it loads everything in one step.
transformer
var _ = $gc('_');
logger.info(JSON.stringify(_.chunk(2)([1,2,3,4])));
Note: This is the correct way to use fp/chunk. In your OP you were calling with the standard chunk syntax.
Additional Commentary
I think it's probably ok to do it this way where you download the library once at deploy time and store it in the globalChannelMap, then retrieve it from the map where needed. It would probably also work to store the require object itself in the map if you wanted to call it elsewhere. It will cache and reuse the object created for future calls to the same resource.
I would not create new Require objects anywhere but the deploy script, or you will be redownloading the resource on every message (or every poll in the case of a Javascript Reader.)
Edit: I guess for an internal webhost, this could be desirable in a Javascript Reader if you intend for it to pick up changes immediately on the next poll without a redeploy, assuming you would be upgrading the library in place instead of incrementing a version
The benefit to using Code Templates, as Vibin suggested is that they get compiled directly into your channel at deploy time and there is no additional fetching step at runtime. Making the library available is as simple as assigning it to your channel.
Even though importing third party libraries could be an option, I was actually looking into this for our team to write our own custom functions, write unit-test for them, and lastly be able to pull that code inside Mirth. I was experimenting with lodash but it was not my end goal to use it, it is. My solution was to do a REST GET call with java in the global script. Your URL would be the GitHub raw URL of the code you want to pull in. Same code of my original question but like I said, the URL is the raw GitHub URL for the function I want to pull in.

PhantomJs onResourceReceived URL decode issue

I'm creating a web scraping bot in PhantomJs, I'm using onResourceReceived to sniff the the requests of the site and retrieve them using this simple code:
page.onResourceReceived = function(response)
{
if (response.url.match("XXXXXXX"))
{
console.log(response.url);
}
};
My problem is that response.url automatically update the data to a URL-decoded version of this. I need to check some parameters but instead of receiving something like this :
xxx.com?...&events=event20%2Cevent4%%2Cevent89%3D7%2Cevent50%2Cevent51%2Cevent52%2Cevent53%2Cevent54%2Cevent55%2Cevent56&...
I get this
xxx.com?... &events=event20%2Cevent4%2Cevent89%3D7&....
It looks like when %3D is reached it cuts the value and continues to the next property.
Is there a way to access the raw version of this data?
Thanks a lot for the help.

How do you expose CSV data to the client in Meteor?

I'm just learning Meteor, and I'm fiddling with something very simple to understand how the framework works. I load a CSV file with country names / country ids that I want to use in a SelectBox on the client.
I installed baby-parse
meteor add harrison:babyparse
I then use
Meteor.startup(function() {
parsed = Baby.parse(Assets.getText('geo.csv'));
Countries = parsed.data;
});
How can I expose the Countries data to the client?
Seems like you'd be better off populating a Mongo collection with the country data.
If you really want to just access a server method from the client, you can call a meteor method on startup from the client and set the result of that to a session variable. For example:
if(Meteor.isClient){
Meteor.call('getCountryData', function(err, res){
if (res){
Session.set('CountryData', res)
}
});
}
if (Meteor.isServer){
Meteor.methods({
'getCountryData':function(){
parsed = Baby.parse(Assets.getText('geo.csv'));
Countries = parsed.data;
return Countries;
}
});
}
Then use Session.get("CountryData") wherever needed on the client.
Again, highly recommend populating a collection in your database and then publishing/subscribing data to the client instead of this approach. Here's a good primer on the basics of MongoDB w/ Meteor: http://meteortips.com/first-meteor-tutorial/databases-part-1/. Chapter 11 (Publish & Subscribe) is what you want to look at after understanding the basics.

Force download from S3 on click

I have files stored on S3, and I want to automatically download them for a user when they click a button
What I've done so far is to have a route
/lib/routes/download
var fs = Npm.require('fs');
Router.route("download", function() {
console.log('retrieving ' + this.params.signedURL);
this.response.writeHead(200, {'Content-type': 'appplication/pdf'}, this.params.signedURL);
this.response.end(fs.readFileSync(this.params.signedURL));
}, { where: 'server', path: '/d/:signedURL'});
But this doesn't work, because i Cant use fs on the client. And even if I could, im not sure this would work
Any advice on how best to accomplish this?
Easiest way to do this is to use the cfs:s3 package which is an add-on to CollectionFS. This not only supports S3 but also transparently breaks files up into smaller chunks during upload and download to/from S3.
I retrieve the signedUrl via a meteor method call, then do this when the user clicks a download button :
window.open(_signedURL,"_self");

Can I create an index in a mongo collection with Meteor? [duplicate]

I am trying to create a two column unique index on the underlying mongodb in a meteor app and having trouble. I can't find anything in the meteor docs. I have tried from the chrome console. I have tried from term and even tried to point mongod at the /db/ dir inside .meteor . I have tried
Collection.ensureIndex({first_id: 1, another_id: 1}, {unique: true}); variations.
I want to be able to prevent duplicate entries on a meteor app mongo collection.
Wondering if anyone has figured this out?
I answered my own question, what a noob.
I figured it out.
Start meteor server
Open 2nd terminal and type meteor mongo
Then create your index...for example I did these for records of thumbsup and thumbsdown type system.
db.thumbsup.ensureIndex({item_id: 1, user_id: 1}, {unique: true})
db.thumbsdown.ensureIndex({item_id: 1, user_id: 1}, {unique: true})
Now, just gotta figure out a bootstrap install setup that creates these when pushed to prod instead of manually.
Collection._ensureIndex(index, options)
Searching inside Meteor source code, I found a bind to ensureIndex called _ensureIndex.
For single-key basic indexes you can follow the example of packages/accounts-base/accounts_server.js that forces unique usernames on Meteor:
Meteor.users._ensureIndex('username', {unique: 1, sparse: 1});
For multi-key "compound" indexes:
Collection._ensureIndex({first_id:1, another_id:1}, {unique: 1});
The previous code, when placed on the server side, ensures that indexes are set.
Warning
Notice _ensureIndex implementation warning:
We'll actually design an index API later. For now, we just pass
through to Mongo's, but make it synchronous.
According to the docs "Minimongo currently doesn't have indexes. This will come soon." And looking at the methods available on a Collection, there's no ensureIndex.
You can run meteor mongo for a mongo shell and enable the indexes server-side, but the Collection object still won't know about them. So the app will let you add multiple instances to the Collection cache, while on the server-side the additional inserts will fail silently (errors get written to the output). When you do a hard page refresh, the app will re-sync with server
So your best bet for now is probably to do something like:
var count = MyCollection.find({first_id: 'foo', another_id: 'bar'}).count()
if (count === 0)
MyCollection.insert({first_id: 'foo', another_id: 'bar'});
Which is obviously not ideal, but works ok. You could also enable indexing in mongodb on the server, so even in the case of a race condition you won't actually get duplicate records.
The Smartpackage aldeed:collection2 supports unique indices, as well as schema-validation. Validation will both occure on server and client (reactivly), so you can react on errors on the client.
Actually why not use upsert on the server with a Meteor.method and you could also send also track it with a ts:
// Server Only
Meteor.methods({
add_only_once = function(id1,id2){
SomeCollection.update(
{first_id:id1,another_id:id2},{$set:{ts:Date.now()}},{upsert:True});
}
});
// Client
Meteor.call('add_only_once',doc1._id, doc2._id);
// actual code running on server
if(Meteor.is_server) {
Meteor.methods({
register_code: function (key,monitor) {
Codes.update({key:key},{$set:{ts:Date.now()}},{upsert:true});
}
...

Resources