server: Refactor to use per-instance locking
Instead of having a WebServer
object handling state machine state and a
WebSocketsCollection
handling websocket connections, we now have all
per-instance state in ServerApp
objects: websocket connections are tracked in
ServerApp.channels
, and state-machine state is in
StateMachineServerApp.state
. Updates to different instances can happen in
parallel: synchronization happens at the level of independent apps.
Also take this opportunity to clean up clock-driven apps: events are now sent unserialized, rather than being serialized and immediately deserialized afterwards.
* jvm/src/main/scala/cs214/webapp/server/web/WebServer.scala:
(Wordlist):
New class. Move wordlist management here.
(instanceIdWords):
Load wordlist just once, eagerly.
(RunningClock, RunningServerAppInstance):
Remove (moved to `ServerApp.scala`)
(apps):
Rename to `instances`.
(register):
Overload to handle clock-driven and regular state machines separately.
(withFreshInstanceId):
New function.
(createInstance):
Simplify by moving functionality to `withFreshInstanceId` and `Wordlist`.
(startClockFor, transition, handleMessage):
Move functionality to `ServerApp.scala`.
* jvm/src/main/scala/cs214/webapp/server/web/WebSocketsCollection.scala:
Delete and merge all functionality into ServerApp.scala.
* jvm/src/main/scala/cs214/webapp/server/web/ServerApp.scala:
(ServerApp):
Rename to `ServerAppFactory`.
Add `instanceId` to `init` signature.
(ServerAppInstance):
Rename to `ServerApp`.
Extend to handle websocket state.
Implement a `shutdown` API to close all websocket connections.
Synchronize every method on a per-instance lock.
(StateMachineServerAppInstance):
Rename to `StateMachineServerApp`.
(Clock, ClockDrivenStateMachineServerApp):
New classes. Move clock threads here and use the new `project` API to send
unserialized Tick events.