You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/02/03 02:51:09 UTC
[james-project] 03/12: JAMES-3491 JMAP WebSocket transport JSON
serialization
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit fe23fea43f3dd556b186e320f041f9e32aa06a2d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Jan 28 10:47:54 2021 +0700
JAMES-3491 JMAP WebSocket transport JSON serialization
---
.../james/jmap/json/ResponseSerializer.scala | 58 ++++++++++++++++++++--
1 file changed, 53 insertions(+), 5 deletions(-)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
index 8bdbe4a..edace41 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/ResponseSerializer.scala
@@ -19,9 +19,6 @@
package org.apache.james.jmap.json
-import java.io.InputStream
-import java.net.URL
-
import eu.timepit.refined.refineV
import io.netty.handler.codec.http.HttpResponseStatus
import org.apache.james.core.Username
@@ -34,8 +31,11 @@ import org.apache.james.jmap.core.{Account, Invocation, Session, _}
import play.api.libs.functional.syntax._
import play.api.libs.json._
+import java.io.InputStream
+import java.net.URL
import scala.collection.{Seq => LegacySeq}
import scala.language.implicitConversions
+import scala.util.Try
object ResponseSerializer {
// CreateIds
@@ -68,7 +68,7 @@ object ResponseSerializer {
private implicit val stateWrites: Writes[State] = Json.valueWrites[State]
// ResponseObject
- private implicit val responseObjectFormat: Format[ResponseObject] = Json.format[ResponseObject]
+ private implicit val responseObjectFormat: OFormat[ResponseObject] = Json.format[ResponseObject]
private implicit val maxSizeUploadWrites: Writes[MaxSizeUpload] = Json.valueWrites[MaxSizeUpload]
private implicit val maxConcurrentUploadWrites: Writes[MaxConcurrentUpload] = Json.valueWrites[MaxConcurrentUpload]
@@ -163,7 +163,45 @@ object ResponseSerializer {
private implicit val jsErrorWrites: Writes[JsError] = Json.writes[JsError]
- private implicit val problemDetailsWrites: Writes[ProblemDetails] = Json.writes[ProblemDetails]
+ private implicit val problemDetailsWrites: OWrites[ProblemDetails] = Json.writes[ProblemDetails]
+
+ private implicit val requestIdFormat: Format[RequestId] = Json.valueFormat[RequestId]
+ private implicit val webSocketRequestReads: Reads[WebSocketRequest] = {
+ case jsObject: JsObject =>
+ for {
+ requestId <- jsObject.value.get("requestId")
+ .map(requestIdJson => requestIdFormat.reads(requestIdJson).map(Some(_)))
+ .getOrElse(JsSuccess(None))
+ request <- requestObjectRead.reads(jsObject)
+ } yield {
+ WebSocketRequest(requestId, request)
+ }
+ case _ => JsError("Expecting a JsObject to represent a webSocket inbound request")
+ }
+ private implicit val webSocketInboundReads: Reads[WebSocketInboundMessage] = {
+ case json: JsObject =>
+ json.value.get("@type") match {
+ case Some(JsString("Request")) => webSocketRequestReads.reads(json)
+ case Some(JsString(unknownType)) => JsError(s"Unknown @type filed on a webSocket inbound message: $unknownType")
+ case Some(invalidType) => JsError(s"Invalid @type filed on a webSocket inbound message: expecting a JsString, got $invalidType")
+ case None => JsError(s"Missing @type filed on a webSocket inbound message")
+ }
+ case _ => JsError("Expecting a JsObject to represent a webSocket inbound message")
+ }
+ private implicit val webSocketResponseWrites: Writes[WebSocketResponse] = response => {
+ val apiResponseJson: JsObject = responseObjectFormat.writes(response.responseObject)
+ JsObject(Map(
+ "@type" -> JsString("Response"),
+ "requestId" -> response.requestId.map(_.value).map(JsString).getOrElse(JsNull))
+ ++ apiResponseJson.value)
+ }
+ private implicit val webSocketErrorWrites: Writes[WebSocketError] = error => {
+ val errorJson: JsObject = problemDetailsWrites.writes(error.problemDetails)
+ JsObject(Map(
+ "@type" -> JsString("RequestError"),
+ "requestId" -> error.requestId.map(_.value).map(JsString).getOrElse(JsNull))
+ ++ errorJson.value)
+ }
def serialize(session: Session): JsValue = Json.toJson(session)
@@ -175,8 +213,18 @@ object ResponseSerializer {
def serialize(errors: JsError): JsValue = Json.toJson(errors)
+ def serialize(response: WebSocketOutboundMessage): JsValue = {
+ case response: WebSocketResponse => Json.toJson(response)
+ case error: WebSocketError => Json.toJson(error)
+ }
+
+ def serialize(errors: WebSocketError): JsValue = Json.toJson(errors)
+
def deserializeRequestObject(input: String): JsResult[RequestObject] = Json.parse(input).validate[RequestObject]
+ def deserializeWebSocketInboundMessage(input: String): JsResult[WebSocketInboundMessage] = Try(Json.parse(input).validate[WebSocketInboundMessage])
+ .fold(e => JsError(e.getMessage), result => result)
+
def deserializeRequestObject(input: InputStream): JsResult[RequestObject] = Json.parse(input).validate[RequestObject]
def deserializeResponseObject(input: String): JsResult[ResponseObject] = Json.parse(input).validate[ResponseObject]
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org