A very popular UK dating/adult site (URL on request ;-) has bought the code from me and is running a modified version of Ameegos on their site and the chat is proving popular to put it mildly. So popular in fact that a single server couldn't cope with the traffic and was frequently being brought to its knees by around 1500 concurrent video chatters.
And this is where the application failed: it wasn't able to scale across multiple servers; instead users have to manually navigate between servers.
Some background info: the room objects hold a variety of information, amongst it is a roomid which is used to build the application/room instance on the fly. As the rooms were already connecting to the master instance serverside and proxying a SharedObject I figured it wouldn't be too hard to store an entire RTMP string inside each room, effectively allowing unlimited servers to be added (in theory each room could have its own server although that's never necessary in this case as each room is limited to 70 to 80 users).
Long story short I went ahead and started building the serverside application which, if you have ever had to debug multiple instances of multiple applications on FMS, is *not* a nice thing to do.
The one problem I had to overcome was this: whe the very first user connects to the application (Which at this stage is not yet running) is automatically kicks onAppStart into life. Inside the onAppStart handler I am setting up my serverside connection to fetch the SharedObject contents from my master instance (no user ever connects directly to the master). I then make decisions based on that data as to where to send the user (best server/room in terms of current traffic). This was tricky because the SharedObject onSync would not fire quick enough before the onConnect was invoked and the connection accepted - this meant that crucial room data wasn't present in time and the first connection by the very first user was rejected. A rare case but still I wanted to fix it. But how?
I remembered reading about putting clients into a pending state before verifying credentials and accepting the connection later on. This should work for SharedObject related delays too...
A browse through the docs made it clear that this code would put a connecting client into pending (neither accepted nor rejected). Note: code formatting is a bit screwed up:
{
return null; // client is now pending }
{
// store client for approval this.client = client;
return null; // client is now pending }
{
if (application.client)
{
// accept the connection application.acceptConnection(application.client);
}
}
What I still don't understand if this is really the right way to do it. What would happen if multiple clients connect at the same time - how does this code approve the right client reference? If I had multiple clients in a pending state would this code still work? Right now (with a single client) it works fine but I have a feeling that I may need to match the correct client via a application.clients lookup somehow or risk accepting the wrong one... Can someone clarify?

I think the key here is to push pending clients in an array (application.pc_array) and then when onSync is fired accept the first one in the array.
application.onConnect = function(newClient)
{
var myASPXServiceResult = new ASPXServiceResult();
myASPXServiceResult.Client = newClient;
var myASPXService = application.gatewayConnection.getService("evoChatRemoting",myASPXServiceResult);
myASPXService.startUserChatSession(newClient.ip);
}
ASPXServiceResult.prototype.startUserChatSession_Result = function(result)
{
if(result == "OK")
{
application.acceptConnection(this.Client);
}
}
do you know if
application.acceptConnection(this.Client);
always reliably resolves to the right client?
I'm just trying to get my head around it. I've used serverside Remoting myself and it always worked fine, I just want to figure out *how* it works.
This line
application.acceptConnection(this.Client);
would refer to whichever current Client then, it is not a avlue that you have stored previously anywhere, correct?
I wonder if someone can explain how the server keeps track of the different clients, I presume it *knows* which client initiated the remoting request and matches it to that automatically, even if another client connects in the meantime before the first Remoting call has returned.
myASPXServiceResult.Client
You're storing the client reference - that makes sense. However for my purposes (which don't use Remoting) I still haven't figured out how to match clients properly. It's ghard to explain, maybe I should open a new post with more details.
When he references the Client he's using
this.Client, but "this" actually refers to myASPXServiceResult, and in the onConnect function you have myASPXServiceResult.Client= newClient.
If he would have used: application.myASPXServiceResult.Client then his code would have failed when the next user connected before the previous one was accepted.
so.Client =...
followed by
so.onSync=function(){
this.Client
}
I hope this helps!
>Inside the onAppStart handler I am setting up my serverside connection to fetch the SharedObject contents from my master instance
Why not set up this ss connection inside onConnect, and only set it up when the first client connects? this way you will have better acces to the Client object via ns.Client or so.Client
I hope this makes sense!
the most obvious one (not sure why I haven't thought of this before, Will Law had to remind me) is to simply store all pending clients in an array and then simply approve them all (without having to match them up again) once my NC returns success. Hope this makes sense.
I could leave everything in my code as it was and simply add a pendingClients Array. Add every client to that while a variable startedUp == false and then approve all pending clients once the NS onStatus has returned. There was no need to identify a certain client, I can simply loop over them all and approve them. DOH DOH and DOH.
Who said FMS was hard? :-)