The code & sample apps can be found on Github here
- create any group of connected entities (people or not) (chatroom, forum, broadcast pivot…).
- manage connections, disconnections, broadcast, targetted message through actor and nothing else.
- websocket endpoints through actors without taking care of Iteratees/Enumerators…
- Bots to simulate members
Reminders on websockets in Play
Here is the function Play provides to create a websocket:
1 2 3 |
|
A websocket is a persistent bi-directional channel of communication (in/out) and is created with:
- an
Iteratee[A, _]
to manage all frames received by the websocket endpoint - an
Enumerator[A]
to send messages through the websocket - an implicit
FrameFormatter[A]
to parse frame content to typeA
(Play provides default FrameFormatter for String or JsValue)
Here is how you traditionally create a websocket endpoint in Play:
1 2 3 4 5 6 7 8 9 10 |
|
Generally, the Enumerator[A]
is created using Concurrent.broadcast[A]
and Concurrent.unicast[A]
which are very powerful tools but not so easy to understand exactly (the edge-cases of connection close, errors are always tricky).
You often want to:
- manage multiple client connections at the same time
- parse messages received from websockets,
- do something with the message payload
- send messages to a given client
- broadcast messages to all connected members
- create bots to be able to simulate fake connected members
- etc…
To do that in Play non-blocking/async architecture, you often end developing an Actor topology managing all events/messages on top of the previous Iteratee/Enumerator
.
The Iteratee/Enumerator
is quite generic but always not so easy to write.
The actor topology is quite generic because there are administration messages that are almost always the same:
- Connection/Forbidden/Disconnection
- Broadcast/Send
Actor Room is a helper managing all of this for you. So you can just focus on message management using actors and nothing else. It provides all default behaviors and all behaviors can be overriden if needed. It exposes only actors and nothing else.
The code is based on the chatroom sample (and a cool sample by Julien Tournay) from Play Framework pushed far further and in a more generic way.
What is Actor Room?
An actor room manages a group of connected members which are supervised by a supervisor
Member = 2 actors (receiver/sender)
Each member is represented by 2 actors (1 receiver & 1 sender):
You MUST create at least a Receiver Actor because it’s your job to manage your own message format
The Sender Actor has a default implementation but you can override it.
Supervisor = 1 actor
All actors are managed by 1 supervisor which have two roles:
Creates/supervises all receiver/sender actors
Manages administration messages (routing, forwarding, broadcasting etc…)
Code sample step by step
Create the Actor Room
1 2 3 4 5 6 |
|
The room creates the Supervisor actor for you and delegates the creation of receiver/sender actors to it.
If you want to broadcast a message or target a precise member, you should use the supervisor.
1 2 |
|
You can manage several rooms in the same project.
Create the mandatory Receiver Actor
There is only one message to manage:
1 2 3 4 5 |
|
If your websocket frames contain Json, then it should be Received[JsValue]
.
You just have to create a simple actor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Please note the Receiver Actor is supervised by the Supervisor
actor. So, within the Receiver Actor, context.parent
is the Supervisor
and you can use it to send/broadcast message as following:
1 2 3 4 5 6 7 8 9 |
|
Create your Json websocket endpoint
Please note that each member is identified by a string that you define yourself.
import org.mandubian.actorroom._
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
All together
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Extend default behaviors
Override the administration message format
AdminMsgFormatter
typeclass is used by ActorRoom to format administration messages (Connected, Disconnected and Error) by default.
AdminMsgFormatter[JsValue]
and AdminMsgFormatter[String]
are provided by default.
You can override the format as following:
1 2 3 4 5 6 7 8 9 |
|
Override the Sender Actor
You just have to create a new actor as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Then you must initialize your websocket with it
1
|
|
You can override the following messages:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Override the Supervisor Actor
Please note Supervisor
is an actor which manages a internal state containing all members:
1
|
|
You can override the default Supervisor as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Create a bot to simulate member
A bot is a fake member that you can use to communicate with other members. It’s identified by an ID as any member.
You create a bot with these API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Then with returned Member
, you can simulate messages:
1 2 3 4 5 6 |
|
Naturally, you can override the Bot Sender Actor
1 2 3 4 5 6 7 8 9 10 11 12 |
|
So what else??? Everything you can override and everything that I didn’t implement yet…
On github project, you will find 2 samples:
simplest
which is a very simple working sample.websocket-chat
which is just the Play Framework ChatRoom sample rewritten withActorRoom
.
Have fun!