Implementing a WebSocketClient in Scala controller - scala

I have a scala controller in which I am calling an external webservice using WS api of Play! framework which returns a json. The same api is now to be called using a WebSocketClient as every connection should be made using a WebSocket instead of http. So normal Action in controller are converted to WebSocket functions, however I am not being able to call a WebSocket function from within the scala code. I have searched and gone through several places on web for the solution, but I didn't found the solution anywhere. How can this be done, calling a WebSocket function and fetch its json using a WebSocketClient in scala code OR we can say, consuming a WebSocket from within scala code ? I found a similar to mine questio on SO but none has given an answer to that! I want to know whether its possible or not in Play framework ?
Consume a WebSocket connection using Scala and Play
Edit: I am implementing the following code:
val c = new AsyncHttpClient()
val webSocketClient = c.prepareGet("ws://0.0.0.0:9000/testSocket").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener {
override def onMessage(s: String): Unit = {
}
override def onOpen(webSocket: websocket.WebSocket): Unit = {
webSocket.sendTextMessage("test")
}
override def onFragment(s: String, b: Boolean): Unit = {}
override def onError(throwable: Throwable): Unit = {}
override def onClose(webSocket: websocket.WebSocket): Unit = {
latch.countDown()
}
}).build()).get()
val result = webSocketClient.sendTextMessage("true")
println("================================" + result)
The result variable is not printed on console giving a json parser exception.
Update: My WebSocket connection in ws://0.0.0.0:9000/testSocket which is inside a scala controller of different project, is as under:
def sockeTest = WebSocket.tryAccept[JsValue] { request =>
futureJsonVariable.map { json =>
val in = Iteratee.ignore[JsValue]
// Some database computation here which generated a Future[JsValue] value in futureJsonVariable variable.
val out = Enumerator(json).andThen(Enumerator.eof)
Right((in, out))
} recover {
case err => Left(InternalServerError(err.getMessage))
}
}
Update2: One last thing I would like to ask regarding this is that, we invoke a WebSocket connection using webSocket.sendMessage("test".getBytes()) which gives us the response of WebSocket in the overridden method onMessage(). I want to know, how can we await until a WebSocket response is being received, so that we can perform the required computations with the WebSocket response data. I have checked by returning a Future[JsValue] variable inside the onMessage() method but that thing is something invalid. So how can we put webSocket.sendMessage("test".getBytes()) in await mode, so that further code is executed upon the response of WebSocket ?

Play doesn't support WebSocket client connections. The best option is probably to use AsyncHttpClient, this is the library that Play's WS API is built on so it will already be on your classpath, instructions for accessing WebSockets using it are here:
https://github.com/AsyncHttpClient/async-http-client

Related

Trying to do Scala WS calls in a given ExecutionContext

I have a project which does HTTP calls to two seperate API's. The calls to both of these API's need to be rate limited separately. I started with the calls to one of the API's and I'm trying to use a custom ExecutionContext to achieve this. Here's my application.conf:
play.modules.enabled += "playtest.PlayTestModule"
my-context {
fork-join-executor {
parallelism-min = 10
parallelism-max = 10
}
}
This is the scala class I'm using to test if it works:
#Singleton
class MyWsClient #Inject() (client: WSClient, akkaSystem: ActorSystem) {
val myExecutionContext: ExecutionContext = akkaSystem.dispatchers.lookup("my-context")
val i = new AtomicInteger(0)
def doThing: Future[Int] = {
Future {
println(i.incrementAndGet)
println("Awaiting")
Await.result(client.url("http://localhost:9000/test").get, Duration.Inf)
println("Done")
i.decrementAndGet
1
}(myExecutionContext)
}
}
However, no matter what I try, the number of parallel calls exceeds the limits I set in the application.conf. But it gets even stranger, because if I replace the line
Await.result(client.url("http://localhost:9000/test").get, Duration.Inf)
with
Thread.sleep(1000)
the limits ARE respected and the rate is properly limited.
What am I doing wrong and how can I fix it? If there is another way of rate limiting with the scala-ws library I would love to hear it.
I understand you want to keep using scala-ws ok, but what about something not relying on using specific ExecutionContext?
If you agree with that here's an idea... You create a RateLimitedWSClient component, which you will inject into your controllers instead of WSClient. This component should be a singleton, and support a single method def rateLimit[R](rateLimitClass: String)(request: WSClient => Future[R]). The rateLimitClass is meant to specify which ratelimit to apply to the current request, as you said you need to rate-limit requests to different API differently. The request function should be obvious.
Now my suggestion for the implementation is to use a simple akka-stream that will pipe your requests through the actual WSClient while rate-limiting using the throttle flow-stage (https://doc.akka.io/docs/akka/current/scala/stream/stages-overview.html#throttle):
val client: WSClient = ??? // injected into the component
// component initialization, for example create one flow per API
val queue =
Source
.queue[(Promise[_], WSClient => Future[_])](...) // keep this materialized value
.throttle(...)
.map { (promise, request) =>
promise.completeWith(request(client))
}
.to(Sink.ignore)
.run() // You have to get the materialized queue out of here!
def rateLimit[R](rateLimitClass: String)(request: WSClient => Future[R]): Future[R] = {
val result = Promise.empty[R]
// select which queue to use based on rateLimitClass
if (rateLimitClass == "API1")
queue.offer(result -> request)
else ???
result.future
}
The above is only rough code, I hope you get the idea. You can of course choose something else that a queue, or if you keep the queue, you have to decide how to handle overflows...

Calling asynchronous/Future code from synchronous code in Finagle

I'm working on a Finagle HTTP application where services were implemented without taking advantage of Futures and accessing Redis via a third-party lib. Such services have the following form:
class SampleOldService extends Service[Request, Response] {
def apply(req: Request): Future[Response] = {
val value: Int = getValueFromRedis()
val response: Response = buildResponse(value)
Future.value(response)
}
}
(They are much more complex than this -- the point here is that they are synchronous.)
At some point we began developing new services with Futures and also using the Finagle Redis API. Redis calls are encapsulated in a Store class. New services have the following form:
class SampleNewService extends Service[Request, Response] {
def apply(req: Request): Future[Response] = {
val value: Future[Int] = Store.getValue()
val response: Future[Response] = value map buildResponse
response
}
}
(They are much more complex than this -- the point here is that they are asynchronous.)
We began refactoring the old services to also take advantage of asynchronicity and Futures. We want to do this incrementally, without having to fully re-implement them at once.
The first step was to try to use the new Store class, with code like this:
class SampleOldService extends Service[Request, Response] {
def apply(req: Request): Future[Response] = {
val valueFuture: Future[Int] = Store.getValue()
val value: Int = Await.result(valueFuture)
val response: Response = buildResponse(value)
Future.value(response)
}
}
However, it proved to be catastrophic, because on heavy loads the requests to the old services are stuck at the Await.result() call. The new asynchronous services show no issue.
The problem seems to be related to exhaustion of thread and/or future pools. We have found several solutions on how to do synchronous calls (which perform I/O) from asynchronous calls by using custom pools (such as FuturePool), but not the other way round, which is our case.
So, what is the recommended way of calling asynchronous code (which perform I/O) from synchronous code in Finagle?
The easiest thing you can do is wrap your synchronous calls with a Thread Pool that return a Future. Twitter's util-core provides the FuturePool utility to achieve exactly that.
Something like that (untested code):
import com.twitter.util.FuturePool
val future = FuturePool.unboundedPool {
val result = myBlockingCall.await()
result
}
You can use FuturePool which are futures that run on top of a cached threadpool, but why do that when you can, have the service return a promise and set the value of the promise when you complete the future from the store class.
val p: Promise[Response] = Promise[Response]()
val value: Future[Int] = Store.getValue()
value onSuccess {x =>
val result: Response = buildResponse(x)
p.setValue(result)
}
p

Akka IO and TestActorRef

If I need to write an integration test involving HTTP request via spray-can, how can I make sure that spray-can is using CallingThreadDispatcher?
Currently the following actor will print None
class Processor extends Actor {
override def receive = {
case Msg(n) =>
val response = (IO(Http) ? HttpRequest(GET, Uri("http://www.google.com"))).mapTo[HttpResponse]
println(response.value)
}
}
How can I make sure that the request is being performed on the same thread as the test (resulting in a synchronous request)?
It seems like strange way to do integration internal-testing as you don't mock the "Google", so is more like integration external-testing and synchronous TestActorRef doesn't much fit here. The requirement to control threads inside spray is also pretty tricky. However, if you really need that for http-request - it's possible. In general case, you have to setup several dispatchers in your application.conf:
"manager-dispatcher" (from Http.scala) to dispatch your IO(Http) ? req
"host-connector-dispatcher" to use it by HttpHostConnector(or ProxyHttpHostConnector) which actually dispatch your request
"settings-group-dispatcher" for Http.Connect
They all are decribed in Configuration Section of spray documentation. And they all are pointing to "akka.actor.default-dispatcher" (see Dispatchers), so you can change all of them by changing this one.
The problem here is that calling thread is not guaranteed to be your thread actually, so it will NOT help much with your tests. Just imagine if some of actors registers some handler, responding to your message:
//somewhere in spray...
case r#Request => registerHandler(() => {
...
sender ! response
})
The response may be sent from another thread, so response.value may still be None in current. Actually, the response will be sent from the listening thread of underlying socket library, indepently from your test's thread. Simply saying, request may be sent in one (your) thread, but the response is received in another.
If you really really need to block here, I would recommend you to move such code samples (like IO(Http) ? HttpRequest) out and mock them in any convinient way inside your tests. Smtng like that:
trait AskGoogle {
def okeyGoogle = IO(Http) ? HttpRequest(GET, Uri("http://www.google.com"))).mapTo[HttpResponse]
}
trait AskGoogleMock extends AskGoogle {
def okeyGoogle = Await.result(super.okeyGoogle, timeout)
}
class Processor extends Actor with AskGoogle {
override def receive = {
case Msg(n) =>
val response = okeyGoogle
println(response.value)
}
}
val realActor = system.actorOf(Props[Processor])
val mockedActor = TestActorRef[Processor with AskGoogleMock]
By the way, you can mock IO(HTTP) with another TestActorRef to the custom actor, which will do the outside requests for you - it should require minimal code changes if you have a big project.

How Can I Return Protocol Buffers Directly in Play! 2.0 Framework?

Play lets you return a number of different types directly in your controllers, such as JsValue or XML along with plain text. I would like to extend this to accept protocol buffers, so I can write:
def page = Action {
val protobuf = //...
Ok(protobuf)
}
Protocol buffers in Java all inherit from a single com.google.protobuf.Message class.
Add the following implicit conversions within the scope of your application controller:
implicit def contentTypeOf_Protobuf: ContentTypeOf[Message] = {
ContentTypeOf[Message](Some("application/x-protobuf"))
}
implicit def writeableOf_Protobuf: Writeable[Message] = {
Writeable[Message](message => message.toByteArray())
}
These will allow Play to serialize buffers directly in a response given by a status such as Ok(protobuf)
Update:
I have posted a working example of the reverse situation, where the incoming request can be parsed and a protobuf can be extracted automatically.
https://gist.github.com/3455432
The parser takes the form of an action in this example, tho you could also code a body parser:
object Put extends Controller {
def index = DecodeProtobuf(classOf[MyProtobuf]) { stack :MyProtobuf =>
Action {
// do something with stack
}
}
}
The client sending the request should serialize the buffer as a byte array, and pass it directly in the body of the request.

Using scala continuations with netty/NIO listeners

I'm using the Netty library (version 4 from GitHub). It works great in Scala, but I am hoping for my library to be able to use continuation passing style for the asynchronous waiting.
Traditionally with Netty you would do something like this (an example asynchronous connect operation):
//client is a ClientBootstrap
val future:ChannelFuture = client.connect(remoteAddr);
future.addListener(new ChannelFutureListener {
def operationComplete (f:ChannelFuture) = {
//here goes the code that happens when the connection is made
}
})
If you are implementing a library (which I am) then you basically have three simple options to allow the user of the library to do stuff after the connection is made:
Just return the ChannelFuture from your connect method and let the user deal with it - this doesn't provide much abstraction from netty.
Take a ChannelFutureListener as a parameter of your connect method and add it as a listener to the ChannelFuture.
Take a callback function object as a parameter of your connect method and call that from within the ChannelFutureListener that you create (this would make for a callback-driven style somewhat like node.js)
What I am trying to do is a fourth option; I didn't include it in the count above because it is not simple.
I want to use scala delimited continuations to make the use of the library be somewhat like a blocking library, but it will be nonblocking behind the scenes:
class MyLibraryClient {
def connect(remoteAddr:SocketAddress) = {
shift { retrn: (Unit => Unit) => {
val future:ChannelFuture = client.connect(remoteAddr);
future.addListener(new ChannelFutureListener {
def operationComplete(f:ChannelFuture) = {
retrn();
}
});
}
}
}
}
Imagine other read/write operations being implemented in the same fashion. The goal of this being that the user's code can look more like this:
reset {
val conn = new MyLibraryClient();
conn.connect(new InetSocketAddress("127.0.0.1", 1337));
println("This will happen after the connection is finished");
}
In other words, the program will look like a simple blocking-style program but behind the scenes there won't be any blocking or threading.
The trouble I'm running into is that I don't fully understand how the typing of delimited continuations work. When I try to implement it in the above way, the compiler complains that my operationComplete implementation actually returns Unit #scala.util.continuations.cpsParam[Unit,Unit => Unit] instead of Unit. I get that there is sort of a "gotcha" in scala's CPS in that you must annotate a shift method's return type with #suspendable, which gets passed up the call stack until the reset, but there doesn't seem to be any way to reconcile that with a pre-existing Java library that has no concept of delimited continuations.
I feel like there really must be a way around this - if Swarm can serialize continuations and jam them over the network to be computed elsewhere, then it must be possible to simply call a continuation from a pre-existing Java class. But I can't figure out how it can be done. Would I have to rewrite entire parts of netty in Scala in order to make this happen?
I found this explanation of Scala's continuations extremely helpful when I started out. In particular pay attention to the parts where he explains shift[A, B, C] and reset[B, C]. Adding a dummy null as the last statement of operationComplete should help.
Btw, you need to invoke retrn() inside another reset if it may have a shift nested inside it.
Edit: Here is a working example
import scala.util.continuations._
import java.util.concurrent.Executors
object Test {
val execService = Executors.newFixedThreadPool(2)
def main(args: Array[String]): Unit = {
reset {
val conn = new MyLibraryClient();
conn.connect("127.0.0.1");
println("This will happen after the connection is finished");
}
println("Outside reset");
}
}
class ChannelFuture {
def addListener(listener: ChannelFutureListener): Unit = {
val future = this
Test.execService.submit(new Runnable {
def run(): Unit = {
listener.operationComplete(future)
}
})
}
}
trait ChannelFutureListener {
def operationComplete(f: ChannelFuture): Unit
}
class MyLibraryClient {
def connect(remoteAddr: String): Unit#cps[Unit] = {
shift {
retrn: (Unit => Unit) => {
val future: ChannelFuture = new ChannelFuture()
future.addListener(new ChannelFutureListener {
def operationComplete(f: ChannelFuture): Unit = {
println("operationComplete starts")
retrn();
null
}
});
}
}
}
}
with a possible output:
Outside reset
operationComplete starts
This will happen after the connection is finished