Client session. This represents a connection to one browser (or other client application). Each browser client is a separate session, so we create one instance of this class per connected browser. Note that browser instances don't necessarily represent different users - a single user could open multiple browser windows on the same server.
We identify each browser instance via a session cookie, which we establish when the client connects. The browser sends the cookie with each subsequent request, allowing us to tie the request to the browser session we previously set up.
The client session key. This identifies the client across requests. We send this to the client as a cookie when they connect, so we get it back on each request.
Is this session alive? When we detect that the client has disconnected, we'll set this to nil. When waiting for a client in a modal event loop, this can be used to terminate the wait if the client disconnects.
Am I the primary player? This is true if the player connected using the primary session key. Collaborative players join through the separate collaborative session key.
Last request time, in system ticks (ms). We use this to determine how long it's been since we've heard from the client, for timeout purposes. This is updated any time we receive a command or event request from the client, and each time we successfully send an event reply.
The client's event queue. When a server-to-client event occurs, we post it to each current client's queue. When the client sends a get-event request, we satisfy it out of this queue.
The storage server session key for the user connected to this session, if any. We can have multiple users logged in to the game in collaborative play mode, each with their own separate storage server session. This allows each user to have their own private preference settings, saved games, etc.
Check to see if the client is still alive. If the client has no pending event requests, and we haven't heard from the client in more than the client session timeout interval, assume the client is no longer connected and kill the session object.
This should be called whenever a sending a reply to a request fails with a Socket Disconnect exception. We also run this periodically during routine housekeeping to check for clients that haven't even bothered to send a request.
Class method: forcibly disconnect all clients. This simply deletes the list of active clients and deletes any pending events in their queues. This doesn't actually terminate their network connections, but simply clears out any pending work for each client that we've initiated on the server side.
Send a keep-alive reply to each pending request from this client that's been waiting for longer than the timeout interval.
Javascript clients in principle will wait indefinitely for an XmlHttpRequest to complete, but in practice browsers tend to set fairly long but finite time limits. If the time limit is exceeded for a request, the client will fail the request with an error. To prevent this, our main event loop (processNetRequests) periodically calls this routine if no other events have occurred recently. We'll clear out the pending event request queue for each client by sending a no-op reply to each event. This tells the client that the server is still alive and connected but has nothing new to report.