diff options
author | Jakob Odersky <jakob@odersky.com> | 2016-11-13 17:14:43 -0800 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2016-11-13 17:14:43 -0800 |
commit | 7efed1380f6a6cfc8d0b95015f1fa167b4a7bc23 (patch) | |
tree | 8a9f81a0f89a029811f1645b9f2e74f5b3b54d94 /server | |
parent | e317debf1a5d639c9a5fde0f0353a7b3b7ae86a0 (diff) | |
download | play-scalajs-chat-7efed1380f6a6cfc8d0b95015f1fa167b4a7bc23.tar.gz play-scalajs-chat-7efed1380f6a6cfc8d0b95015f1fa167b4a7bc23.tar.bz2 play-scalajs-chat-7efed1380f6a6cfc8d0b95015f1fa167b4a7bc23.zip |
Implement chat room backend
Diffstat (limited to 'server')
-rw-r--r-- | server/app/controllers/HomeController.scala | 23 | ||||
-rw-r--r-- | server/app/controllers/actors.scala | 56 | ||||
-rw-r--r-- | server/app/views/index.scala.html | 6 | ||||
-rw-r--r-- | server/conf/routes | 2 |
4 files changed, 80 insertions, 7 deletions
diff --git a/server/app/controllers/HomeController.scala b/server/app/controllers/HomeController.scala index 13bc8dc..4d48c98 100644 --- a/server/app/controllers/HomeController.scala +++ b/server/app/controllers/HomeController.scala @@ -1,14 +1,24 @@ package controllers -import play.api._ +import akka.actor.{ActorRef, ActorSystem, Props} +import akka.stream.Materializer +import chat._ +import javax.inject._ +import play.api.libs.streams.ActorFlow import play.api.mvc._ +import play.api.mvc.WebSocket.MessageFlowTransformer import upickle.default._ /** * This controller creates an `Action` to handle HTTP requests to the * application's home page. */ -class HomeController extends Controller { +class HomeController @Inject() ( + implicit system: ActorSystem, + mat: Materializer +) extends Controller { + + lazy val room: ActorRef = system.actorOf(Props(classOf[RoomActor])) /** * Create an Action to render an HTML page. @@ -21,8 +31,13 @@ class HomeController extends Controller { Ok(views.html.index()) } - def message = Action { implicit request => - Ok(write(chat.Message("hello"))) + def socket(uid: String) = WebSocket.accept[Command, Event] { request => + ActorFlow.actorRef(out => Props(classOf[ClientActor], uid, room, out)) } + implicit val transformer = MessageFlowTransformer.stringMessageFlowTransformer.map( + in => read[Command](in), + (out: Event) => write(out) + ) + } diff --git a/server/app/controllers/actors.scala b/server/app/controllers/actors.scala new file mode 100644 index 0000000..f10f925 --- /dev/null +++ b/server/app/controllers/actors.scala @@ -0,0 +1,56 @@ +package controllers + +import akka.actor.{ Actor, ActorRef, Terminated } +import chat._ +import scala.collection.mutable.HashMap + + +/** An actor instantiated for every websocket connection. It represents a + * chat client and registers with a chat room. + * @param uid user id of the connecting client + * @param room chat room actor that this client will join + * @param socket websocket actor, any message sent to it will get transferred to the remote + * browser + */ +class ClientActor(uid: String, room: ActorRef, socket: ActorRef) extends Actor { + + override def preStart() = { + room ! (self, uid) + } + + def receive = { + case cmd: Command => room ! cmd + case ev: Event => socket ! ev + } + +} + +/** An actor that represents a chat room. + * Handles commands and events subclassing `chat.Command` and `chat.Event` + */ +class RoomActor extends Actor { + val clients = new HashMap[ActorRef, String] + + override def receive = { + + case (client: ActorRef, uid: String) => + context.watch(sender) + clients += client -> uid + for ( (client, _) <- clients ) { + client ! Joined(uid) + } + + case Terminated(client) => + clients -= client + for ( (cl, _) <- clients ) { + cl ! Left(clients(client)) + } + + case Broadcast(content) => + val origin = clients(sender) + for ( (client, _) <- clients ) { + client ! Message(origin, content) + } + } +} + diff --git a/server/app/views/index.scala.html b/server/app/views/index.scala.html index 911bdaf..4b71c59 100644 --- a/server/app/views/index.scala.html +++ b/server/app/views/index.scala.html @@ -1,7 +1,9 @@ @() -@main("Welcome to Play") { - <main id="root">placeholder</main> +@main("Welcome to Chat") { + <main id="root"> + hello + </main> <script src="@routes.Assets.versioned("client-fastopt.js")" type="text/javascript"></script> <script type="text/javascript"> chat.Main().main() diff --git a/server/conf/routes b/server/conf/routes index ca64d25..ab400c7 100644 --- a/server/conf/routes +++ b/server/conf/routes @@ -5,7 +5,7 @@ # An example controller showing a sample home page GET / controllers.HomeController.index -GET /message controllers.HomeController.message +GET /socket/:uid controllers.HomeController.socket(uid) # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) |