SignalR via Azure Service Bus - javascript

I must be missing something when setting up SignalR to use an Azure Service Bus. I have my App Service (API - Web API 2) setup to run 3 constant instances (currently), upon startup, the API uses the Service Bus connection string and sets the appropriate topic prefix.
On the front-end, SignalR is able to connect to my API, but messages are only sometimes received by the client. My assumption is that the client only receives messages from the server to which it originally connected. This leads me to believe that SignalR is not using the Service Bus correctly. When viewing the Service Bus via Azure, I do see that topics are being created, but there are no messages in any of them (I also see subscriptions).
So, as far as I can tell, SignalR between the client and server is still using a direct connection instead of going through the Service Bus. Note that the client is using the URL of the API for the SignalR connection -- is this correct?
SignalRConfig (During app startup.)
var serviceBusConnectionString = configHelper.SignalR.ServiceBusConnectionString;
var serviceBusTopicPrefix = configHelper.SignalR.TopicPrefix;
Logger.Info("SignalR: configuring");
// Use the service bus, if specified.
if (serviceBusConnectionString != null && serviceBusTopicPrefix != null) {
Logger.Info("SignalR: using service bus");
GlobalHost.DependencyResolver.UseServiceBus(serviceBusConnectionString, serviceBusTopicPrefix);
}
app.MapSignalR();
The above code runs for each instance, I have no idea if this is correct or not. Perhaps that is why I am seeing multiple topics, e.g. signalr_topic_my-app-staging_0 -- 0 through 5.
Note that I've tried to follow this (outdated) tutorial: https://learn.microsoft.com/en-us/aspnet/signalr/overview/performance/scaleout-with-windows-azure-service-bus

Your code seems correct and it should run for each instance.
There should be 6 topics in Service Bus: signalr_topic_{TOPIC_PREFIX}_0 through to signalr_topic_{TOPIC_PREFIX}_5.
Is each instance using the same topic prefix name? If they are using different topic names then this would explain the behavior you are seeing.

Related

Communication between JavaScript and WCF Service Library (WCF Test Client)

there is a web service (WCF Service Library) when I debug the web service project (in Visual Studio) "Test Client WCF" is launched (so I guess its hosted via the Test Client). I have a web service method called "Test" which returns string. When I "call" that method with the Test Client WCF - it works.
When I want to use browser as a client. I go to http://localhost:9001/Name/WebService/WebAPI and I see the web service (xml with some info about methods). And now I want to use JavaScript to call that Test method.
I created a client similar to this https://stackoverflow.com/a/11404133 and I replace the sr variable (SOAP request) with a request, which is in XML part of the Test method in the "Test Client WCF" and for url I chose http://localhost:9001/Name/WebService/WebAPI . I tried that JavaScript client, but I got some client error -
content-type 'text-xml' is invalid, server wanted
'application/soap+xml; charset=utf-8'
(unfortunately right now I can't get to the web service, so I don’t know a number of the error and exact message, but there was no other information, beside the content-type). So I changed the request header to 'application/soap+xml; charset=utf-8', but then I got error – that tells me:
The message cannot be processed at the receiver, due to an
AddressFilter mismatch at the EndpointDispatcher. Check that the
sender and receiver's EndpointAddresses agree
(Or something like that - I had to translated it to english)
I also tried the "JavaScript client" with an existing service, that I found on the internet and with text/xml content-type. And it works fine.
Please do you have any advice - how to call the Test method with JavaScript? Thanks.
The service invocated in Javascript is called Restful style service. WCF is able to create a Restful style service too. But we need to set up some kinds of additional configuration. The service is hosting in IIS express when we test the service in Visual Studio. It uses the default binding configuration to host the service(BasicHttpBinding), called SOAP web service. The universal way to invocate the service is taking advantage of using service proxy class, that is what the WCFTestClient do.
If we want to invocate the service by using JavaScript, here is a simple demo, wish it is useful to you. Please be aware that the project template is WCF Service Application instead of Service Library project.
https://stackoverflow.com/questions/56873239/how-to-fix-err-aborted-400-bad-request-error-with-jquery-call-to-c-sharp-wcf/56879896#56879896
Feel free to let me know if there is something I can help with.

Meteor: How can I get useraccounts package to write a new user doc into a remote collection?

I'm using the packages accounts-password and useraccounts:bootstrap and it all works fine, meaning the sign-on form creates a new doc in the Meteor.users collection. But I don't want any collection on the client facing app, hence I do have a second app running to which I successfully connect via DDP.connect() and I can exchange all necessary docs/collections via pub/sub and calling methods on the remote app.
The only thing that doesn't work is the useraccount doc. I've used (on the client app):
remote.subscribe('users', Meteor.userId(), function() {
});
and (on the remote app):
Meteor.publish('users', function() {
return Meteor.users.find({});
});
even though I'm not sure if there is a pub/sub already included in the package. Still, the doc is written to the local (client) app and not to the remote app.
How can I achieve this?
useraccounts:core simply makes use of Accounts.createUser on the server side (see this line) within a method called from the client-side (see this another line).
So the new user object is created from the server side and not from the client (though it flows all the way down to the client thanks to the DDP and default users subscriptions...).
If you're really looking to change the defaul behaviour provided by the Meteor core Accounts packages (accounts-base, accounts-password in this case...) you should try to override the Accounts.createUser method which is were all begins...
In any case be warned that the current user is published to the client by default: see these lines
Finally, to prevent useraccounts:core to use the Accounts API you could try to override the AtCreateUserServer method and deal with the creation of a new user on a remote application inside there.
Package accounts-base provide such functionality.
The accounts-base package exports two constructors, called AccountsClient and AccountsServer, which are used to create the Accounts object that is available on the client and the server, respectively.
Nevertheless, these two constructors can be instantiated more than once, to create multiple independent connections between different accounts servers and their clients, in more complicated authentication situations.
Documentation: Accounts (multi-server)

Modifying Pubnub presence heartbeat for Python

According to the presence documentation, Pubnub will fire the Timeout presence event after 5 minutes of not receiving a heartbeat.
I need to modify this value but I cannot find a way of doing this with the Python SDK. Here is a link to the Pubnub docs showing how to do it with JavaScript: http://www.pubnub.com/docs/web-javascript/presence#optimizing_timeout_events
Does anyone know how to achieve this using the python SDK?
Thanks a lot.
edit: My clients are not javascript clients. They are python console applications.
Heartbeat can be monkey-patched into the Pubnub class with something like this:
from pubnub import Pubnub
class PubnubHeartbeat(Pubnub):
def __init__(self, heartbeat=300, **kwargs):
self.heartbeat = heartbeat
super(PubnubHeartbeat, self).__init__(**kwargs)
def getUrl(self, request):
if "subscribe" in request['urlcomponents'][:2]:
if "urlparams" not in request:
request['urlparams'] = {}
request['urlparams']['heartbeat'] = self.heartbeat
return super(PubnubHeartbeat, self).getUrl(request)
p = PubnubHeartbeat(
subscribe_key="demo",
publish_key="demo",
heartbeat=60
)
def recv(msg):
print msg
p.subscribe(channels="heartbeat_test", callback=recv)
This isn't recommended for long-term production code (unless maybe if you are pinning your Pubnub dependency with pubnub==3.7.3 during install). The example subclass uses an undocumented method to inject the heartbeat URL parameter. (See Craig Conover's answer for a description of what that does).
PubNub Python SDK Presence
Because Python is rarely used as a client, the PubNub Python SDK's presence API is not as robustly implemented as the traditional client SDKs (JavaScript, etc.). So there is no heartbeat parameter in the Pubnbub intitializer nor is there a setter or attribute for this so you are forced to stick with the default 5 minute heartbeat setting.
However, with the PubNub JavaScript SDK, when you init PUBNUB with a custom heartbeat (60 seconds for example), the heartbeat key/value is just passed along as a query param in the REST URL:
http://pubsub.pubnub.com/subscribe/demo/my_channel/0/14411482999795083?uuid=12345&pnsdk=PubNub-JS-Web%2F3.7.14&heartbeat=60
So if you really wanted to, you could just subscribe using REST calls and pass the heartbeat in that way.
What I forgot to mention when I first posted this answer is that your client is responsible for pinging the PubNub server at least once every 60 seconds, preferably on a 30 second interval this the 60 second heartbeat window that the server is configured for this client.
With the PubNub SDK, this is done in a separate thread over the same connection (sort of - at least in a way that the server knows that it is the same client that set the heartbeat).
That said, we are getting into a less trivial solution using REST and so why even use the SDK. It would be easier for us to update the Python SDK than for you to do all the dirty work. We will do just that but not in the short term but hopefully with the next minor release of the Python SDK.
Based on our off-SO conversation, you just want to shorten the window of time that a client will appear to be online when in fact the client is not connected and was unable to explicitly unsubscribe before the connection was closed (closed the terminal instead of "logging off" using your app's UI or command line).
What you can do is implement a ping/ack handshake protocol. This is very high level so there may be some finer points that need to be filled in but it should provide the general concept.
Before one client (sender) engages in communication with another (receiver), just send a ping message to the other client on the client’s private channel (every client will subscribe to a channel unique to that client: for example, private_client001, private_client002, etc.).
The receiving client will auto-ack back on the sender’s unique channel (which will be part of the ping msg payload)
If the sender of the ping doesn’t get an ack msg back within a second (or whatever time tolerance works for you) then assume the receiver is not online.
When the receiver comes back online, you get missed messages, and any pings that are less than 5 minutes old, you can ack back and see if the sender still wants to engage.
This is a common issue for many use cases (especially chat) because there is always that window of time (the heartbeat window) that a client could really be offline but appear to be online because they did not leave in proper, predictable fashion that would have produced an explicit unsubscribe resulting in a leave event. So implementing this sort of handshake pre-connect protocol is a good practice.

Using the Pusher.com API for client to client events

I have setup an account and app in the pusher.com API dashboard and have experimented with both private and public channels and client->client events - I have no trouble doing this.
My project is using CodeIgniter (latest) PHP framework (+ jQuery latest + pusher latest) and I have access to edit everything - nothing is out of bounds in terms of solutions, this is a non commercial project.
My aim is to have client/socket A send an event/message to client/socket B within 'channelX'.
I would like many people/sockets to be possible within 'channelX' - so for example we could have 10 clients connected to this channel, but within it I would like 2 parties to be able to communicate directly with each other (can be via server or just via pusher api).
At the moment, and where my understanding and research leads me: is that any event triggered in my 'channelX' private channel is sent to all clients - now I have used the 'exclude socket' parameter to make sure the event doesn't trigger on 'socketA' (the person doing the initiating of the event) - and this works when there is only 2 clients/sockets connected to a channel - but add more parties and it gets messy.
The question:
Should a channel ONLY have 2 clients/sockets if the events are only to be shared between two?
Ideally what I would like to do:
Have one master channel which holds all users - then each user should be able to send a 'ping' or 'poke' to one of the other users - without all of the other clients receiving this pusher event/trigger.
I do have code but my question is really theory based and so I'm not expecting bundles of code to come from this question - but the docs on the pusher.com website kind of miss this point (or perhaps I did!)
Thanks for any input
There is an old FAQ article on how to implement 1-to-1 chat that may provide a strategy that suits your needs.

Multiple Websockets

I'm trying to use two websockets on one page. This is my code:
var pageViewWs = new WebSocket("ws://localhost:9002/pageView");
var sessionWs = new WebSocket("ws://localhost:9002/session");
pageViewWs.onmessage = function (event) {
alert("PageView");
};
sessionWs.onmessage = function (event) {
alert("Session");
};
Only the PageView alert appears. On the server side no requests are made to /session, only to /pageView.
Now, if I switch var pageViewWs and var sessionWs around then the Session alert is shown instead of the PageView. It is not because they are alerts, I've tried appending to the body and to divs and I've stepped through using Firebug. It seems that only one WebSocket can be created at a time although in Firebug the properties for pageViewWs and sessionWs appear the same with the exception of their url.
I've only tested this in Firefox 15.0.1. Is there some sort of Websocket limitation whereby you can only run one at a time? Or is something wrong with my code?
I faced the same problem to run multiple services through the same port. So, I created a PHP library to do this.
Why ?
Some free plans of hosting providers don't allow you to bind to ports or allow you to bind to one port. In case of OpenShift Cloud Server, you can only bind to port 8080. So, running multiple WebSocket services is not possible. In this case, Francium DiffSocket is useful.
You can run different services on the same port using a PHP library called Francium DiffSocket.
After setting up Francium DiffSocket, you can do this for using different services :
var chatWS = new WebSocket("ws://ws.example.com:8000/?service=chat");
var gameWS = new WebSocket("ws://ws.example.com:8000/?service=game");
An example are these services which are running through a single port :
Finding Value Of Pi
Advanced Live Group Chat With PHP, jQuery & WebSocket
Live Group Chat With PHP, jQuery & WebSocket
I believe you can only create one WebSocket connection from a client to a specific port on the host. Have you tried either running the two services on different ports, or on different servers? This would allow you to determine the limitation...
Apart from the HTTP Request head both the request are the same. They hit the same application server on the same port. It is up to the server side application to treat each connection differently based on the HTTP request that initiated it.
I've done this in node. You could do it manually but packages like
espress-ws
or express-ws-routes
eases the process.

Categories

Resources