Closed borice closed 5 years ago
Looking at the code I couldn't find something built-in, but thankfully it was easy to write. Here's a quick-and-dirty version. Not sure if this is something people want a pull request for.
import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
import java.util.zip.{GZIPInputStream, GZIPOutputStream}
import com.spingo.op_rabbit._
import play.api.libs.json._
import scala.io.{Codec, Source}
import scala.util.{Failure, Success, Try}
object Gzip {
private val codec: Codec = Codec.UTF8
implicit def gzipJsonMarshaller[T](implicit writer: Writes[T]): RabbitMarshaller[T] =
new RabbitMarshaller[T] {
override protected def contentType: String = "application/json"
override protected def contentEncoding: Option[String] = Some("gzip")
override def marshall(value: T): Array[Byte] = {
val json = writer.writes(value)
val rawBytes = Json.stringify(json).getBytes(codec.charSet)
val byteStream = new ByteArrayOutputStream()
using(new GZIPOutputStream(byteStream)) { outStream =>
outStream.write(rawBytes)
}
byteStream.toByteArray
}
}
implicit def gzipJsonUnmarshaller[T](implicit reader: Reads[T]): RabbitUnmarshaller[T] =
new RabbitUnmarshaller[T] {
override def unmarshall(value: Array[Byte], contentTypeOpt: Option[String], contentEncodingOpt: Option[String]): T = {
val contentType = contentTypeOpt.getOrElse("application/json")
val contentEncoding = contentEncodingOpt.getOrElse("gzip")
if (contentType != "application/json" && contentType != "text/json")
throw MismatchedContentType(contentType, "application/json")
if (contentEncoding != "gzip")
throw GenericMarshallingException("Expected GZIP encoding")
val zipStream = new GZIPInputStream(new ByteArrayInputStream(value))
val data = Source.fromInputStream(zipStream)(codec).mkString
val json = Try(Json.parse(data)) match {
case Success(jsValue) => jsValue
case Failure(e) => throw InvalidFormat(data, e.toString)
}
Json.fromJson[T](json) match {
case JsSuccess(v, _) => v
case JsError(errors) => throw InvalidFormat(data, JsError.toJson(errors).toString)
}
}
}
}
the using(...)
method above is just a little helper to properly close things:
(yeah, I know in this case it isn't needed but I'm doing it out of habit)
import scala.language.reflectiveCalls
def using[A, B <: {def close() : Unit}](closeable: B)(f: B => A): A =
try {
f(closeable)
}
finally {
closeable.close()
}
to use the above, simply import Gzip._
instead of import com.spingo.op_rabbit.PlayJsonSupport._
That's pretty cool! I'm not sure how much interest there would be for this. Do you have access to add a wiki page? At worst people can google and find this issue.
I made a Gist for it here: https://gist.github.com/borice/f68678a19f5c42e9fddbb20b62b043a1
Hello.
Is there any support already provided for the compression of message payloads? Just like Play has the ability to
gzip
a response, I'm looking for something similar here.Thank you.