I'm trying to integrate the schedule component from Syncfusion. The component has a URL adaptor to connect to the controller; GetData() and Batch() for Crud Operations. Batch has a payload indicating what actions to perform. At the end, the Batch method would requery the database and send data identical to GetData() back.
Unfortunately, there is no built-in method to notify clients of anything going wrong - whether there is an exception, server-side validation kicks in or similar.
What I'd like to do is to add a placeholder outside the compentent to receive and display server messages (be it a notification popup, a or whatever.
Since I can't influence the Ajax call itself, I was wondering if I had to get started with SignalR (still in beta for .Net Core 2 as far as I know), or if I may have missed something more obvious? I have read a lot about push notifications etc - but these are not quite what I'm after, it'd be slightly over the top I think.
To summarise, let's say I have
<div id="messages"></div>
<div id="component">HereGoesTheScheduleWhichICantDoMuchWith</div>
Now in the Batch() method, it would be great to call a SendMessage("Sorry,you can't do this") - the text of which would ideally then appear in the messages-div.
How would you go about this?
I have now solved this, using SignalR (currently 1.0.0-alpha2-final) and for a nice view on the Client, PNotify.
Presently, it only works if the client is authenticated, if it needs to work anonymously you'd need to figure out a way to track SignalR's connection id.
On the page with the Syncfusion Schedule component, I connect to SignalR.
let connection = new signalR.HubConnection("/signalr", { transport: signalR.TransportType.ServerSentEvents });
connection.on("Notify",
(title, message) => {
new PNotify({
title: title,
text: message
});
});
connection.start();
The Hub (SignalRHub : Hub) creates a notification group for the user connecting:
public override Task OnConnectedAsync()
{
Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
return base.OnConnectedAsync();
}
The associated controller gets IHubContext<SignalRHub> signalRHub injected.
Now in the Batch-Method for the Syncfusion component, which returns Json and can't itself carry messages or notifications, you can notify the user:
_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Notify", "A title", "A message");
In my particular case, I'm sending over an object to control layout, animation and popup duration for PNotify (e.g. longer for an exception to allow copy/paste etc) - as you please. Returning an object could be done using:
_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Notify", JsonConvert.SerializeObject(new { title = "Some Title", message = "notification", type = "notice"}););
Obviously, connection.on("Notify"... needs to be changed accordingly.
I hope this is clear enough and might help someone else.
Related
I'm trying to have clients publish a A/V stream, turn them off, and then turn them back on. The first time I tell them to publish and then unpublish, it works fine. However, the next time I tell them to publish (Using the same session ID and token), I get the error "Cannot Connect, the session is already undefined".
Why is the "session" getting destroyed?.. is it the unpublish? My code is pretty much taken from the tutorials:
clientSession = OT.initSession(apiKey, sessionId);
clientSession.connect(token, function (error) {
if (error) {
handleError(error);
} else {
clientPublisher = OT.initPublisher(container, {
insertMode: 'append',
width: '100%',
height: '100%'
}, handleError);
}
});
}
To unpublish:
clientSession.unpublish(clientPublisher);
There are 2 ways you could do this. You could initialise a single publisher object once and keep reusing it everytime you republish. Or you could keep destroying and reinitialising a new publisher each time. I've written up an example of both approaches for you:
Reuse same publisher: https://jsbin.com/tobabos/edit?html
Create new publisher each time: https://jsbin.com/jawuxez/edit?html
Note: Please provide your own API key, session ID and token to run the above JSbins
The key difference is that to reuse a publisher you need to do this:
pub.on('streamDestroyed', e => e.preventDefault());
This is documented here: https://tokbox.com/developer/sdks/js/reference/Publisher.html#.event:streamDestroyed
It makes sure that when you unpublish, the publisher object is not destroyed so it can be reused.
What also happens is if you reuse a publisher, the publisher remains on the page and the user can still see themselves. Even if the publisher is not streaming to the session. You could use CSS or DOM manipulation to hide the publisher, but the webcam light will remain on.
However, if you destroy and recreate the publisher each time, the publisher disappears from the page and the webcam light turns off while unpublished. Depending on the browser and the user's settings, they may be asked to permit access to their webcam again.
I am new to Parse and I want to know if there is a way to schedule a Background job that starts every 3 minutes and sends a message (an integer or something) to all users that at that moment are logged in. I could not find any help here reading the guide. I hope someone can help me here.
I was in need to push information for all logged in users in several apps which were built with Parse.com.
None of the solutions introduced earlier by Emilio, because we were in need to trigger some live event for logged users only.
So we decided to work with PubNub within CloudCode in Parse : http://www.pubnub.com/blog/realtime-collaboration-sync-parse-api-pubnub/
Our strategy is to open a "channel" available for all users, and if a user is active (logged in), we are pushing to this dedicated "channel" some information which are triggered by the app, and create some new events or call to action.
This is a sample code to send information to a dedicated channel :
Parse.Cloud.define("sendPubNubMessage", function(request, response) {
var message = JSON.stringify(request.params.message);
var PubNubUrl;
var PubNubKeys;
Parse.Config.get().then(function(config) {
PubNubKeys = config.get('PubNubkeys');
}).then(function() {
PubNubUrl = 'https://pubsub.pubnub.com/publish/';
PubNubUrl+= PubNubKeys.Publish_Key + '/';
PubNubUrl+= PubNubKeys.Subscribe_Key + '/0/';
PubNubUrl+= request.params.channel +'/0/';
PubNubUrl+= message;
return Parse.Cloud.httpRequest({
url: PubNubUrl,
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
}).then(function(httpResponse) {
return httpResponse;
});
}).then(function(httpResponse) {
response.success(httpResponse.text);
}, function(error) {
response.error(error);
});
});
This is an another sample code used to send a message to a dedicated channel once something was changed on a specific class :
Parse.Cloud.afterSave("your_class", function(request, response) {
if (!request.object.existed()) {
Parse.Cloud.run('sendPubNubMessage', {
'message': JSON.stringify({
'collection': 'sample',
'objectId': request.object.id
}),
'channel' : 'all' // could be request.object.get('user').id
});
}
});
#Toucouleur is right in suggesting PubNub for your Parse project. PubNub acts essentially like an open socket between client and server so that the sever can send messages to clients and vice versa. There are 70+ SDKs supported, including one here for Win Phone.
One approach for your problem would be to Subscribe all users to a Channel when they log in, and Unsubscribe from that Channel when they exit the app or timeout.
When you want to send a message you can publish to a Channel and all users Subscribed will receive that message in < 1/4 second. PubNub makes sending those messages as Push Notifications really simple as well.
Another feature you may find useful is "Presence" which can give you realtime information about who is currently Subscribed to your "Channel".
If you think a code sample would help let me know!
Here's a few ideas I came up with.
Send a push notification to all users, but don't add an alert text. No alert will show for users who have the app closed and you can handle the alert in the App Delegate. Disadvantage: Uses a lot of push notifications, and not all of them are going to be used.
When the app comes to foreground, add a flag to the PFInstallation object that specifies the user is online, when it goes to the background, set the flag to false. Send a push notification to the installations that have the flag set to true. Disadvantages: If the app crashes, you would be sending notifications to users that are not online. Updating the user twice per session can increase your Parse request count.
Add a new property to the PFInstallation object where you store the last time a user did something, you can also set it on a timer of 30s/1m while the app is open. Send a push notification to users that have been active in the last 30s/1m. Disadvantage: Updating the PFInstallation every 30 seconds might cause an increase on your Parse request count. More accuracy (smaller interval) means more requests. The longer the session length of your users, the more requests you will use.
Is there a way to send events from the server to all or some clients without using collections.
I want to send events with some custom data to clients. While meteor is very good in doing this with collections, in this case the added complexity and storage its not needed.
On the server there is no need for Mongo storage or local collections.
The client only needs to be alerted that it received an event from the server and act accordingly to the data.
I know this is fairly easy with sockjs but its very difficult to access sockjs from the server.
Meteor.Error does something similar to this.
The package is now deprecated and do not work for versions >0.9
You can use the following package which is originally aim to broadcast messages from clients-server-clients
http://arunoda.github.io/meteor-streams/
No collection, no mongodb behind, usage is as follow (not tested):
stream = new Meteor.Stream('streamName'); // defined on client and server side
if(Meteor.isClient) {
stream.on("channelName", function(message) {
console.log("message:"+message);
});
}
if(Meteor.isServer) {
setInterval(function() {
stream.emit("channelName", 'This is my message!');
}, 1000);
}
You should use Collections.
The "added complexity and storage" isn't a factor if all you do is create a collection, add a single property to it and update that.
Collections are just a shape for data communication between server and client, and they happen to build on mongo, which is really nice if you want to use them like a database. But at their most basic, they're just a way of saying "I want to store some information known as X", which hooks into the publish/subscribe architecture that you should want to take advantage of.
In the future, other databases will be exposed in addition to Mongo. I could see there being a smart package at some stage that strips Collections down to their most basic functionality like you're proposing. Maybe you could write it!
I feel for #Rui and the fact of using a Collection just to send a message feel cumbersome.
At the same time, once you have several of such message to send around is convenient to have a Collection named something like settings or similar where you keep these.
Best package I have found is Streamy. It allows you to send to everybody, or just one specific user
https://github.com/YuukanOO/streamy
meteor add yuukan:streamy
Send message to everybody:
Streamy.broadcast('ddpEvent', { data: 'something happened for all' });
Listen for message on client:
// Attach an handler for a specific message
Streamy.on('ddpEvent', function(d, s) {
console.log(d.data);
});
Send message to one user (by id)
var socket = Streamy.socketsForUsers(["nJyQvECmkBSXDZEN2"])._sockets[0]
Streamy.emit('ddpEvent', { data: 'something happened for you' }, socket);
I Have a requirement like below :
Get invoked a particular action repeatedly without user interaction.For example, I have a message status page which displayed JMS message status.Message status can be changed by a number of application components.What I wanted is, my status UI has to pick latest message status.I need the action which displays status UI to be called repeatedly in an interval of 5 seconds or so, so that UI will get displayed with latest status.
How can I achieve this in spring.Is it something,Polling an action?
Any help highly appreciated
The easiest thing to do is to ask the server every few seconds using JavaScript and AJAX (pseudo-code using jquery):
function askServerForStatus() {
$.getJSON('/your-app/jms-status', function(response) {
$('#status').text(response.status);
}
}
setInterval(askServerForStatus, 5000); //every 5 seconds
Very simple example, it asks Spring MVC controllers mapped to /jms-status and expects the following JSON response:
{"status": "Processing..."}
Consider using setTimeout().
More general, reliable and robust approach is to use websockets, servlet-3.0 asynchronous support or comet. Also have a look at atmosphere.
I'm writing a multiplayer chess game, and using Pusher for the websocket server part.
Anyways, if I have a list of users, and I select any one of them and challenge them, how do I send challenge to just that one user? I know I would use the client event like:
channel.trigger("client-challenge_member1", {some : "data"});
But this event would have to have already been created I think. So do I create this event dynamically after each member subscribes? as possibly in:
channel.bind("pusher:subscribed_completed", function(member) // not sure of correct syntax but...
{
channel.bind("client-challenge_" + member.memberID, function(data)
{
alert(data.Name + " is challenging you.");
});
});
I would think there'd be a overloaded method for trigger, like:
channel.trigger(eventName, data, memberID)
But I cannot see anything like this. Any ideas? Thanks.
I ran into this problem on my application. At this time Pusher does not provide methods for sending events to a specific user. I think the approach that you mentioned would work for your situation. For my application I had each user subscribe to a channel with their user id as the channel id, then I could send messages to a single user through that channel.
client = new Pusher(PUSHER_API_KEY);
channel = client.subscribe(user_id);
channel.bind('my_event',function(data){
//Do stuff
});
I talked this approach over with the pusher team and they assured me there was no real overhead in having the extra channels. The new Pusher() command is the code that creates a new socket connection so you don't have to worry about extra sockets per channel or anything like that. Hope this helps.
I'm from Pusher. As Braden says, you can easily make a channel per user. This is more efficient than having the user id in the event name which means you spam everyone with useless messages.
This is an area we want to improve on further, so thanks for the feedback.
If you're able to consider another service, Beaconpush has the ability to send messages to a specific user.
From their site:
POST /1.0.0/[API key]/users/[user]