diff --git a/app/controllers/ExamplesController.scala b/app/controllers/ExamplesController.scala index 4f039c7ba173f034c614aa0610145bb6e7ace7eb..73a04e21e3d23d38952c19a28b0fab70302f62fc 100644 --- a/app/controllers/ExamplesController.scala +++ b/app/controllers/ExamplesController.scala @@ -87,7 +87,7 @@ class ExamplesController @Inject()(cc: ControllerComponents)(implicit ec: Execut * * @return */ - def websocketWithHelper():WebSocket = { + def webSocketWithHelper():WebSocket = { WebSocketHelper.createWebSocket[String, String]( { queue => // We now have an asynchronous queue. What would we like to do with it @@ -109,39 +109,44 @@ class ExamplesController @Inject()(cc: ControllerComponents)(implicit ec: Execut * asynchronous work. However, using this template, you should just * @return */ - def websocket() = WebSocket.accept[String, String] { request => - - // Our source is going to be an asynchronous queue we can push messages to with 'out.offer(msg)'. This is going to - // be the "source" of our flow. A complication is it doesn't create the queue immediately - this just says - // *when* this source is connected to a flow, create a queue. So we don't have a queue yet. - val outSource = Source.queue[String](50, OverflowStrategy.backpressure) + def webSocket() = WebSocket.accept[String, String] { request => // Because I want to refer to the queue in the sink, but I haven't actually got the queue yet, I'm just creating // a box to put our queue in. At the moment, it's empty var outOpt:Option[SourceQueueWithComplete[String]] = None - // Create a "sink" that describes what we want to do with each message. Here, I'm just going to count the characters - // and echo it straight back out on the "out" queue. - val in = Sink.foreach[String] { message => + // A websocket is made from a "flow" - a source of messages up to the browser, and a sink for messages from the browser. + // We're going to need to give this function our Sink and our Source as arguments. + Flow.fromSinkAndSourceCoupledMat( - // If we have an out queue, send the message on it - outOpt foreach { out => - out.offer(s"That message had ${message.length} characters in it") - } + // Create a "sink" that describes what we want to do with each message. Here, I'm just going to count the characters + // and echo it straight back out on the "out" queue. + Sink.foreach[String] { message => - } + // If we have an out queue, send the message on it + outOpt foreach { out => + out.offer(s"That message had ${message.length} characters in it") + } + + }, - // This defines a "flow" -- something that has an input and an output. - // "Coupled" means that if the input closes, the output will close - // "Mat" means "materialised" -- ie, it'll give us the output queue that gets created and the Future that will - // complete when the flow is done. - Flow.fromSinkAndSourceCoupledMat(in, outSource) { case (done, out) => + // Our source is going to be an asynchronous queue we can push messages to with 'out.offer(msg)'. + // The queue will be created when the connection is complete - this just says what it *will* be + Source.queue[String](50, OverflowStrategy.backpressure) - // done is a future that will complete when the flow finishes + ) { case (done, queue) => + + // the second argument list is a callback that takes a tuple with two arguments. + // done is a future (like a JavaScript promise) that will complete when the flow finishes // out is our "materialised" output queue. All we need do is put it in the box we made earlier - out.offer("Connected!") - outOpt = Some(out) + // Send a connected message to the browser + queue.offer("Connected!") + + // Put the queue in the box we defined earlier + outOpt = Some(queue) + + // When the connection has ended, empty the box and println that it's closed done.foreach { _ => outOpt = None println("Connection closed!") @@ -149,6 +154,7 @@ class ExamplesController @Inject()(cc: ControllerComponents)(implicit ec: Execut } + } /** diff --git a/conf/routes b/conf/routes index 192f1c932436663968f6cb58f87a03b2cfe9297c..5af64d0474eb3c7f05310aeb2219020c8ebc25b4 100644 --- a/conf/routes +++ b/conf/routes @@ -11,8 +11,8 @@ POST /example/json controllers.ExamplesController.receiveJsonPo GET /example/game controllers.ExamplesController.game(id:Option[String]) -GET /example/socket controllers.ExamplesController.websocket() -GET /example/time controllers.ExamplesController.websocketWithHelper() +GET /example/socket controllers.ExamplesController.webSocket() +GET /example/time controllers.ExamplesController.webSocketWithHelper() GET /example/eventsource controllers.ExamplesController.eventSource()