Omid
Omid

Reputation: 1989

Sockets and Streaming in Play Framework

I am reading the Play-Socket.io documentation and Play WebSocket documentation on how to use them via Akka Streams.

I cannot understand why it's necessary to use Flow.fromSinkAndSource.

The documentation for Play WebSockets says:

Note that while conceptually, a flow is often viewed as something that receives messages, does some processing to them, and then produces the processed messages - there is no reason why this has to be the case, the input of the flow may be completely disconnected from the output of the flow. Akka streams provides a constructor, Flow.fromSinkAndSource, exactly for this purpose, and often when handling WebSockets, the input and output will not be connected at all.

I don't get this at all, why they should be disconnected at all? Why doesn't a simple Flow make sense here?

Upvotes: 0

Views: 671

Answers (1)

Jeffrey Chung
Jeffrey Chung

Reputation: 19527

I cannot understand why it's necessary to use Flow.fromSinkAndSource....I don't get this at all, why they should be disconnected at all? Why doesn't a simple Flow make sense here?

In Play, a WebSocket message handler is a Flow[In, Out, _] (which is converted to/from a Flow[Message, Message, Any] via a MessageFlowTransformer). If you're using WebSockets in a request-response fashion, then you could use Flow[In].map or something with similar semantics, to implement this handler (the following examples are from the Play documentation):

def socket =  WebSocket.accept[String, String] { request =>

  // log the message to stdout and send response back to client
  Flow[String].map { msg =>
    println(msg)
    "I received your message: " + msg
  } // Flow[String, String, _]
}

In the above example, the input and output are connected: the input is transformed, and the result of that transformation is used as the output.

WebSockets may also be truly bidirectional, meaning that the input and output do not necessarily have to be connected. This is when Flow.fromSinkAndSource comes into play: the Sink and Source that are passed into this method are independent. A trivial example of this is a handler that ignores an incoming connection and simply sends a single message to the socket:

def socket = WebSocket.accept[String, String] { request =>

  // Just ignore the input
  val in = Sink.ignore

  // Send a single 'Hello!' message and close
  val out = Source.single("Hello!")

  Flow.fromSinkAndSource(in, out) // Flow[String, String, _]
}

In the above example, Flow.fromSinkAndSource is used because the input and output are not connected: the input has nothing to do with the output.

Whether you use WebSockets in a request-response or a truly bidirectional manner, both approaches are modeled as a Flow[In, Out, _]. If you're using WebSockets in a truly bidirectional way, then you can use Flow.fromSinkAndSource to implement a Flow[In, Out, _].

Upvotes: 3

Related Questions