25
WebSockets in Play! Framework Fabio Tiriticco @ticofab Scala Academy 20 March 2014 Amsterdam Scala

WebSockets wiith Scala and Play! Framework

Embed Size (px)

DESCRIPTION

A WebSockets HOW-TO using Scala and Play!Framework. Links to example repositories and other resources. Created for the AmsterdamScala meetup.

Citation preview

Page 1: WebSockets wiith Scala and Play! Framework

WebSockets in Play! Framework

Fabio Tiriticco @ticofab

Scala Academy 20 March 2014

Amsterdam Scala

Page 2: WebSockets wiith Scala and Play! Framework

Two words about myself

Currently freelancing and working on my own ideas.

…one of which involves and WebSockets!

Bicycle Touring Amsterdam

Page 3: WebSockets wiith Scala and Play! Framework

Agenda• What are WebSockets? • WebSocket clients • Relationship and comparison with HTTP • Advantages and disadvantages • WebSocket servers in Play! • Simple examples & exercises • Use case

Page 4: WebSockets wiith Scala and Play! Framework

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.

Page 5: WebSockets wiith Scala and Play! Framework

The TCP / IP stack

WEBSOCKET

Page 6: WebSockets wiith Scala and Play! Framework

The API, Client-sideRECEPTION CALLBACKS

• onOpen

• onClosed

• onMessage(message)

• onError(error)

CONNECTION

• open

• close

SEND DATA

• send(message)

Page 7: WebSockets wiith Scala and Play! Framework

var myWebSocket = new WebSocket("ws://fabio.com/example");

// define callbacksmyWebSocket.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

Page 8: WebSockets wiith Scala and Play! Framework

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

Page 9: WebSockets wiith Scala and Play! Framework

Request URL:ws://echo.websocket.org/Request Method:GETStatus Code:101 Web Socket Protocol HandshakeConnection:UpgradeHost:echo.websocket.orgSec-WebSocket-Version:13Upgrade: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’

Page 10: WebSockets wiith Scala and Play! Framework

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!

Page 11: WebSockets wiith Scala and Play! Framework

WS vs HTTP: overheadHTTP: up to 2000 bytes (2Kb)

WebSocket: 2 bytes

Page 12: WebSockets wiith Scala and Play! Framework

WS vs HTTP: processing time

Page 13: WebSockets wiith Scala and Play! Framework

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).

Page 14: WebSockets wiith Scala and Play! Framework

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/

Page 15: WebSockets wiith Scala and Play! Framework

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:

Page 16: WebSockets wiith Scala and Play! Framework

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:

Page 17: WebSockets wiith Scala and Play! Framework

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.

Page 18: WebSockets wiith Scala and Play! Framework

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

Page 19: WebSockets wiith Scala and Play! Framework

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)

Page 20: WebSockets wiith Scala and Play! Framework

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.

Page 21: WebSockets wiith Scala and Play! Framework

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!

Page 22: WebSockets wiith Scala and Play! Framework

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

Page 23: WebSockets wiith Scala and Play! Framework

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/

Page 24: WebSockets wiith Scala and Play! Framework

Use casePlay! Framework sample:

WebSocket chat

Page 25: WebSockets wiith Scala and Play! Framework

Thank you

Websocket in Play!Framework

@ticofab