Server send command to all clients in Meteor - meteor

I have a public client side function:
test = function(){
alert("HELLO")!;
}
What I need is a function that works like this - so on the admin client script, they hit a button which calls a server method:
Meteor.call("callFunctions");
The server side function:
Meteor.methods({
callFunctions: function() {
//call clientside function test() for all clients
}
});
How can I do this without depending on a database?

My client-call package does that. It depends on database internally, but you don't have to worry about that dependence.
To call the methods on all clients you'll need to manually register and loop through their ids.
Set up method:
Meteor.ClientCall.methods({
'alert': function() {
...
},
});
Call it:
Meteor.ClientCall.apply(clientId, 'alert', []);

Related

Why client does not instantly return from client method?

client method
Meteor.methods({
insertPost: function(data) {
console.log('client')
Posts.insert(data, function(err, ret) {
console.log('client insert end')
});
},
});
server method
Meteor.methods({
insertPost: function(data) {
console.log('server')
Meteor._sleepForMs(200000);
Posts.insert(data, function(err, ret) {
console.log('server insert end')
});
},
});
client submit
'click #save': function(e) {
// data = ....
Meteor.call('insertPost', data, function(error) {
Router.go('/');
});
},
Why does client stuck at form page, instead of instantly going to '/'.
Here is the meteor documentation about it.
Calling methods on the client defines stub functions associated with
server methods of the same name. You don't have to define a stub for
your method if you don't want to. In that case, method calls are just
like remote procedure calls in other systems, and you'll have to wait
for the results from the server.
If you do define a stub, when a client invokes a server method it will
also run its stub in parallel. On the client, the return value of a
stub is ignored. Stubs are run for their side-effects: they are
intended to simulate the result of what the server's method will do,
but without waiting for the round trip delay. If a stub throws an
exception it will be logged to the console.

Meteorjs: Remove reactivity to a certain publish statement

Is there any way to publish once the subscribe request is made and then stop pushing the changes that are made to the collection until the client subscribes again?
I have this scenario:
Server:
Meteor.publish("posts", function () {
return Messages.find(); //Do not push changes to this collection!
});
Client:
Meteor.subscribe("posts");
If you just have to do a one-shot data send to the client, using a method may work:
//Server
Meteor.methods({
getSomePosts : function(limit)
{
check(limit, Number);
return Posts.find({}, {limit : limit}).fetch();
}
});
//Client
Meteor.call('getAllPosts', function(err, result) {
//Do stuff with the result
});
Note that this will be heavy on your database, you may want to use a variable and update it periodically rather than fetching the whole collection each time a client calls the method.
More about limits in the doc!

SignalR external service timed loop - server or client

I have external services that I want to call every 20-30 seconds and make accessible to the client using SignalR but I'm not sure if I should have the client call the server in a JavaScript setInterval loop or if I should have the server run its own loop and push the information to the client. I'm looking to do dynamic page updates to show what a user is currently playing on Xbox 360/Xbox One or PlayStation Network.
Currently, I'm calling the server side code from the client in a setInterval loop, but I'm not sure how well this will scale. I had been doing Web API 2 calls through AJAX previously, but that will quickly eat up bandwidth. The external services are not mine so the only way to get simulated real-time results is to send a request to the external services periodically. The only problem I see with doing a server side loop is thread blocking. I don't want to stop the current thread while the loop is running.
Client side code:
var profile = $.connection.profileHub;
profile.client.receiveXboxProfile = function (profile) {
console.log(profile.GamerTag);
};
profile.client.receivePSNProfile = function (profile) {
console.log(profile.PSNId);
};
$.connection.hub.start()
.done(function () {
function GetGamerProfiles() {
profile.server.sendXboxProfile(window.UserName)
.done(function() {
})
.fail(function (error) {
console.log('SignalR ' + error);
});
profile.server.sendPSNProfile(window.UserName)
.done(function () {
})
.fail(function (error) {
console.log('SignalR ' + error);
});
}
GetGamerProfiles();
var id = setInterval(function () {
GetGamerProfiles();
}, 20000);
});
Server side hub:
[Authorize]
public async Task SendXboxProfile(string username)
{
// Makes call to external service to get Xbox profile
Clients.Caller.receiveXboxProfile(await xboxapi.GetProfile(username));
}
[Authorize]
public async Task SendPSNProfile(string username)
{
// Makes call to external service to get PSN profile
Clients.Caller.receivePSNProfile(await psnapi.GetProfile(username));
}
Maybe SignalR isn't the best solution for this problem since I don't control the external services, but I am very intrigued by the concept of SignalR and HTML 5 websockets. In general, is it better to do periodic updates on the client or server with SignalR?

Accessing this.userId not working when calling from within Meteor.SetTimeout

I've been trying to access the this.userId variable from within a Meteor.methods call, but it doesn't seem to work when I try to call the method via Meteor.setTimeout or Meteor.setInterval.
This is what I've got:
if (Meteor.is_server) {
Meteor.methods({
getAccessToken : function() {
try {
console.log(this.userId);
return Meteor.users.findOne({_id: this.userId}).services.facebook.accessToken;
} catch(e) {
return null;
}
}
});
var fetch_feed = function() {
console.log(Meteor.call("getAccessToken"));
[...] // A bunch of other code
};
Meteor.startup(function() {
Meteor.setInterval(fetch_feed, 60000); // fetch a facebook group feed every minute
Meteor.setTimeout(fetch_feed, 3000); // initially fetch the feed after 3 seconds
});
}
Watching the terminal log, the this.userId always returns a null. But if I try calling the method from the client side, or through the console, it returns the correct ID.
How come this doesn't work from within a Meteor.setInterval? Is it a bug or am I doing something wrong?
Meteor userId's are associated with client connections. The server may interact with many clients and this.userId inside a method will tell you which client has asked for the method to be run.
If the server uses Meteor.call() to run a method then it will not have a userId since it is not running for any client.
The methods allow clients to call for functions to be run on the server. For things the server will trigger itself a javascript function will do.
There is a solution I used - sometimes you do not want to make the method a function but really want it to remain a method. In that case, a hack to make this work:
var uniqueVar_D8kMWHtMMZJRCraiJ = Meteor.userId();
Meteor.setTimeout(function() {
// hack to make Meteor.userId() work on next async
// call to current method
if(! Meteor._userId) Meteor._userId = Meteor.userId;
Meteor.userId = function() {
return Meteor._userId() || uniqueVar_D8kMWHtMMZJRCraiJ
};
Meteor.apply(methodName, args);
}
, 100);
Some brief explanation: we save Meteor.userId in Meteor._userId and overwrite Meteor.userId with a function that returns Meteor._userId() if it is true and otherwise the historic value of Meteor.userId() before any of this happened. That historic value is saved in an impossible to occur twice var name so that no context conflicts can happen.

Invoke a client js function in Meteor after getting results from the server

I'm trying to see how can I invoke a js function after the client gets a result from a Meteor method call. The only thing I was able to get is to invoke the function myFunc only on the client that made the actual method call.
Any thoughts how i can invoke the function on all the currently subscribed clients?
here is the code:
function myFunc(error, result) {
alert(result);
}
if (Meteor.is_client) {
Template.container.events = {
'click input' : function () {
Meteor.call('someMethod',myFunc);
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
};
}
if (Meteor.is_server) {
Meteor.startup(function () {
// code to run on server at startup
});
}
Meteor.methods({
someMethod: function() {
//console.log(!this.is_simulation);
return "something";
}
})
Thanks
Currently you can't broadcast a method call to all clients directly. At least as far as I can tell. But a work around would be to create a collection called Alerts and monitor it for changes. Then when you want to send a message to all your users you can change the document in Alerts:
Client:
Alerts = new Meteor.Collection("alerts")
Meteor.autosubscribe(function() {
Alerts.find().observe({
added: function(item){
alert(item.message);
}
});
});
Server:
Alerts = new Meteor.Collection("alerts")
Meteor.publish("alerts", function(){
Alerts.find();
});
Alerts.remove({}); // remove all
Alerts.insert({message: "Some message to show on every client."});
Another option is using Meteor Stream package which purpose is to avoid using a mongodb collection on the server side. It does supports client to clients, server to clients, client to server AND server to servers messaging, including a support for Meteor Cluster
If you want to stay with meteor only using collections, the following code allows you to either broadcast a message from the client to all the clients or a message from the server to all the subscribed clients. Just use this mechanism to then fire a function on the client side once the right message is received. The code is made in such a way that you will never have useless items remaining into the collection.
Messages = new Meteor.Collection("messages");
if (Meteor.isClient) {
Meteor.subscribe("messages");
var query = Messages.find({});
var handle = query.observe({
added: function(document)
{
console.log(document.message);
}
});
// Test the mechanism from the client side
Meteor.call("client talked");
}
if (Meteor.isServer) {
Meteor.startup(function() {
Messages.remove({});
});
Meteor.publish("messages", function()
{
// you might add an optional filter in order to broadcast only the messages you want to the client
return Messages.find();
});
function talk(message)
{
var id = Messages.insert({"message":message});
Messages.remove(id);
}
Meteor.methods(
{
talk: function(message)
{
// you might filter here if the clients can talk using this.userId
talk(message);
}
});
// test the mechanism from the server side
talk("server talked");
}
I like what Zeke said, but for people who uses Meteor 0.5.0+, use Deps.autorun instead of autosubscribe... details at:
https://groups.google.com/forum/#!topic/meteor-core/mTa81RLvhbY
and
http://www.meteor.com/blog/2013/02/14/meteor-055-devshop-code-and-community-contributions
I simple approach to call a JavaScript client-side function would be to add a script tag in your html template that is bound by your collection. Anytime a new item is inserted, this tag would be inserted into the client would run your function. I have a collection call uploads with some properties such as name. The following template triggers drawpoints() client-side function upon receipt of a new item in Uploads collection:
{{#each uploads}}
<tr>
<td>{{name}}</td>
<td>
<div class="alert alert-success">Download Here</div>
</td>
</tr>
<script>drawpoints();</script>
{{/each}}

Resources