Meteor: execute calls from client console "everywere" - meteor

Meteor is said to automagically (in most cases) figure out what code to run on the client and what code to run on the server so you could theoretically just write all your code in one .js file.
I would like to be able to write code in my browser console and have it executed pretty much as if I had put the code in a file on my server.
For example, in my browser console:
[20:08:19.397] Pages = new Meteor.Collection("pages");
[20:08:30.612] Pages.insert({name:"bro"});
[20:08:30.614] "sGmRrQfezZMXuPfW8"
[20:08:30.618] insert failed: Method not found
Meteor says "method not found" because I need to do new Meteor.Collection("pages"); on the server.
But is there a workaround for this, whether using the above-mentioned automagic or by explicitly saying in my browser console "run the following line of code on the server!"?

Well it doesn't "automagically" figure it out - you have to very explicitly do one of two things:
Separate the code into client and server directories.
Wrap the code in an isClient or an isServer section.
Otherwise, any code you write will execute in both environments. However, any code input by the user on the client will only be executed on the client. Meteor has been specifically designed to protect this boundary.
You can call a method on the server from the client, but again the server cannot be tricked into executing client-defined functions.
In your specific example, you can always define the collection only on the client like so:
Pages = new Meteor.Collection(null);
That will allow you do freely manipulate the collection data on the client, but it will not involve the server (nothing will be stored in the db).

Related

Meteor methods - stream/yield data from server

I'm writing a Meteor app which allows clients to execute terminal commands on the server at the click of a button.
I know how to do this with a single command:
//server
Meteor.methods({ exec : cmd => { ... } })
//client
Meteor.call('exec', cmd, (err, result) => {
console.log(result)
})
But now I'm trying to implement a more complex protocol and don't quite know what the best way is. I want the client to kick off a series of commands, have the server run them and tell me, step by step, whether they succeeded or failed.
Obviously I could implement this with the above code by writing client-side code that runs exec with the first command, checks the result from the server, runs exec with the next command and so on.
The crux is that in my case the series of commands is always the same, so it would make much more sense to only do one Meteor.call on the client -- the server would know what commands to run. However I would also like to have the results of the individual commands available on the client as they come in -- and this is what I can't do, because Meteor.call only returns once, of course.
What I'm looking for is a sort of stream or iterator through which I can send a number of messages to the client until everything is done. I've seen some outdated packages called meteor-streams and similar that might be able to do something like that, but I'm thinking there must be a smart way in Meteor itself to solve this. Ideas?
A common solution is a Notifications collection. Create the collection with a schema: for: ${userid}, msg: ${msg string}, type: ${err success etc}. Create a Notifications publication, which publishes docs with the users userid.
You can then subscribe to the Notifications collection in some main template page on the client. Use observeChanges to look for changes to the collection and either console.log them, use JavaScript to display them on the page or simply install a package like sAlerts to handle them.
Inside the observe changes callback, a seenNotification method should be called which removes the notification from the db, so it is not shown again.
I'll post code snippets a bit later.
Have a look at this: https://github.com/RocketChat/meteor-streamer
I think it will solve your problem easily.

How to execute a query in eval.xqy file with app-server id

I need to run query with importing modules from pod.
Without importing modules if I run simple query with Database Id using below, it is working.
let $queryParam := fn:concat("?query=",xdmp:url-encode($query),"&eval=",$dataBaseId,":123")
let $url := fn:concat($hostcqport,"/eval.xqy",$queryParam)
let $response := xdmp:http-post($url, $options)[2]
If I have import modules statements then it is throwing Error(File Not Found).
So I tried getting the app-server id and tried passing that instead of database-id as below,
let $queryParam := fn:concat("?query=",xdmp:url-encode($query),"&eval=",$serverId,":123")
let $url := fn:concat($hostcqport,"/eval.xqy",$queryParam)
let $response := xdmp:http-post($url, $options)[2]
How to pass the server-id to make the query executing against particular app-server.
Is this MarkLogic 8 or earlier (I ask because rewrite options on 8 allow for dynamic switching of module databases before execution (among lots of other amazing goodies). This may be what you want because you can look at the query parameters at this point and build logic into the rewite rules.
Otherwise, Can you explain in more detail what you are trying to accomplish in the end. By the time your code ran, it was already executed in the context of a particular App server - so asking to execute against a another app server by analysing the query parameters is a bit too late (because you are already using the app server).
[edit] The following is in response to the comments since provided. This is a messy response because the actual ticket and comments are still not a completely clear picture. But if you stitch them together, then a problem statement does now exist for which I can respond.
The original author of the question confirmed via comments that they are "trying to hit an app server on a different node than the one that you actually posted to"
OK.. This is the response to that clarification:
That is not possible. Your request is already being processed by a thread on the node that you hit with your http request. Marklogic is a cluster, but it does not share threads (or anything else for that matter). Choices are:
a redirect to the proper node
possibly use the current node to make the request on your behalf.
But that ties up the first thread and the thread on the other node and has the HTTP communication overhead - and you need to have an app server listening for this purpose.
If this is a fire-and-forget type of situation, then you can hit any node and save the data/request in a document in the DB using a URI naming convention that indicates what app server it is for, and by way of insert triggers (with a URI-prefix for their server id), pick up the request from the DB and process it.

Detecting whether code is running in mirror when using Velocity to test a Meteor app

I have a simple Meteor application. I would like to run some code periodically on the server end. I need to poll a remote site for XML orders.
It would look something like this (coffee-script):
unless process.env.ORDERS_NO_FETCH
Meteor.setInterval ->
checkForOrder()
, 600000
I am using Velocity to test. I do not want this code to run in the mirrored instance that runs the tests (otherwise it will poach my XML orders and I won't see them in the real instance). So, to that end, I would like to know how to tell if server code is running in the testing environment so that I can avoid setting up the the periodic checks.
EDIT I realised that I missed faking one of my server calls in the tests, which is why my test code was grabbing one of the XML orders from the real server. So, this might not be an issue. I am not sure yet how the tests are run for the server code and if the server code runs in a mirror (is that a client only concept)?.
The server and the client both run in a mirror when using mocha/jasmine integration tests.
If you want to know if you are in a mirror, you can use:
Meteor.call('velocity/isMirror', function(err, isMirror) {
if (isMirror) {
// do something
}
});
Also, on the server you can use:
process.env.IS_MIRROR
You've already got the fake working, and that is the right approach.

In Meteor Methods this.connection is always undefined

I am trying to implement some methods for a DDP API, for use with a C# remote client.
Now, I want to be able to track the connection to implement some type of persistent session, to this end, id hope to be able to use the session id given by DDP on connection, example:
{
"msg": "connected",
"session": "CmnXKZ34aqSnEqscR"
}
After reading the documentation, I see that inside meteor methods, I can access the current connection using "this.connection", however, I always get an undefined "this.connection".
Was it removed? If so, how can i access it now?
PS: I dont want to login as a user and access this.userId, since the app I want to create should not login, but actually just get a document id and do work associated with that, including changes to other collections, but all, regarding ONLY this id, and I dont want to have to include this id every time I call a function, since, this could possibly lead security problems if anyone can just send any id. The app would ideally do a simple login, then associate token details with his "session".
Changing from:
() => { this.connection; }
to:
function() { this.connection; }
solves the problem from me. Based on a comment in the accepted answer.
The C# client on github has a few bugs with it as it doesn't follow the DDP spec exactly. When you send commands to it to connect and run a call, it usually sends the '.call' too soon.
The method does work if you do it this way with this.connection on the server side Meteor method.
You need to make sure you send the method calls after you know that you are actually connected. This is what works at least with Meteor 0.8.2
I was using a file named ".next.js" to force meteor to use the newest unsupported javascript spec using a package.
Somehow this messed it up. Changed back to default javascript and it now works.
Thank you :)
init.coffee
Meteor.startup ->
# client init
if Meteor.isClient
Meteor.call "init"
methods.coffee
Meteor.methods
init: ->
console.log #connection.httpHeaders.host
it's that easy...

Meteor 0.7.2 + OplogObserveDriver not updating under certain circumstances

This is pretty cutting-edge as 0.7.2 was just released today, but I thought I'd ask in case somebody can shed some light.
I didn't report this to MDG because I can't reproduce this on my dev environment and thus I wouldn't have a recipe to give them.
I've set up oplog tailing in my production environment, which was deployed exactly as my dev environment was, except it's on a remote server.
The server runs Ubuntu + node 0.10.26 and I'm running the bundled version of the app with forever. Mongo reports its replSet is working in order.
The problem is that some collection updates made in server code don't make it to the client. This is the workflow the code is following:
Server publishes the collection using a very simple user_id: this.userId selector.
Client subscribes
Client calls a server method using Meteor.call()
Client starts observing a query on that collection using a specific _id: "something" selector. It will echo on "changed"
Server method calls .update() on the document matching that "something" _id, after doing some work.
If I run the app without oplog tailing (by not setting MONGO_OPLOG_URL), the above workflow works every time. However, if I run it with oplog tailing, the client doesn't echo any changes and if I query the collection directly from the JS console on the browser I don't see the updated version of the collection.
To add to the mystery, if I go into the mongo console and update the document manually, I see the the change on the client immediately. Or if I refresh the browser after the Meteor.call() and then query the collection manually from the js console the changes are there, as I'd expect.
As mentioned before, if I run the app on my dev environment with oplog tailing (verified using the facts package) it all works as expected and I can't reproduce the issue. The only difference here would be latency between client and server? (my dev environment is in my LAN).
Maybe if somebody is running into something similar we can isolate the issue and make it reproducible..

Resources