Using SignalR in full ajax navigated web pages? - javascript

I'm trying to accommodate myself to SignalR.
But I need a gold point to completely understand it. I feel one step away from snatch...
My codes:
Javascript:
$(function() {
var connection = $.connection.signalR;
connection.client.broadcastTotalOnline = function (totalOnlineUser) {
$('#TotalOnline').html(totalOnlineUser);
};
$.connection.hub.start().done(function() {
console.log("Connection Started!");
});
});
C#:
public class SignalR : Hub
{
public void SendTotalOnline()
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalR>();
using (var dbContextx = new db_Oyun())
{
while (true)
{
int totalOnlineUser = dbContextx.tbl_User.Count(x => x.Online);
context.Clients.All.broadcastTotalOnline(totalOnlineUser);
Thread.Sleep(1000);
}
}
}
}
Above codes are work perfect but when I call new page to inner content with AJAX.
And then I would like to use same hub, same object and same hub, different object. It not working. Not calling alert; but when I removed above signalR codes, under codes working.
$(function () {
var connection = $.connection.signalR;
connection.client.broadcastTotalOnline = function (totalOnlineUser) {
alert(totalOnlineUser);
};
});

When you start your SignalR connection, it examines the $.connection.signalR.client object to see if you added any callbacks. If you add a callback using normal assignment after the connection has started, SignalR will not pick up that callback.
To add a callback after the connection has started, you can use $.connection.signalR.client.on:
$.connection.signalR.client.on("broadcastTotalOnline", function (totalOnlineUser) {
alert(totalOnlineUser);
});
If you were trying to add a callback to a Hub you didn't already have a callback for before starting your connection, then even using .on would not work.
You must have at least one callback hooked up to every hub you plan to use before you start up your connection. The callback that you setup can be a dummy callback that is never called. Adding the callback is just you way of indicating to SignalR that your interested in messages originating from that hub.
You don't need to add any dummy callbacks in your case since you already attach to broadcastTotalOnline before starting the connection.
If you want to remove a callback, you can use $.connection.signalR.client.off with a reference to the function you previously added:
var callback = function (totalOnlineUser) {
alert(totalOnlineUser);
};
$.connection.signalR.client.on("broadcastTotalOnline", callback);
$.connection.signalR.client.off("broadcastTotalOnline", callback);

Related

Is it possible to swap out the Node.js net socket data event listener?

I'm using the Node.js net package to connect to and communicate with a Telnet server. I'm using net.createConnection() to create and initialize a socket; then doing something like the following to bind the initial data event listener:
client.on('data', (data) => { this.handleFoo(data) });
I thought it might be a good idea to encapsulate different functionality in different callbacks; one to handle negotiating the connection, logging in, etc. One for general purpose communication.
I tried simply calling .on() again to see if I could replace the event listener callback to something that didn't have all of the connection/logon code:
client.on('data', (data) => { this.handleBar(data) });
Unfortunately that had no effect, and the original callback was getting called again. Is this possible to do?
I couldn't find another socket method that would un-register that first listener callback.
Thanks.
You need a named function. Use client.removeListener() or client.off() available since Node.js v10.0.0. These are available to net.Socket because it extends EventEmitter.
const fooHandler = (data) => { this.handleFoo(data) };
client.on('data', fooHandler);
...
client.off('data', fooHandler);

SignalR JavaScript client universal trigger

I need to attach an event to every hub.client method.
For example:
Hub.client.doSomething = function (e) {
aFunction(e);
};
Hub.client.doSomethingElse = function (e) {
aFunction(e);
};
Is there a way to attach aFunction() to all client methods on the client level, without placing the function in each client method?
I don't know about such callback available directly on hub proxy, but you could use received callback on connection object. (see list of connection lifetime events and received definition)
Be aware that received callback is called every time data is received by connection, this means, that if you have multiple hubs, it will be invoked when any of hub send data to client. This means, that you will have to inspect data received in callback and decide, if you should process this data (if it belongs to given hub, if it is real message, or just signalr internal message).
With some JavaScript code you can achieve what you need, regardless of what SignalR provides out of the box:
var extend = function (proxy, ex) {
var keys = Object.keys(proxy.client),
aop = function (p, k, f) {
var prev = p[k];
return function () {
f();
prev.apply(p, arguments);
};
};
keys.forEach(function (k) {
proxy.client[k] = aop(proxy.client, k, ex);
});
};
extend(Hub, aFunction);
It is enough to call the extend function on all your hub proxies after having defined your real handlers.
With some more effort this code can be made more solid and generic, but I think it should already put you in the right direction.

Nodejs How to access a tcp socket outside the callback function

If I create a server using this code:
var net = require('net');
server = net.createServer(function(sock){
/** some code here **/
});
server.listen(9000);
How do I access the socket outside of the callback function? This would help me to be able to create an array/list of sockets that I can store and access whenever I need to send data to a specific client.
I did have a weird workaround that I am currently using but I don't think this is the correct way. Basically I added socket to the server object by saying:
this.socket = sock
inside the callback function of createServer.
Then I can access it saying server.socket but this is only really useful if there is only one client.
To help better understand what I am trying to accomplish I have created a class that has a constructor function which holds this code:
this.server = net.createServer(this.handleConnection)
This class also has the method handleConnection to use as the callback. I also have a method called start which can be called with a port as a parameter to initiate server.listen(port).
What I want to accomplish is a method like below:
sendCommand(message, socket){
socket.write(message);
}
This way the server can send a message to the client from a function that is not within the callback function of createServer. Keep in mind that I am doing this from within a class so using the this keyword within the callback function accesses the net server object and not the class I created.
Every example I see is an extremely simple tcp server that only has one message sent from the server within the callback function. If anyone could shed some light on my problem that would be great thanks!
I'm not sure if this is what you're after, but I would do something like this.
var net = require('net');
var conns = [];
var server = net.createServer(function(sock){
conns.push(sock);
sock.on('close', function (){
// TODO: Remove from conns
});
});
server.listen(9000);
var net = require('net');
var listeners = [];
server = net.createServer(function(sock){
/** some code here **/
listeners.push(sock);
sock.on('close', function (){
var index = listeners.indexOf(sock);
if (index > -1) {
listeners.splice(index, 1);
}
});
});
server.listen(9000);

Singleton Websockets object with different callback handlers

I have a JavaScript Websockets implementation where I would like to use a singleton model that uses one Websocket connection for multiple calls to the server but with different callback event handlers. I have the implementation working just fine but have noticed some strange behaviors with messages being directed to the wrong callback handler. Here is some code:
Connection.js file
var connection = function(){
var _socket = null;
return {
socket : function(){
if (_socket == null){
_socket = new WebSocket("ws://localhost:8081/index.ashx");
_socket.onclose = function(evt){alert('Closed');}
_socket.extraParameter = null;
}
return _socket;
},
send : function(data, callback){
var localSocket = connection.socket();
localSocket.extraParameter = new Date().toString();
localSocket.onmessage = callback;
localSocket.originalDataSent = data;
localSocket.send(data);
}
}
}();
App.js file
var App = function(){
return {
cpuUtilization : function(evt){
var localSocket = this;
var dateTimeOfRequest = localSocket.extraParameter;
var originalDataSent = localSocket.originalDataSent
var jsonData = $.parseJSON(evt.data);
if ($.parseJSON(originalDataSent).type == "cpu"){
$("#dateTimeContainer").html();
$("#cpuContainer").html(jsonData.value);
}
}
}
}();
Third Party Signal.js file
var Signal = function(){
return {
handlerProcess : function(evt){
// Does some third party stuff...
}
}
}();
usage
connection.send("{type:'process'}", Signal.handlerProcess);
connection.send("{type:'cpu'}", App.cpuUtilization);
connection.send("{type:'memory'}", Signal.handlerMemory);
connection.send("{type:'harddrive'}", Signal.handlerHardDrive);
Now where I think I am see the problem is when multiple request are made through the same websocket and the message returns. Since this is asynchronous, I have no way of tieing the request to the event callback. My solution uses the options in the handler for reference, but depending on the time it takes for the websocket request to run, the wrong callback handler is being called and process fails. I think it is failing because I am accessing properties from the websocket instance that may be changing between calls.
Is there a way to pass a reference or additional parameters along with the evt parameter? Maybe wrapping this somehow?
I think it is failing because I am accessing properties from the websocket instance that may be changing between calls.
Yes.
Since this is asynchronous, I have no way of tieing the request to the event callback.
No. You can create a closure for the callback function instead of calling using callback directly:
... send: function(data, callback){
var localSocket = connection.socket();
var extraParameter = new Date().toString();
localSocket.onmessage = function(evt) {
callback(evt.data, /* original- */ data, extraParameter);
};
localSocket.send(data);
}
But still, you have a changing onmessage callback handler. That means, an event may be sent to a handler that does not deserve it. Having an asynchronous system, you will need to add a piece of information to the server resonse that indicates which process the data belongs to. The one universal message handler then could resolve that and call the right callback.

How do you dynamically call a function in Actionscript 3 from Javascript at runtime without using eval()?

I'm trying to build an API in JS that will perform some operations and then execute the callback that's registered in AS when it's done. Because it's an API, I am just providing a JS method signature for another developer to call in Flash. Thus, the callback name that's registered in the AS part of the code should be a parameter that's passed in to the JS API in order for JS to communicate back to Flash.
For example:
[AS3 code]
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", flashCallbackName);
function processRequest(data:String):void
{
//do stuff
}
[JS code]
var namespace =
{
jsFnToCall: function(callback)
{
//Do stuff in this function and then fire the callback when done.
//getFlashMovie is just a util function that grabs the
//Flash element via the DOM; assume "flash_id"'s a global var
//Below does not work...it's what I'd be ideally be doing some how.
getFlashMovie(flash_id).callback(data);
}
};
Because the definition of the function is in AS, I can't use the window[function name] approach. The only way I can think of is to build the callback in a string and then use the eval() to execute it.
Suggestions? T.I.A.
Well, I can think of one thing I would try, and one thing that would work.
What I would try first.
getFlashMovie(flash_id)['callback'](data);
What would work: Have the callback always be the same, say callback. The first parameter to the callback could be used to determine what actual function to call in flash. For example:
function callback($fn:String, $data:*) {
// either
this[$fn]($data);
// or
switch ($fn) {
case "callback1":
DoSomeCallback($data);
break;
}
Additionally passing the objectID makes it a bit simpler:
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", ExternalInterface.objectID, "flashCallbackName");
Then in your JS:
var namespace =
{
jsFnToCall: function(objectID, callback)
{
//Do stuff in this function and then fire the callback when done.
document[objectID][callback](data);
}
};

Categories