On Ably, I'm not receiving messages, how do I debug that? - real-time

I'm using Ably to implement Pub/Sub in my application but I'm getting no errors but at the same time I'm not receiving any published messages. I'm not sure what's wrong. Help appreciated.
Here's my code:
//publisher
var Ably = require('ably');
var apiKey = '';
var ably = new Ably.Realtime({key: apiKey});
var pubChannel = ably.channels.get("sports");
setInterval(function(){
pubChannel.publish('update', {'Team': 'Man United'})
},1000)
//subscriber
var apiKey = '';
var ably = new Ably.Realtime({key: apiKey});
var subChannel = ably.channels.get("Sports");
subChannel.subscribe(function(msg){
document.getElementById('text').innerHTML = JSON.stringify(msg.data);
})
(disclaimer: I am a developer advocate for Ably, and posting and self-answering a commonly asked support question here on Stack Overflow so our users can find this more easily)

Here's what I found as a general debugging process:
First, make sure the channel you're publishing on is the same channel you're subscribing to. (Ably channel names are case-sensitive -- sports is a different channel to Sports).
Second, make sure you're using the same app everywhere (make sure you're not, say, publishing with an api key from your Sandbox app, but subscribing with an api key from your Production app)
Thirdly, you need to find out whether the problem is on the publishing or the subscribing side. Open the dev console, attach to the channel that you're publishing on, and try a publish. Do you see the message appear there (but still not on your subscribing device)? If yes, the problem is on the subscribing side. If no, the problem's on the publishing side.
Debugging publish problems
When you call channel#publish, you can pass a callback (or equivalent - select the language you're using from the language bar), which if the publish failed will tell you why.
Debugging subscribe problems
Check the connection state, make sure you're connected to Ably
Check the channel state, make sure you're attached to the channel
Make sure you've added a subscribe listener. If you added a listener for a specific event name, make sure you're publishing with the exact same event name

Related

Is there a smart possibility to get API results without sending requests every second? [VueJS | Vuetify]

So I made a website to show which services on my server are running and which are offline.
The site is an Vuetify App running in a docker container. My services are monitored via UptimeRobot.
Currently I use:
created: function () {
this.interval = setInterval(() => this.getStatuses(), 1000);
},
To trigger my API request function every second to update the status of my services.
But is there some smarter possibility to only update on change and not request every second to see if something happened?
Like I send one request to get the status and then receive a message when something changed? I hope you can understand, whats my problem. It's hard to decribe.
Yes you can by firing an event. for example:
in your app.js
window.Fire = new Vue();
For example here you create a user then you want to update table after creating a new user, Follow these steps:
createUser(){
// FireUpdate is your fire name, you can give it any name you want!
// Call this after you post something to specific route.
Fire.$emit('FireUpadte');
}
Then you will load new users using this approach:
created(){
// Load new Users after created.
Fire.$on('FireUpadte', () => { this.createUser(); });
}
For more information check this video: https://www.youtube.com/watch?v=DHuTkJzH2jI&list=PLB4AdipoHpxaHDLIaMdtro1eXnQtl_UvE&index=20
What you're looking for are websockets. You establish a websocket connection and it stays open, allowing the server to notify the web app when something changes.
You can run your own socket.io server on a Node.js backend or use a service like Pusher.com (very cheap, free tier is pretty big).
I highly recommend going the Pusher.com route, they also have great tutorials ; )
https://pusher.com

How to receive cumulocity real time notifications with SmartREST?

We use the cumulocity REST API. Regular real time notifications work, e.g. we subscribe to /alarms/*, start our connection/polling loop and when we create an alarm we receive the expected JSON. We did not install any specific modules or statements, it just works.
But when we try to do the same with SmartREST we receive this error, as soon as the alarm is created:
40,,/alarms/177649296,Could not find any templates subscribed for the channel
Following the reference guide (http://cumulocity.com/guides/reference/smartrest/) we tried it like this, where all requests have the same X-Id-header and all requests result in the expected http status 200 and no error messages, except for the last one:
Register a smart response template by doing a POST to /s
Body: 11,102,,,$.channel
Handhake: POST to /cep/realtime
Body: 80
Response is our clientId (e.g. 191het1z38bp7iq1m96jqqt8jnef)
Subscribe: POST to /cep/realtime
Body: 81,191het1z38bp7iq1m96jqqt8jnef,/alarms/*
Connect: POST to /cep/realtime
Body: 83,191het1z38bp7iq1m96jqqt8jnef
In the normal REST case the notification consists of a JSON array with 2 elements, both of which have a property "channel". So that is what we would expect from our response template. Instead, we get the aforementioned error 40.
Is our response template wrong? Is it not properly matched by the X-Id? What does it mean, that there are no "templates subscribed for the channel"? The subscriptions are done for a clientId, and not for a specific response template, and the templates are supposed to be matched automatically anyway. So probably "template" means "X-Id" here? The documentation seems ambiguous as to the meaning of that word. But anyway, we did use the same X-Id header in all of the requests.
Any pointer about what we're doing wrong would be appreciated, since we tried pretty much anything by now.
The SmartREST protocol was developed for a IoT-device <-> platform communication. So there was never any design around using it to subscribing to realtime data (except of course for the operations a device needs) as usually devices to not need subscribe to the data that they created themselves.
That said it is possible to use it but with a couple of limitations. Your approach is basically correct but there is one problem with the subscription. The wildcard subscriptions will not work with SmartREST because on subscription it links your X-Id with the channel you subscribed to but there is never a message published on the channel /alarms/*. Thus this kind of weird error message that said that there was no template subscribed for the channel the alarm appeared on. Inside CometD you still receive the alarm because of the wildcard subscription but the SmartREST part does not work.
The messages are published on the channel with the deviceId (e.g. /alarms/12345).
If you subscribe to /alarms/12345 it will work. You can of course subscribe to as many channels as you want but wildcard subscription won't work.
Regarding the templates you need to know the following. The SmartREST parsing is not done on the raw JSON of CometD but on the payload inside it (e.g. the alarm). So a template for an alarm could look like this:
11,500,,$.severity,$.id,$.type,$.severity
This would trigger only if the object has a severity and would return id, type and severity.

Smack MultiUserChatManager creates not joinable room

I am using Smack 4.1.1 as Gradle dependency in mine Android project.
I have successfully established connection with mine local OpenFire server.
But I have an issue while creating temporary room from Android client.
final MultiUserChat multiUserChat = userChatManager.getMultiUserChat(roomId);  
try {  
multiUserChat.create(connection.getUser());  
LOG.debug("room created");  
} catch (XMPPException.XMPPErrorException | SmackException e) {  
LOG.error("create room error:{}", e);  
}  
try{  
multiUserChat.sendConfigurationForm(new Form(DataForm.Type.submit));   
} catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException e) {  
LOG.error("sending room configurations error:{}", e);  
}   
The most great thing is that I can see that room was created in OpenFire admin panel and get room information from another client.
try {  
MultiUserChatManager userChatManager = MultiUserChatManager.getInstanceFor(connection);  
RoomInfo info = userChatManager.getRoomInfo(roomId);  
LOG.debug("room has {} occupants", info.getOccupantsCount());  
joinToExistingRoom(roomId);  
} catch (XMPPException.XMPPErrorException e) {  
LOG.error("join room error:{}", e);  
final XMPPError.Condition condition = e.getXMPPError().getCondition();  
if (condition == XMPPError.Condition.item_not_found) {  
LOG.error("room does not exist error:{}", e);  
createRoom(roomId);  
}  
}  
But while trying to join room from second client I receive XMPPError: recipient-unavailable - wait.
Snippet of mine joinRoom method:
final MultiUserChat multiUserChat = userChatManager.getMultiUserChat(roomId);  
try {  
multiUserChat.join(connection.getUser());  
LOG.debug("joined to room:{}", roomId);  
} catch (SmackException.NoResponseException  
| XMPPException.XMPPErrorException  
| SmackException.NotConnectedException e) {  
LOG.error("error joining room {}", e);  
}  
So I am catching error joining room org.jivesoftware.smack.XMPPException$XMPPErrorException: XMPPError:recipient-unavailable - wait
So the question is what can be wrong?
I also tried creating submitForm from createAnswerForm() method. But the result is the same.
One solution I have found to make it work is to send persistantroom as true in Answer of configuration form. But this method creates persistent room, though I need this room to be destroyed after all attendees leave room.
Maybe it is a simple problem, but now I do not know how to solve this issue.
Help will be appreciated a lot.
Thanks in advance.
The create() method documentation states that:
Creates the room according to some default configuration, assign the requesting user as the room owner, and add the owner to the room but not allow anyone else to enter the room (effectively "locking" the room). The requesting user will join the room under the specified nickname as soon as the room has been created.
To create an "Instant Room", that means a room with some default configuration that is available for immediate access, the room's owner should send an empty form after creating the room.
Try to send configuration form this way:
multiUserChat.create(connection.getUser())
Form form = new Form(DataForm.Type.submit);
multiUserChat.sendConfigurationForm(form);
See also muc extension documentation

Is it possible to have Lync communicate with a REST API?

I have created a basic REST API where a user can ask for an acronym, and the web-page will return the meaning of the acronym via a POST call.
The majority of my end-users don't use the Internet as much as they use the Microsoft Lync application.
Is it possible for me to create a Lync account, and have it pass questions to my API, and return the answers to the user? Meaning the user just needs to open a new chat in Lync rather than a new web-page.
I'm sure this is possible, but I can't find any information on Google or on the web. How can this be accomplished?
Thanks very much.
Edit :
Adding a bounty in the hopes of someone creating a simple example as I believe it would be very useful for a large number of devs :).
Yep, absolutely. UCMA (the Unified Communications Managed API) would be my choice of API to use here, and a good place to start - UCMA apps are "normal" .net applications, but also expose an application endpoint, which can be added to a user's contact list. When users send messages, that can trigger events in your application so you can take the incoming IM, do the acronym translation and return the full wording.
I have a bunch of blog posts about UCMA, but as of yet no defined collection of "useful" posts to work through, but coming soon! In the meantime, feel free to browse the list.
-tom
To elaborate on Tom Morgan's answer, it would be easy to create an UCMA application for this.
Create an UCMA application
Now this doesn't have to be complicated. Since all you want is to receive an InstantMessage and reply to it, you don't need the full power of a trusted application. My choice would be to use a simple UserEndpoint. As luck would have it, Tom has a good example of that online: Simplest example using UCMA UserEndpoint to send an IM.
Make it listen to incoming messages
Whereas the sample app sends a message when it is connected, we need to listen to messages. On the UserEndpoint, set a message handler for instant messages:
endpoint.RegisterForIncomingCall<InstantMessagingCall>(HandleInstantMessagingCall);
private void HandleInstantMessagingCall(object sender, CallReceivedEventArgs<InstantMessagingCall> e)
{
// We need the flow to be able to send/receive messages.
e.Call.InstantMessagingFlowConfigurationRequested += HandleInstantMessagingFlowConfigurationRequested;
// And the message should be accepted.
e.Call.BeginAccept(ar => {
e.Call.EndAccept(ar);
// Grab and handle the toast message here.
}, null);
}
Process the message
There is a little complication here, your first message can be in the 'toast' of the new message argument, or arrive later on the message stream (the flow).
Dealing with the Toast message
The toast message is part of the conversation setup, but it can be null or not a text message.
if (e.ToastMessage != null && e.ToastMessage.HasTextMessage)
{
var message = e.ToastMessage.Message;
// Here message is whatever initial text the
// other party send you.
// Send it to your Acronym webservice and
// respond on the message flow, see the flow
// handler below.
}
Dealing with the flow
Your message flow is where the actual data is passed around. Get a handle on the flow and store it, because it's needed later to send messages.
private void HandleHandleInstantMessagingFlowConfigurationRequested(object sender, InstantMessagingFlowConfigurationRequestedEventArgs e)
{
// Grab your flow here, and store it somewhere.
var flow = e.Flow;
// Handle incoming messages
flow.MessageReceived += HandleMessageReceived;
}
And create a message handler to deal with incoming messages:
private void HandleMessageReceived(object sender, InstantMessageReceivedEventArgs e)
{
if (e.HasTextBody)
{
var message = e.TextBody;
// Send it to your Acronym webservice and respond
// on the message flow.
flow.BeginSendInstantMessage(
"Your response",
ar => { flow.EndSendInstantMessage(ar); },
null);
}
}
That would about sum it up for the most basic example of sending/receiving messages. Let me know if any parts of this need more clarification, I can add to the answer where needed.
I created a Gist with a full solution. Sadly it is not tested because I'm currently not near a Lync development environment. See UCMA UserEndpoint replying to IM Example.cs.
I never used Lync but while I was looking at the dev doc, I stumble upon a sample which could be what you're looking for.
Lync 2013: Filter room messages before they are posted
Once you have filtered the messages, you just need to catch the acronym and call your custom code that calls your API.
Unless I'm missing something, I think you could do it with a simple GET request as well. Just call your API like this yoursite.com/api/acronym/[the_acronym_here].
You can use UCWA (Microsoft Unified Communications Web API),is a REST API.For detail , can reference as the following..
https://ucwa.lync.com/documentation/what-is-lync-ucwa-api

Real time model events in Sails.js 0.10-rc5

I've been playing around with building some realtime functionality using Sails.js version 0.10-rc5 (currently the #beta release).
To accomplish anything, i've been following the sweet SailsCast tutorial on this subject (sailsCast link)
It talks about subscribing to a model via a 'subscribe' action within the model's controller. Then listening to it at the client side, waiting for the server to emit messages. Quite straightforward, although I do not seem to receive any messages.
I'm trying to do this to get real-time updates on anything that changes in my User models, or if new ones get created.. So I can display login status etc. in real time. Pretty much exactly the stuff that's explained in the sailsCast.
In my terminal i'll get two things worth noticing, of which the first is the following:
debug: Deprecated: `Model.subscribe(socket, null, ...)`
debug: See http://links.sailsjs.org/docs/config/pubsub
debug: (⌘ + double-click to open link from terminal)
debug: Please use instance rooms instead (or raw sails.sockets.*() methods.)
It seems like the 'subscribe' method has been deprecated. Could anybody tell me if that's correct, and tell me how to fix this? I've been checking out the reference to the documentation in the debug message, although it just points me to the global documentation page. I've been searching for an answer elsewhere, but haven't found anything useful.
The second message I'm getting is:
warn: You are trying to render a view (_session/new), but Sails doesn't support rendering views over Socket.io... yet!
You might consider serving your HTML view normally, then fetching data with sockets in your client-side JavaScript.
If you didn't intend to serve a view here, you might look into content-negotiation
to handle AJAX/socket requests explictly, instead of `res.redirect()`/`res.view()`.
Now, i'm quite sure this is because I have an 'isAuthenticated' policy added to all of my controllers and actions. When a user is not authenticated, it'll redirect to a session/new page. Somebody must log in to be able to use the application. When I remove the 'isAuthenticated' policy from the 'subscribed' action, the warnings disappear. Although that means anyone will get updates via sockets (when I get it to work), even when they're logged out. - I don't really feel like people just sitting at the login screen, fishing out the real time messages which are intended only for users who are logged in.
Can anyone help me getting the real time updates to work? I'd really appreciate!
As far as the socket messages not being received, the issue is that you're following a tutorial for v0.9.x, but you're using a beta version of Sails in which PubSub has gone through some changes. That's covered in this answer about the "create" events not being received.
Your second issue isn't about sockets at all; you'll just need to reconsider your architecture a bit. If you want to to use socket requests to sign users in, then you'll have to be more careful about redirecting them because, as the message states, you can't render a view over a socket. Technically you could send a bunch of HTML back to the client over a socket, and replace your current page with it, but that's not very good practice. What you can do instead is, in your isAuthenticated policy, check whether the request is happening via sockets (using req.isSocket) and if so, send back a message that the front end can interpret to mean, "you should redirect to the login page now". Something like:
module.exports = function (req, res, next) {
if ([your auth logic here]) {
return next();
}
else {
if (req.isSocket) {
return res.json({status: 403, redirectTo: "/session/new"});
} else {
return res.redirect("/session/new");
}
}
}