0

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 ?

Community
  • 1
  • 1

1 Answers1

1

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

James Roper
  • 12,695
  • 46
  • 45
  • thanks for your reply, I gone through the github link provided by you and I can see the code implementation is in java. Will try implementing the same code in scala as I am working with scala controller. Do you have any link reference in your knowledge base where this same implementation is provided in scala ? – Vinit Sharma Feb 04 '16 at 04:07
  • I suggest you learn Scala better. Java code can trivially be converted to Scala code. – James Roper Feb 04 '16 at 04:13
  • I tried implementing the scala code out of the java code provided at your said github link. I want to know like, how should I retrieve the json output when a WebSocket is connected from scala(A WebSocket is connected when we perform `webSocketVar.sendTextMessage("test")` ? I want to know what should I write inside the overridden method `onMessage()` so as to get the json response of the WebSocket method I am connecting? I have updated in my question for the code I am implementing. – Vinit Sharma Feb 04 '16 at 12:16
  • @VinitSharma Why don't you just use the Java library? Scala is capable of interop with Java. Using a well tested library is better than doing all of that work on your own. – bash0r Feb 04 '16 at 12:29
  • @bash0r, I am quite new with Play! framework and scala language. Frankly speaking but I didn't get what you are trying to say. I have simply implemented the code in scala taking help of the java code provided on the git link given by JamesRoper. Am I implementing the code in a wrong way ? Or am I missing for something in my code above ? Please help regarding this. – Vinit Sharma Feb 04 '16 at 12:52
  • @VinitSharma You can use the Java code as is. Both languages compile down to the JVM (https://de.wikipedia.org/wiki/Java_Virtual_Machine). So you don't need to implement it on your own. Then there would be a question: Do you use a build system? – bash0r Feb 04 '16 at 12:56
  • @bash0r, I am using Intellij IDEA SBT plugin for build purpose. Even though I use the same java code, but still I don't know how would I be able to fetch the json response by calling the `WebSocket` function in scala code ? Any idea about it ? – Vinit Sharma Feb 04 '16 at 12:58
  • @VinitSharma Have a look at this specific file: https://github.com/AsyncHttpClient/async-http-client/blob/master/client/src/main/java/org/asynchttpclient/ws/WebSocketTextListener.java It implements a Java interface, which are used in Java for Lambdas and Callbacks and such things. You can create a `new WebSocketTextListener { }` just right in place with the method `WebSocket addWebSocketListener(WebSocketListener l);` to apply the listener to a WebSocket. That's not the Scala way of handling this kind of problems, but it works. :) – bash0r Feb 04 '16 at 13:03
  • @bash0r, If you take a look at my code, I have done the same thing in scala which you are telling me to do, but I need to override the `onMessage()` method in such a way, so that I can get the json response of the `WebSocket` by calling the `sendTextMessage` method. – Vinit Sharma Feb 04 '16 at 13:12
  • @VinitSharma The parameter `s` of type `String` holds that value. You need to convert it with a JSON parser to Scala objects. `http://stackoverflow.com/questions/12591457/scala-2-10-json-serialization-and-deserialization` is what you're looking for I guess. – bash0r Feb 04 '16 at 13:15
  • @bash0r, I understood what you are saying, but still am helpless and don't know what to write inside the `onMessage(s: String)` method, also one more thing that, how do I connect the `WebSocket`, because simply calling the `sendTextMessage("test")` didn't initiated the `WebSocket` connection ? Any small amount of code as a hint would also suffice. – Vinit Sharma Feb 04 '16 at 13:35
  • @VinitSharma That's what I've found with help of Google: https://jfarcand.wordpress.com/2011/12/21/writing-websocket-clients-using-asynchttpclient/ – bash0r Feb 04 '16 at 13:44
  • @JamesRoper, Sir I have added my code implementation in the question. Can you please suggest me for what is being missing in my code ? I need to fetch json by calling a WebSocket connection from my scala code. How would I achieve that ? – Vinit Sharma Feb 05 '16 at 03:32
  • Got resolved my issue. My `WebSocket` connection was created to accept and provide value of type `JsValue`, while I was trying to connect the `WebSocket` by sending a string message, because of which it was not getting connected. By using `sendMessage()` instead of `sendTextMessage()` solved my issue and I can connect the `WebSocket` now and fetch its json value as well. Cheers to @JamesRoper for telling me the right thing to implement. – Vinit Sharma Feb 05 '16 at 11:22