Dave's megaref suggestion was the kind of thing I had in mind initially but using Agents might be make more sense.
I'm going to have a play around then report back on my progress. Thanks for your thoughts, it's very much appreciated. James On Friday, 12 April 2013 07:52:22 UTC+1, Cedric Greevey wrote: > > What about a map of table IDs to agents? > > The map itself only needs to change if an event creates or destroys a > table. Anything else impacts a single table, and can be sent off to that > table's agent. An agent makes sense to hold each single table, as tables > undergo sequential transformations triggered by incoming external events. > > Similarly, a map of user IDs to agents can track everyone's play-money. > > The code that translates between incoming network events and sends to > agents is pretty much completely decoupled from the way the latter work, as > well; it won't need to be changed, for instance, if you start persisting > user information to a database. The money-handling agent for a user just > needs to now post an update to the backing database, and your startup code > needs to load the database data to initialize the agent contents on a > restart, and presto, you now have long term persistent user accounts and > money amounts, without touching the network/agent-send code, only the > functions applied to the agents. > > So, sorting incoming network events and calling the appropriate business > logic becomes a concern completely separated from implementing that > business logic, and from the server-side DAL, and from the outgoing > networking. (The agents would need to also generate outgoing network > packets to update clients on the state changes they should know about. For > example, if a player gets dealt a 5 of hearts, their client needs to be > told that -- the others shouldn't, of course, as otherwise it would enable > someone with a hacked client to cheat by peeking at other players' cards.) > > Timers can also be managed in a similar manner; for example, for each > connected client a fold-timeout agent can be created, and when the player > moves, the agent is sent something like this: > > (defn timeout-set [[_ player]] > (let [a *agent*] > (future (Thread/sleep (+ 50 timeout-duration)) (send-off a > timeout-check))) > [(+ timeout-duration (System/currentTimeMillis)) player]) > > which depends on this: > > (defn timeout-check [[timeout-time player]] > (if (<= timeout-time (System/currentTimeMillis)) > (do > (send-off player timed-out) > [Long/MAX_VALUE player]) > [timeout-time player])) > > which will send "timed-out" to the player-agent if they don't move for > timeout-duration milliseconds. When the player moves, timeout-set both sets > the earliest time they may now time out (current time + timeout-duration) > and creates a sleeping thread that will wake up a little bit later than > then and send the agent a timeout-check. (Since *agent* won't be the same > in that thread and when it wakes up, it's saved into a closed-over local in > timeout-set.) The timeout-check function sees if the agent's stored timeout > value has been exceeded; if not the player must have moved again in the > interim and it returns the agent's current state, leaving it undisturbed. > Otherwise, it maxes out the timeout time and sends a timed-out signal to > the player's agent. The player can't get timed out a second time until > moving again first, which would bring the timeout time back down out of the > stratosphere. The timeout time for a player would also be set to this when > there was no hand in progress, and on first connecting. > > Of course, the above could need to be adapted to your needs. Also, I'm > unsure how big a thread pool you'd get with future; very many connected > clients might swamp it with long-sleeping threads. Using the executor > framework stuff from Java might be a better idea, or even more agents (and > send-off rather than send), if you want it to scale, though using a future > makes the example code above very simple and easy to understand. > > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.