This might sound very basic, but I have just started to play around with meteor.
I see how it's possible to seamlessly have access to database like entities (Collections) both on the server and the client, and sync it automatically.
However I don't see yet how I can snyc a simple variable accross the server and all clients. Something like a global variable. I don't need a fancy mongo collection, just a simple variable. :)
You could use Meteor.methods to get and set variables in the server. But I don't think there is a way to push changes to other clients like changes of collections do.
So you have to take care that everything stays in sync. You should really use a collection for this or get the information from an existing collection.
e.g. a connected user could set a flag in its collection item and the reactivity magic would do the rest ;)
Users.find({connected:true}).count();
Related
Firebase offers some overall Analytics in their App Dashboard, however, I need to know whether my stored data are ever used or they are just lying idly on a per node basis.
Why? It's simple: we are learning while developing, which makes the app a very fast evolving one. Not only the logic changes, but also the data stored need to be refactored from time to time. I would like to get rid of abandoned and forgotten data. Any ideas?
In best case, I would like to know this:
When was a node used last time? (was it used at all?)
How many times was it used in 1h/24h/1w/1M?
Differentiate between read/write operations
2017 update
Cloud Functions trigger automatically and run on server.
https://firebase.google.com/docs/functions/
https://howtofirebase.com/firebase-cloud-functions-753935e80323
2016 answer
So apparently the Firebase itself doesn't provide any of this.
The only way I can think of right now is to create wrappers for firebase query and write functions and either do the statistics in a client app or create a devoted node for storing the statistical data.
In case of storing the data in firebase, the wrapper for writing functions (set, update, push, remove, setWithPriority) is relatively easy. The query functions (on, once) will have to write in a successCallback.
I just noticed that Meteor.call, the concept that prevent user from invoke collection's insert, update, remove method, still able to be invoked from JavaScript console.
For client's example:
// client
...
Meteor.call('insertProduct', productInfo);
...
Here's the server part:
// server
Meteor.methods({
insertProduct: function( productInfo ){
Product.insert(...);
}
})
OK, I know people can't invoke Product.insert() directly from their JavaScript console.
But if they try a little bit more, they'd find out there's Meteor.call() in client's JavaScript from Developer tool's resource tab.
So now they can try to invoke Meteor.call from their console, then try to guessing what should be productInfo's properties.
So I wonder how can we prevent this final activity?
Does Meteor.call done the job well enough?
or I'm missing something important?
Meteor.call is a global function, just like window.alert(). Unfortunately, there is nothing you can do from preventing a user calling Meteor.call. However, you can validate the schema of data and the actual data of what a user is sending. I'd recommend https://github.com/aldeed/meteor-simple-schema (aldeed:simple-schema as the meteor package name) to ensure you don't get garbage data in your project.
As others pointed out, "Meteor.call" can surely be used from the console. The subtle issue here is that there could be a legal user of a meteor app who can in turn do bad things on the server. So even if one checks on the server if the user is legal, that by itself does not guarantee that the data is protected.
This is not an issue only with Meteor. I think all such apps would need to potentially protect against corruption of their data, even through legal users
One way to protect such corruption is by using IIFE (Immediately Invoked Function Expression)
Wrap your module in a IIFE. Inside the closure keep a private variable which stores a unique one time use key (k1). That key needs to be placed there using another route -- maybe by ensuring that a collection observer gets fired in the client at startup. One can use other strategies here too. The idea is to squirrel in the value of k1 from the server and deposit it in a private variable
Then each time you invoke a Meteor.call from inside you code, pass k1 along as one of the parameter. The server in turn checks if k1 was indeed legal for that browser connection
As k1 was stored inside a private variable in the closure that was invoked by the IIFE, it would be quite difficult for someone at the browser console to determine the value of k1. Hence, even though "Meteor.call" can indeed be called from the browser console, it would not cause any harm. This approach should be quite a good deterrent for data corruption
As mentionned by #Faysal, you have several ways to ensure your calls are legit. An easy step to do so is to implement alanning:roles and do role checks from within your method like the following:
Meteor.methods({
methodName: function() {
if (!Roles.userIsInRole(this.userId, 'admin')) {
throw new Meteor.Error(403, 'not authorized);
} else { yourcode });
This way, only admin users can call the method.
Note that you can also check this.connection from within the method and determine if the call comes from the server (this.connection === false) or from the client.
Generally speaking, doing checks and data manipulations from your methods is a nice way to go. Allow/deny are nice to begin with but become really hard to maintain when your collections get heavier and your edge-cases expand.
You cannot block Meteor.call from the console, just like you can't block CollectionName.find().count() from the console. These are global functions in meteor.
But there are simple steps you can take to secure your methods.
Use aldeed:simple-schema to set the types of data your collection can accept. This will allow you to set the specific keys that your collection takes as well as their type (string, boolean, array, object, integer) https://github.com/aldeed/meteor-simple-schema
Ensure that only logged in users can update from your method. Or set global Allow/Deny rules. https://www.meteor.com/tutorials/blaze/security-with-methods && https://www.discovermeteor.com/blog/allow-deny-a-security-primer/
Remove packages insecure and autopublish
The simple combo of schema and allow/deny should do you just fine.
As you know by now that you can't really block calling Meteor.call from Javascript console, what i'd like to add as a suggestion with #Stephen and #thatgibbyguy that, be sure to check your user's role when adding documents into the collection. Simple-Schema will help you prevent inserting/updating garbage data into the collection. and alanning:roles package certainly makes your app secure by controlling who has the permission to write/read/update your collection documents.
Alanning:roles Package
I created an app that stores, compares, filters and takes statistics out of a collection of records. I've done it so it works offline, as in some user cases the user might not have constant (or at all) access to internet.
My problem is that after I've included ~60 records, the app starts to behave really slow. For instance, I list a collection of simple objects from LocalStorage into a ng-model (Select list), and after those ~60 records are in, to open the Select box will be seriously slowed down.
What could the problem be? I'm thinking, either some function is sucking more resources than necessary, or LocalStorage is not intended for such uses?
I'm starting to get into PouchDB, would you say that migrating all to Pouch instead of LocalStorage would be a good move?
I can't paste the whole controller here as it's huge, but I've put an online version for testing. You can see it here.
For you not to have to create 60 records just to see the effect, you can download this CSV and import it in the app.
In order to import, the pass for Edit Mode is: admin
Let's see if someone has a tip for this one!
I see you are storing all your records inside a single LocalStorage value (with the key being recordspax). So yeah, that will get quite slow, because your app has to 1) JSON parse/stringify and 2) store/retrieve the entire list every time you read/write data to the database.
Basically you are reading your entire database in and out of disk for every operation. Since both LocalStorage and JSON stringify/parse happen synchronously on the main thread, it can block DOM rendering and will thus slow down your app.
PouchDB could be a help here, but you could also benefit from something simpler like LocalForage, or simply changing your DB design so that every record has its own key/value rather than storing everything into a single key with a single value.
(Both LocalForage and PouchDB use IndexedDB/WebSQL rather than LocalStorage, meaning that database operations are not synchronous and do not block the DOM. However, you still don't want to stuff everything into a single document and therefore read the entire DB in and out of disk. :))
Does anybody know how to use the JsonRest store in dojo witn an Observable weapper, like the one in dojo.store.Observable?
What do I need, server side, to implement the store and make it work as an Observable one? What about the client side?
The documentation says http://dojotoolkit.org/reference-guide/1.7/dojo/store/Observable.html
If you are using a server side store like the JsonRest store, you will need to provide a queryEngine in order for the update objects to be properly included or excluded from queries. If a queryEngine is not available, observe listener will be called with an undefined index.
But, I have no idea what they mean. I have never created a store myself, and am not 100% familiar with queryEngine (to be honest, I find it a little confusing). Why is queryEngine needed? What does the doc mean by "undefined index"? And how do you write a queryEngine for a JsonRest store? Shouldn't I use some kind of web socket for an observable REST store, since other users might change the data as well?
Confused!
I realize this quesiton is a bit old, but here's some info for future reference. Since this is a multi-part question, I'll break it down into separate pieces:
1) Server-side Implementation of JsonRest
There's a pretty decent write up on implementing the server side of JsonRest Store. It shows exactly what headers JsonRest will generate and what content will be included in the rest. It helps form a mental model of how the JsonRest api is converted into HTTP.
2) Query Engine
Earlier in the same page, how query() works client side is explained. Basically, the query() function needs to be able to receive an object literal (ex: {title:'Learning Dojo',categoryid:5}) and return the objects in the store that match those conditions. "In the store" meaning already loaded into memory on the client, not on the server.
Depending on what you're trying to do, there's probably no need to write your own queryEngine anyway -- just use the built-in SimpleQueryEngine if you're building your own custom store. The engine just needs to be handed an object literal and it adds the whole dojo query() api for you.
3) Observables
My understanding is that the Observables monitor client side changes in the collection of objects (ex: adding or removing a result) or even within a specific object (ex: post 5 has changed title). It does NOT monitor changes that happen server-side. It simply provides a mechanism to notify other aspects of the client-side app that data changed so that all aspects of the page stay synchronized.
There's a whole write up on using Observables under the headings 'Collection Data Binding' and 'Object Data Binding: dojo/Stateful'.
4) Concurrency
There's two things you'd want to do in order to keep your client side data synchronized with the server side data: a) polling for changes from other users on the server, b) using transactions to send data to the server.
a) To poll for changes to the data, you'd want to have your object store track the active query in a variable. Then, use setTimeout() or setInterval() to run the query in the background again every so often. Make sure that widgets or other aspects of your application use Observables to monitor changes in the query result set(s) they depend on. That way, changes on the server by other users would automatically be reflected throughout your application.
b) Use transactions to combine actions that must be combined. Then, make sure the server sends back HTTP 200 Status codes (meaning 'It Worked!'). If the transactions returns a HTTP status in the 400s, then it didn't work for some reason, and you need to requery the data because something changed on the backend. For example, the record you want to update was deleted, so you can't update it. There's a write up on transactions as well under the heading 'Transactional'
I'm working on a couple sites that share some Socket.io initialization code. Also shared is a global var. If this var has a value I need to send it over in all socket emits.
I have not been able to figure out a good way to append this variable to all outgoing emits. I was hoping that Socket.io would have a method that is called whenever an emit is fired (just before sending the data), allowing you to add to the data as needed. But, if it exists, I could not find it.
Any suggestions?
It's ugly, but you could save the existing, and write your own emit function that does what you want, and then calls the original emit.