I'm using the pusher interface, and I would like to write a fallback for environments where the pusher service is unavailable. I can't find a way to check if the pusher subscription is ok.
I tried this
$scope.channel.bind('pusher:error', function() {
console.log("pusher:error");
});
and also pusher:subscription_error but it does nothing.
any help will be appreciated.
It's important to highlight the difference between connection and subscription.
A connection is a persistent connection to Pusher over which all communication takes place.
A subscription is a request for data. In Pusher these are represented by channels. Subscriptions and associated data use the established connection and multiple subscriptions are multiplexed over a single connection.
To determine if the Pusher service is reachable or not you should check the connection state.
However, if you ever see this I'd also recommend contacting Pusher support since this shouldn't happen.
Detecting & Querying Connection State
It's possible to detect connection state by binding to events on the connection object.
pusher.connection.bind('state_change', function(states) {
var prevState = states.previous;
var currState = states.current;
});
You can additional get the state right now.
var currentState = pusher.connection.state;
Full documentation on this can be found here:
https://pusher.com/docs/client_api_guide/client_connect#connection-states
The example in the questions appears to use Angular so you'll need to get reference to the connection object from the $scope. If you're using pusher-angular then the API should be the same as the normal Pusher library.
Subscription Status
You can bind to two events to determine the result of a subscription:
pusher:subscription_succeeded
pusher:subscription_error
The code to use these looks as follows:
var channel = pusher.subscribe('my-channel');
channel.bind('pusher:subscription_succeeded', function() {
// Yipee!!
});
channel.bind('pusher:subscription_error', function() {
// Oh nooooos!
});
Documentation on the success event can be found here:
https://pusher.com/docs/client_api_guide/client_events#subscription_succeeded
Docs on the error event can be found here:
https://pusher.com/docs/client_api_guide/client_events#subscription_error
Related
I am trying to read device Id from Event Hub (on the back of IoTHub) but my syntax in JS seems wrong.
module.exports = function (context, IoTHubMessages) {
context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessages}`);
var deviceId = IoTHubMessages.SystemProperties["iothub-connection-device-id"];
The function returns an error: Exception: TypeError: Cannot read property 'iothub-connection-device-id' of undefined
I'm not entirely sure if "iothub-connection-device-id" is the correct name of the attribute on Event Hub but the problem seems to be with SystemProperties.
Appreciate any help.
iothub-connection-device-id is the right key to use, you just have to use it on the right property bag. An unrelated GitHub issue https://github.com/Azure/azure-sdk-for-js/issues/7801 shows how this key is indeed available on each message.
Depending on the cardinality in your functions.json file, IotHubMessages will either be an array of messages or a single message. See IOTHubMessage.forEach is not a function? for more details.
If it is an array of messages, accessing SystemProperties directly on it will not work. You will need to loop through to access each message separately.
Do you see systemProperties on the individual messages? If yes, then message.systemProperties["iothub-connection-device-id"] should work.
You should be reading messages this way. Read this for more about regarding the topic - https://learn.microsoft.com/en-us/samples/azure-samples/functions-js-iot-hub-processing/processing-data-from-iot-hub-with-azure-functions/
IoTHubMessages.forEach(message => {
context.log(`Processed message: ${message}`);
count++;
totalTemperature += message.temperature;
totalHumidity += message.humidity;
deviceId = message.deviceId;
});
First, use the JSON.stringify to print you the payload received. Secondly i believe you should be able to access your device id by doing the following: message.annotations["iothub-connection-device-id"]. For more info, please reference to the Quickstart examples you have available in the Microsoft's Github repos. Navigate to the iot-hub\Quickstarts\read-d2c-messages folder and you should find the example of processing the message payload and printing the output.
I landed on this question when looking for the deviceId when a deviceTwinChange happens on on Azure Iot hub and the message it routed through event hub to my Azure function. In IotHubMessage I wave only getting reported or desired information. I was looking for the deviceId so i knew what device it came from
properties: {
reported: {
//everything in my reported section
}
}
But i found out this:
module.exports = function (context, IoTHubMessages) {
The device Id is in the context variable. I just did not on Azure Iot hub using an Azure function.
var deviceId = context.bindingData.systemProperties["iothub-connection-device-id"];
A bit annoying that the metadata is kept in context and there is no documentation about this.
Extra points: There is no application properties in the context. Does anyone know how to get application properties in the information send to the azure function? This is for when you enrich the data from azure iot hub
This is the information in azure iot hub when doing the routing. Just havent seen the information in my azure function come through.
Add up to 10 message enrichments per IoT Hub. These are added as application properties to messages sent to chosen endpoint(s).
I was trying to send coordinate data for a game by using the broadcast modifier and volatile modifier at the same time. Is that able to be done?
socket.broadcast.volatile.emit('coords', x, y);
Yes, you can do that. All the socket.broadcast and socket.volatile properties do is execute a getter than sets the appropriate flag and then returns the socket object to allow you to chain them. Here's the code for creating those getters:
var flags = [
'json',
'volatile',
'broadcast',
'local'
];
flags.forEach(function(flag){
Object.defineProperty(Socket.prototype, flag, {
get: function() {
this.flags[flag] = true;
return this;
}
});
});
Then, when you call .emit() all the flags are passed on to the adapter that does the actual sending as you can see here. So, the adapter gets the emit() and gets the flags (both broadcast and volatile) to do accordingly.
Note that the main feature of volatile is if that a message is not queued if the client connection is not currently available (client is polling or client has lost the connection and may be reconnecting).
I have two related questions regarding the Firebase web platform's
synchronisation of locally-modified data to the server:
Every client sharing a Firebase database maintains its own internal version of any active data.
When data is updated or saved, it is written to this local version of the database.
The Firebase client then synchronizes that data with the Firebase servers and with other clients on a 'best-effort' basis.
1. Handling sync errors
The data-modification methods
(set(),
remove(), etc)
can take an onComplete callback parameter:
A callback function that will be called when synchronization to the Firebase servers
has completed. The callback will be passed an Error object on failure; else null.
var onComplete = function(error) {
if (error) {
console.log('Synchronization failed');
} else {
console.log('Synchronization succeeded');
}
};
fredRef.remove(onComplete);
In the example above, what kind of errors should the fredRef.remove() callback expect to receive?
Temporary errors?
Client is offline (network connection lost) ?
Firebase server is temporarily overloaded or down for maintenance, but will be available again soon?
Permanent errors?
Permission denied (due to security rules) ?
Database location does not exist?
Is there a way to distinguish between temporary and permanent errors?
How should we handle / recover from these errors?
For temporary errors, do we need to call fredRef.remove() again after a short period of time, to retry the operation?
2. Global sync status
I realise that each call to set() and remove() will receive an individual sync success/failure
result in the onComplete callback. But I'm looking for a way to determine the
global sync status of the whole Firebase client.
I'd like to use a beforeunload event listener
to warn the user when they attempt to leave the page before all modified data has been synced to the server,
and I'm looking for some function like firebase.isAllModifiedDataSynced(). Something like this:
window.addEventListener('beforeunload', function (event) {
if (!firebase.isAllModifiedDataSynced()) {
event.returnValue = 'Some changes have not yet been saved. If you ' +
'leave this page, your changes will be lost.';
}
});
Here's an example of the same functionality in Google Drive:
I'm aware of the special /.info/connected location:
it is useful for a client to know when it is online or offline.
Firebase clients provide a special location at /.info/connected which is updated every time the client's connection state changes.
Here is an example:
var connectedRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/.info/connected");
connectedRef.on("value", function(snap) {
if (snap.val() === true) {
alert("connected");
} else {
alert("not connected");
}
});
The special /.info/connected location can be connected to a beforeunload event listener like this:
var connectedRef = new Firebase('https://myapp.firebaseio.com/.info/connected');
var isConnected = true;
connectedRef.on('value', function (snap) {
isConnected = snap.val();
});
window.addEventListener('beforeunload', function (event) {
if (!isConnected) {
event.returnValue = 'Some changes have not yet been saved. If you ' +
'leave this page, your changes will be lost.';
}
});
My question is:
If isConnected is true, does this also mean that all modified data has been synced to the server?
i.e. Does "connected" also mean "synced"?
If not, how can the app determine the global sync status of the whole Firebase client?
Is there a special /.info/synchronized location?
Does the app need to manually keep track of the sync success/failure result of every onComplete callback?
In the example above, what kind of errors should the fredRef.remove() callback expect to receive?
Client is offline (network connection lost) ?
No, this will not cause an error to be passed to the completion listener. It will simply cause the completion listener to not be called (yet).
Firebase server is temporarily overloaded or down for maintenance, but will be available again soon?
No. This is essentially the same as being without a network connection.
Permission denied (due to security rules) ?
Yes, this is will indeed cause an error to be passed to the completion handler.
Database location does not exist?
No, this will not cause an error to be caused to the completion listener.
If isConnected is true, does this also mean that all modified data has been synced to the server? i.e. Does "connected" also mean "synced"?
No it does not. .info/connected will fire with true when a connection is made to the database.
If not, how can the app determine the global sync status of the whole Firebase client?
There is currently no way to determine whether your local data is up to date with the server.
Is there a special /.info/synchronized location?
No, such a location doesn't exist.
Does the app need to manually keep track of the sync success/failure result of every onComplete callback?
That depends on the use-case. But if you want to simply know when all your writes are executed, push a dummy value and wait for that to complete. Since Firebase executes the writes in order, you can be certain at that stage that you've gotten the other events.
I'm currently trying to rebroadcast my local stream to all my peer connections. options I tried:
1) Loop trough all my peer connection and recreate them with the new local stream. Problem that I encounter here is the fact that createOffer is asynchronous.
2) create 1 sdp and send it to all peers. Problem: no video
Would anyone have a way to resend an offer to a list of peers?
Each PC needs to recreate an offer (as bwrent said).
as you obviously are using a p2p multiparty (multiple peer connections) you might want to pass on the peerID to the createOffer success callback every time, then you don't have to worry about it being asynchronous. You need to make the full handshake (offer, answer, candidate) peerID dependent.
(Simplified) Example from our SDK
Skyway.prototype._doCall = function (targetMid) {
var pc = this._peerConnections[targetMid]; // this is thread / asynchronous safe
pc.createOffer(
function (offer) {
self._setLocalAndSendMessage(targetMid, offer); // pass the targetID down the callback chain
},
function (error) {this._onOfferOrAnswerError(targetMid, error);},
constraints
);
};
Skyway.prototype._setLocalAndSendMessage = function (targetMid, sessionDescription) {
var pc = this._peerConnections[targetMid]; // this is thread / asynchronous safe
pc.setLocalDescription(
sessionDescription,
self._sendMessage({ target: targetMid, ... }), // success callback
function () {} // error callback
);
};
If you mean async in a way that when a callback fires it has the wrong variable of who to send it to as the loop has ended and the variable contains the last 'person'? You could scope it to solve the asynchronous problem:
For(var i=0;i<peerConnections.length;i++){
(function(id){
//inside here you have the right id. Even if the loop ended and the i variable has changed to something else, the I'd variable still is the same.
})(i);
}
This is a bit like Alex' answer, as his anwer also describes an example of scoping the variable inside the function executing the .createOffer
Another way to handle this correctly is to use renegotiation. Whenever you change a stream, the on onnegotiation event handler is automatically fired. Inside this function you create a new offer and send that to the other person. As you mentioned you have multiple peer connect ions listening to the stream, you need to know whom to send the sdp to. If you would add the persons id to the rtc object, you can then get it back inside the onnegotioation event by calling this.id.
When i namespace my app, i run into a problem i want to send data to a particular socket, here's the abbreviated version of the code I'm using:
var io = require('socket.io').listen(config.web.port);
var chat = io.of('space').on('connection', function (socket) {
// This works:
// Input: xhr-polling received data packet 5::/space:{"name":"test"}
// Output: xhr-polling writing 5::/space:{"name":"test","args":[{"msg":"test"}]}
socket.on('test', function(){
socket.emit('test',{msg: "test"});
});
// This fails:
// Input: xhr-polling received data packet 5::/space:{"name":"test2"}
// Output: xhr-polling writing 5:::{"name":"test2","args":[{"msg":"test2"}]}
socket.on('test2',function(){
io.sockets.socket(socket.id).emit('test2',{msg: "test2"});
});
}
As you can see, the second one lacks the namespace part from the output. In the real app I'm picking the socket id from a client manager so I'm using socket.id in this piece of code instead of client.getSocketId(), but the idea is the same as I'm just echoing to the origin client here.
How do i make the second method to use the correct namespace when outputting to the client?
After checking out the source for SocketNamespace, it appears the syntax is io.of('space').socket(id).emit(....
[Edit per Fuu's comment]
To find this, I checked the Socket.IO GitHub repository and looked for a file that would have to do with namespaces--namespace.js seemed to fit the bill. The file wasn't very long, so I scanned it looking for methods on SocketNamespace's prototype that looked like it might do what we wanted.
Since you call io.sockets.socket to find a socket on the global namespace, SocketNamespace.prototype.socket stuck out to me as being promising. Furthermore, it takes a parameter called sid, and the body of the method appears to be fetching a socket from a hash of sockets by this ID. A Socket is what we want (it holds the emit method), so my presumption was that this is the method to use in this case.