How does Play recognize a particular websocket message? - scala

I am looking at the websocket-chat example. It unveils much, but I still cannot get something. I understand how messages are received, processed and sent on the web page side.
However, Play captures websocket messages by means of the receive method of an Akka actor. In the websocket-chat, there are several cases in this method, but I don't get, how does it know which websocket message should be mapped to which case. In fact, I don't understand the path that a websocket message follows upon entering Play's domain, how is it processed and how can different message types/kinds be sent from the webpage.
I have not find any info or sources related to this. Could please someone explain this or point to some kind of a good reference?
UPDATE:
The link to the original example.

The receive method from the sample doesn't have any link to the Play Websocket API. This receive method comes from the Akka library.
The Websockets events are managed through an Iteratee, which create and send a Talk message to the Actor system.
Simply put, it allows to have a highly scalable system (non-blocking), by sending messages between "workers".
So I suggest that you take a look at the Actor model in the Akka library.

Related

Moving from socko to akka-http websockets

I have an existing akka application built on socko websockets. Communication with the sockets takes place inside a single actor and messages both leaving and entering the actor (incoming and outgoing messages, respectively) are labelled with the socket id, which is a first class property of a socko websocket (in socko a connection request arrives labelled with the id, and all the lifecycle transitions such as handshaking, disconnection, incoming frames etc. are similarly labelled)
I'd like to reimplement this single actor using akka-http (socko is more-or-less abandonware these days, for obvious reasons) but it's not straightforward because the two libraries are conceptually very different; akka-http hides the lower level details of the handshaking, disconnection etc, simply sending whichever actor was bound to the http server an UpgradeToWebsocket request header. The header object contains a method that takes a materialized Flow as a handler for all messages exchanged with the client.
So far, so good; I am able to receive messages on the web socket and reply them directly. The official examples all assume some kind of stateless request-reply model, so I'm struggling with understanding how to make the next step to assigning a label to the materialized flow, managing its lifecycle and connection state (I need to inform other actors in the application when a connection is dropped by a client, as well as label the messages.)
The alternative (remodelling the whole application using akka-streams) is far too big a job, so any advice about how to keep track of the sockets would be much appreciated.
To interface with an existing actor-based system, you should look at Source.actorRef and Sink.actorRef. Source.actorRef creates an ActorRef that you can send messages to, and Sink.actorRef allows you to process the incoming messages using an actor and also to detect closing of the websocket.
To connect the actor created by Source.actorRef to the existing long-lived actor, use Flow#mapMaterializedValue. This would also be a good place to assign an unique id for a socket connection.
This answer to a related question might get you started.
One thing to be aware of. The current websocket implementation does not close the server to client flow when the client to server flow is closed using a websocket close message. There is an issue open to implement this, but until it is implemented you have to do this yourself. For example by having something like this in your protocol stack.
The answer from Rüdiger Klaehn was a useful starting point, thanks!
In the end I went with ActorPublisher after reading another question here (Pushing messages via web sockets with akka http).
The key thing is that the Flow is 'materialized' somewhere under the hood of akka-http, so you need to pass into UpgradeToWebSocket.handleMessagesWithSinkSource a Source/Sink pair that already know about an existing actor. So I create an actor (which implements ActorPublisher[TextMessage.Strict]) and then wrap it in Source.fromPublisher(ActorPublisher(myActor)).
When you want to inject a message into the stream from the actor's receive method you first check if totalDemand > 0 (i.e. the stream is willing to accept input) and if so, call onNext with the contents of the message.

Scalatra, Atmosphere, and sending messages to clients from outside the message handler

I'm currently reading through the official Scalatra documentation, particularly the guide on using Scalatra with Atmosphere. That page explains how to use Scalatra and Atmosphere to write a WebSocket based application which responds to incoming messages with outgoing messages.
For the purposes of an application which connects multiple different messaging sources, how would I send outgoing messages from elsewhere in the application?
Possible examples include:
messages sent as a result of an incoming HTTP request
periodic messages on a timer
messages pulled from a queue
etc.
Some of these messages could potentially target multiple clients.
I'm a bit confused by the official docs on this matter because all the examples happen various incoming message handlers and I'm not sure where to get a reference to the Atmosphere system or where/how I'm allowed to call it.
I Hope someone can clarify.

how is it possible to use spray and akka without blocking until result is estimated?

This question is more about architecture than anything else.
I just started building a Rest API with akka. Currently I use play for doing the necessary routing. The problem with play is that I have my entry point for akka within my controller, so there is always one actor that has to wait all the time until my business logic calculates a suitable response.
Now I came across spray and it looks like there is nearly the same problem with it. (spray-routing)
What I`m trying to achieve is that I have an entry point that receives a HTTPRequest, then the request is handled by my actor system and at the end of this system there is an actor which sends the priviously calculated response back to the requesting client.
Actually I cant figure out how to chain actors without waiting for an end result. What I want is a "START" - Actor receiving a Request and one at the end sending back the response.
I hope i wrote it so that someone understands what I mean.
Thanks in advance.

Scalatra, Atmosphere, and Receiving Multiple Messages

I am just playing with Scalatra and Akka like the guide suggests http://www.scalatra.org/guides/async/atmosphere.html. I've modified the guid so that I'm passing an actor system into the Atmosphere client.
However, I would like to know how I can get messages from the actor system back down to the client.
I can't use the ask pattern because the actor system may send multiple messages to the client - not one. What should I do here?
Perhaps you can use The Inbox.

Where should I look for a Scala framework that supports bidirectional asynchronous communication?

I have a single server which can have multiple clients. Each client sends an asynchronous message to the server which immediately routes the message to a third party provider. At some point in the future, the server receives a response from the third party provider which should immediately be routed back to the sending client. I have had a look at Akka but had trouble figuring out how to route messages from the server back to clients at arbitrary points in the future. If I can be given some pointers even to the right parts of documentation I'm happy to take it from there. At the moment I am bewildered by the array of frameworks and options available.
"I have had a look at Akka but had trouble figuring out how to route messages from the server back to clients at arbitrary points in the future."
When a message comes in from a client, store away the reference of the sender, so you can send to it later.
Perhaps if you elaborate on the problem you experienced we can assist?
Cheers,
√
BlueEyes is designed for this kind of workflow.
You could also use atmosphere.
If your clients are browsers, you can use Lift and its comet support. This post gives you one example of doing async work using Lift