SlideShare a Scribd company logo
WebSockets in
Play! Framework
Fabio Tiriticco
@ticofab
Scala Academy
20 March 2014
Amsterdam Scala
Two words about myself
Currently freelancing and working on my own ideas.
…one of which involves and WebSockets!
Bicycle Touring Amsterdam
Agenda
• What are WebSockets?
• WebSocket clients
• Relationship and comparison with HTTP
• Advantages and disadvantages
• WebSocket servers in Play!
• Simple examples & exercises
• Use case
What are WebSockets?
• Full-duplex channel between client and server.
• Persistent connection. Both parties can send data
at any time.
• Very simple API.
• Standardised by the IETF as RFC 6455 in 2011,
which has lead to broader adoption.
The TCP / IP stack
WEBSOCKET
The API, Client-side
RECEPTION CALLBACKS
• onOpen
• onClosed
• onMessage(message)
• onError(error)
CONNECTION
• open
• close
SEND DATA
• send(message)
var myWebSocket = new WebSocket("ws://fabio.com/example");
// define callbacks
myWebSocket.onmessage = function(event) {
console.log("got data: " + event.data);
}
myWebSocket.onopen = function(event) {
console.log("Connection open ...");
};
myWebSocket.onclose = function(event) {
console.log("Connection closed.");
};
myWebSocket.onerror = function(event) {
console.log("Error!");
};
myWebSocket.send("Hello from Javascript!”); // send stuff
myWebSocket.close(); // close connection
JavaScript client example
WebSocketClient mWsClient = new WebSocketClient(URI.create(“ws://fabio.com/example”), new
Listener() {
@Override
public void onMessage(final String message) {
Log.d(TAG, “onMessage: ” + message);
}
@Override
public void onError(final Exception error) {
Log.e(TAG, "Error!", error);
}
@Override
public void onDisconnect(final int code, final String reason) {
Log.d(TAG, String.format("Disconnected! Code: %d Reason: %s", code, reason));
}
@Override
public void onConnect() {
Log.d(TAG, "onConnect");
}
}, mExtraHeaders);
mWsClient.connect();
mWsClient.send(“Hello from Android!”);
mWSClient.disconnect();
Android (Java) client example
Request URL:ws://echo.websocket.org/
Request Method:GET
Status Code:101 Web Socket Protocol Handshake
Connection:Upgrade
Host:echo.websocket.org
Sec-WebSocket-Version:13
Upgrade:websocket
Relationship with HTTP
• A websocket connection is initiated via a
standard HTTP GET request, where the client
asks for an ‘Upgrade’
• The response will be a 101 status, ‘Switching
protocol’
Why WebSockets?
• The ‘native’ web built around HTTP only relies on
client’s action. Only the client can request new content
by for instance opening a new page.
• A way to make things more dynamic is using intense
polling, which is bad for performance and traffic.
• The need to give impression of a ‘dynamic’ web was
solved using workarounds like Long-polling or
Streaming.
• It works but it’s complicated and it doesn’t solve the
big issue of the HTTP overhead!
WS vs HTTP: overhead
HTTP: up to 2000 bytes (2Kb)
WebSocket: 2 bytes
WS vs HTTP: processing time
Downsides of WebSockets
• You need to build your own protocol, even for the
simplest thing! You cannot use any of the friendly
HTTP statuses, body etc. Lower level of abstraction.
• If your application doesn’t require a lot of dynamic
interaction, HTTP is much simpler to implement.
• Regular sockets vs WebSockets: plain TCP is even
faster, but very low level (difficult to access).
A few useful links
• https://tools.ietf.org/html/rfc6455 (official doc)
• http://www.html5rocks.com/en/tutorials/websockets/
basics/ (basic tutorial)
• http://www.websocket.org (the echo server folks)
• http://blog.arungupta.me/2014/02/rest-vs-websocket-
comparison-benchmarks/ (HTTP vs WebSocket
comparison)
• http://eng.42go.com/websockets-vs-regular-sockets/
WebSockets in Play!
Similar signature to a regular HTTP Action:
val echo = Action { request =>
Ok("Got request [" + request + "]")
}
def index = WebSocket.using[String] { request =>
val in = Iteratee.foreach[String](chunk => println(chunk))
val out = Enumerator("Hello!")
(in, out)
}
using[A](f: (RequestHeader) (Iteratee[A, _], Enumerator[A]))
WebSocket.using signature:
WebSockets in Play!
There is also an ‘async’ version which combines the
two channels asynchronously and returns a Future.
def index = WebSocket.async[String] { request =>
Future {
val in = Iteratee.foreach[String](chunk => println(chunk))
val out = Enumerator("Hello!")
(in, out)
}
}
async[A](f: (RequestHeader) Future[(Iteratee[A, _], Enumerator[A])])
WebSocket.async signature:
Iteratees and Enumerators
• Complex functional abstractions. Very powerful but
difficult to grasp.
• In the WebSocket domain, all you need to know is that
they represent the two channels where data flows
between client and server.
Iteratees & Enumerators
How To
• They both take a type:
• Play! Framework provides various utilities to create
them and use them together.
• Time for some concrete examples!
trait Iteratee[E, +A] extends AnyRef
trait Enumerator[E] extends AnyRef
Repositories
(ask Google for “ticofab github” or something like that)
• https://github.com/ticofab/simple-websocket-client
(test client)
• https://github.com/ticofab/simple-play-websocket-
server (test server)
WebSockets in Play!
Even though you can wrap the pair (Iteratee, Enumerator) into
an Actor, the framework also offers a way to manage a
WebSocket using actors out of the box. The signature of the
accept function is unusual: a function that returns a function
which takes an ActorRef and returns the Props of an actor!
acceptWithActor[A, B](f: (RequestHeader) (ActorRef) Props)
There is also a way to reject a Websocket connection:
tryAcceptWithActor[A, B](f: (RequestHeader) Future[Either[Result,
(ActorRef) Props]])
Return Left to reject or Right(WebsocketActor.Props) to accept.
def index = WebSocket.acceptWithActor[String, String] { request => out =>
WebsocketActor.props(out)
}
object MyWebSocketActor {
def props(out: ActorRef) = Props(new WebsocketActor(out))
}
class WebsocketActor(out: ActorRef) extends Actor {
def receive = {
case msg: String =>
out ! ("I received your message: " + msg)
}
}
WebSockets in Play!
Little exercise
1. Uses Actors to handle connections wrapping Iteratee and
Enumerators.
2. It echoes anything it receives, but closes the connection if it
receives a specific string of your choice.
3. Bonus: make the endpoint proxy the result of the API call to:
Create a new Play! app with a WebSocket endpoint.
http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl
Two good articles
• Iteratees and Enumerators for human beings: http://
mandubian.com/2012/08/27/understanding-play2-
iteratees-for-normal-humans/
• WebSocket examples: http://blog.tksfz.org/
2012/10/12/websockets-echo-using-play-scala-
and-actors-part-i/
Use case
Play! Framework sample:
WebSocket chat
Thank you
Websocket in Play!Framework
@ticofab

More Related Content

WebSockets wiith Scala and Play! Framework

  • 1. WebSockets in Play! Framework Fabio Tiriticco @ticofab Scala Academy 20 March 2014 Amsterdam Scala
  • 2. Two words about myself Currently freelancing and working on my own ideas. …one of which involves and WebSockets! Bicycle Touring Amsterdam
  • 3. Agenda • What are WebSockets? • WebSocket clients • Relationship and comparison with HTTP • Advantages and disadvantages • WebSocket servers in Play! • Simple examples & exercises • Use case
  • 4. What are WebSockets? • Full-duplex channel between client and server. • Persistent connection. Both parties can send data at any time. • Very simple API. • Standardised by the IETF as RFC 6455 in 2011, which has lead to broader adoption.
  • 5. The TCP / IP stack WEBSOCKET
  • 6. The API, Client-side RECEPTION CALLBACKS • onOpen • onClosed • onMessage(message) • onError(error) CONNECTION • open • close SEND DATA • send(message)
  • 7. var myWebSocket = new WebSocket("ws://fabio.com/example"); // define callbacks myWebSocket.onmessage = function(event) { console.log("got data: " + event.data); } myWebSocket.onopen = function(event) { console.log("Connection open ..."); }; myWebSocket.onclose = function(event) { console.log("Connection closed."); }; myWebSocket.onerror = function(event) { console.log("Error!"); }; myWebSocket.send("Hello from Javascript!”); // send stuff myWebSocket.close(); // close connection JavaScript client example
  • 8. WebSocketClient mWsClient = new WebSocketClient(URI.create(“ws://fabio.com/example”), new Listener() { @Override public void onMessage(final String message) { Log.d(TAG, “onMessage: ” + message); } @Override public void onError(final Exception error) { Log.e(TAG, "Error!", error); } @Override public void onDisconnect(final int code, final String reason) { Log.d(TAG, String.format("Disconnected! Code: %d Reason: %s", code, reason)); } @Override public void onConnect() { Log.d(TAG, "onConnect"); } }, mExtraHeaders); mWsClient.connect(); mWsClient.send(“Hello from Android!”); mWSClient.disconnect(); Android (Java) client example
  • 9. Request URL:ws://echo.websocket.org/ Request Method:GET Status Code:101 Web Socket Protocol Handshake Connection:Upgrade Host:echo.websocket.org Sec-WebSocket-Version:13 Upgrade:websocket Relationship with HTTP • A websocket connection is initiated via a standard HTTP GET request, where the client asks for an ‘Upgrade’ • The response will be a 101 status, ‘Switching protocol’
  • 10. Why WebSockets? • The ‘native’ web built around HTTP only relies on client’s action. Only the client can request new content by for instance opening a new page. • A way to make things more dynamic is using intense polling, which is bad for performance and traffic. • The need to give impression of a ‘dynamic’ web was solved using workarounds like Long-polling or Streaming. • It works but it’s complicated and it doesn’t solve the big issue of the HTTP overhead!
  • 11. WS vs HTTP: overhead HTTP: up to 2000 bytes (2Kb) WebSocket: 2 bytes
  • 12. WS vs HTTP: processing time
  • 13. Downsides of WebSockets • You need to build your own protocol, even for the simplest thing! You cannot use any of the friendly HTTP statuses, body etc. Lower level of abstraction. • If your application doesn’t require a lot of dynamic interaction, HTTP is much simpler to implement. • Regular sockets vs WebSockets: plain TCP is even faster, but very low level (difficult to access).
  • 14. A few useful links • https://tools.ietf.org/html/rfc6455 (official doc) • http://www.html5rocks.com/en/tutorials/websockets/ basics/ (basic tutorial) • http://www.websocket.org (the echo server folks) • http://blog.arungupta.me/2014/02/rest-vs-websocket- comparison-benchmarks/ (HTTP vs WebSocket comparison) • http://eng.42go.com/websockets-vs-regular-sockets/
  • 15. WebSockets in Play! Similar signature to a regular HTTP Action: val echo = Action { request => Ok("Got request [" + request + "]") } def index = WebSocket.using[String] { request => val in = Iteratee.foreach[String](chunk => println(chunk)) val out = Enumerator("Hello!") (in, out) } using[A](f: (RequestHeader) (Iteratee[A, _], Enumerator[A])) WebSocket.using signature:
  • 16. WebSockets in Play! There is also an ‘async’ version which combines the two channels asynchronously and returns a Future. def index = WebSocket.async[String] { request => Future { val in = Iteratee.foreach[String](chunk => println(chunk)) val out = Enumerator("Hello!") (in, out) } } async[A](f: (RequestHeader) Future[(Iteratee[A, _], Enumerator[A])]) WebSocket.async signature:
  • 17. Iteratees and Enumerators • Complex functional abstractions. Very powerful but difficult to grasp. • In the WebSocket domain, all you need to know is that they represent the two channels where data flows between client and server.
  • 18. Iteratees & Enumerators How To • They both take a type: • Play! Framework provides various utilities to create them and use them together. • Time for some concrete examples! trait Iteratee[E, +A] extends AnyRef trait Enumerator[E] extends AnyRef
  • 19. Repositories (ask Google for “ticofab github” or something like that) • https://github.com/ticofab/simple-websocket-client (test client) • https://github.com/ticofab/simple-play-websocket- server (test server)
  • 20. WebSockets in Play! Even though you can wrap the pair (Iteratee, Enumerator) into an Actor, the framework also offers a way to manage a WebSocket using actors out of the box. The signature of the accept function is unusual: a function that returns a function which takes an ActorRef and returns the Props of an actor! acceptWithActor[A, B](f: (RequestHeader) (ActorRef) Props) There is also a way to reject a Websocket connection: tryAcceptWithActor[A, B](f: (RequestHeader) Future[Either[Result, (ActorRef) Props]]) Return Left to reject or Right(WebsocketActor.Props) to accept.
  • 21. def index = WebSocket.acceptWithActor[String, String] { request => out => WebsocketActor.props(out) } object MyWebSocketActor { def props(out: ActorRef) = Props(new WebsocketActor(out)) } class WebsocketActor(out: ActorRef) extends Actor { def receive = { case msg: String => out ! ("I received your message: " + msg) } } WebSockets in Play!
  • 22. Little exercise 1. Uses Actors to handle connections wrapping Iteratee and Enumerators. 2. It echoes anything it receives, but closes the connection if it receives a specific string of your choice. 3. Bonus: make the endpoint proxy the result of the API call to: Create a new Play! app with a WebSocket endpoint. http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl
  • 23. Two good articles • Iteratees and Enumerators for human beings: http:// mandubian.com/2012/08/27/understanding-play2- iteratees-for-normal-humans/ • WebSocket examples: http://blog.tksfz.org/ 2012/10/12/websockets-echo-using-play-scala- and-actors-part-i/
  • 24. Use case Play! Framework sample: WebSocket chat
  • 25. Thank you Websocket in Play!Framework @ticofab