From d3dabc94ad162289342c2adb8ae863b1260f8b77 Mon Sep 17 00:00:00 2001 From: Will Billingsley <wbilling@une.edu.au> Date: Mon, 17 Sep 2018 20:21:54 +1000 Subject: [PATCH] Made one of the websocket examples more idiomatic --- app/controllers/ExamplesController.scala | 52 +++++++++++++----------- conf/routes | 4 +- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/app/controllers/ExamplesController.scala b/app/controllers/ExamplesController.scala index 4f039c7..73a04e2 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 192f1c9..5af64d0 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() -- GitLab