I'm having a WebSocket endpoint exposed by the Play Framework like this:
def socket: WebSocket = WebSocket.acceptOrResult[JsValue, JsValue] { request =>
Future.successful(
if (acceptedSubProtocol(request.headers, appConfig.ocppServerCfg.supportedProtocols)) { // TODO: Get the Protocol via AppConfig
Right(ActorFlow.actorRef { actorRef =>
Props(new ProvisioningActor(actorRef))
})
} else {
logger.warn(s"Supported Protocol is not one of ${appConfig.ocppServerCfg.supportedProtocols.mkString(",")} " +
"in the Sec-WebSocket-Protocol header")
Left(Forbidden)
}
)
}
The following implicit conversion for the incoming Json which looks like this:
implicit val ocppCallRequestReads2: Reads[OCPPCallRequest] = Reads { jsValue =>
val messageTypeIdE = (jsValue \ 0).toEither
val messageIdE = (jsValue \ 1).toEither
val actionNameE = (jsValue \ 2).toEither
val payloadE = (jsValue \ 3).toEither
val yielded = for {
messageTypeId <- messageTypeIdE
messageId <- messageIdE
actionName <- actionNameE
payload <- payloadE
} yield {
OCPPCallRequest( // Here I know all 4 exists, so safe to call head
messageTypeId.head.as[Int],
messageId.head.as[String],
actionName.head.as[String],
payload
)
}
yielded match {
case Right(ocppCallRequest) => JsSuccess(ocppCallRequest)
case Left(errors) =>
println("****************+ ERRORS")
errors.messages.foreach(println)
println("****************+ ERRORS")
JsError(errors)
}
}
And the actual JSON:
[
"19223201",
"BootNotification",
{
"reason": "PowerUp",
"chargingStation": {
"serialNumber" : "12345",
"model" : "",
"vendorName" : "",
"firmwareVersion" : "",
"modem": {
"iccid": "",
"imsi": ""
}
}
}
]
What I'm trying to do is to validate the incoming JSON and propogate any errors to the client. When I tried to run my example., I'm not able to pass the error back as a JSON response, but the WebSocket endpoint closes with an internal server error as seen below:
[info] a.a.CoordinatedShutdown - Running CoordinatedShutdown with reason [ApplicationStoppedReason]
[info] a.e.s.Slf4jLogger - Slf4jLogger started
[info] play.api.Play - Application started (Dev) (no global state)
****************+ ERRORS
Array index out of bounds in ["19223201","BootNotification",{"reason":"PowerUp","chargingStation":{"serialNumber":"12345","model":"","vendorName":"","firmwareVersion":"","modem":{"iccid":"","imsi":""}}}]
****************+ ERRORS
[error] p.c.s.c.WebSocketFlowHandler - WebSocket flow threw exception
java.lang.ClassCastException: scala.Tuple2 cannot be cast to play.api.libs.json.JsValue
at akka.stream.impl.fusing.Map$$anon$1.onPush(Ops.scala:52)
at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:542)
at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:496)
at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:650)
at akka.stream.impl.fusing.ActorGraphInterpreter$SimpleBoundaryEvent.execute(ActorGraphInterpreter.scala:61)
at akka.stream.impl.fusing.ActorGraphInterpreter$SimpleBoundaryEvent.execute$(ActorGraphInterpreter.scala:57)
at akka.stream.impl.fusing.ActorGraphInterpreter$BatchingActorInputBoundary$OnNext.execute(ActorGraphInterpreter.scala:104)
at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:625)
at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:800)
Any clues as to how I can control the WebSocket endpoint not to crash into an exception? What happens is that the connection gets closed and I do not want that.