All Downloads are FREE. Search and download functionalities are using the official Maven repository.

im.actor.server.enrich.PreviewHelpers.scala Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
package im.actor.server.enrich

import scala.concurrent.duration._
import scala.concurrent.{ ExecutionContext, Future }
import scala.util.{ Failure, Success, Try }

import akka.http.scaladsl.HttpExt
import akka.http.scaladsl.model.{ HttpEntity, HttpRequest, HttpResponse }
import akka.stream.Materializer
import akka.stream.scaladsl._
import akka.stream.stage.{ Context, PushStage }
import akka.util.ByteString

import im.actor.server.enrich.PreviewMaker.Failures._
import im.actor.server.enrich.PreviewMaker._

object PreviewHelpers {

  def withRequest(request: ⇒ HttpRequest, handler: UpdateHandler)(function: HttpResponse ⇒ Future[PreviewResult])(implicit http: HttpExt, materializer: Materializer, ec: ExecutionContext): Future[PreviewResult] = {
    Try(request) match {
      case Success(v) ⇒ http.singleRequest(v).flatMap(function).recover { case e: Exception ⇒ failedToMakePreview(handler, e.getMessage) }
      case Failure(_) ⇒ Future.successful(failedToMakePreview(handler))
    }
  }

  def downloadDefault(entity: HttpEntity.Default, fileName: Option[String], handler: UpdateHandler, config: RichMessageConfig)(implicit materializer: Materializer, ec: ExecutionContext): Future[PreviewResult] = {
    val mediaType = entity.contentType.mediaType
    val contentLength = entity.contentLength
    (mediaType.isImage, contentLength) match {
      case (true, length) if length <= config.maxSize ⇒
        entity
          .toStrict(10.seconds)
          .map { body ⇒ PreviewSuccess(body.data, fileName, mediaType.value, handler) }
          .recover { case e: Exception ⇒ failedToMakePreview(handler, e.getMessage) }
      case (true, _)  ⇒ Future.successful(contentTooLong(handler))
      case (false, _) ⇒ Future.successful(notAnImage(handler))
    }
  }

  def downloadChunked(entity: HttpEntity.Chunked, fileName: Option[String], handler: UpdateHandler, config: RichMessageConfig)(implicit materializer: Materializer, ec: ExecutionContext): Future[PreviewResult] = {
    val mediaType = entity.contentType.mediaType
    mediaType.isImage match {
      case true ⇒
        entity.dataBytes
          .via(sizeBoundingFlow(config.maxSize))
          .runWith(Sink.fold(ByteString.empty) { (acc, el) ⇒ acc ++ el })
          .map { body ⇒ PreviewSuccess(body, fileName, mediaType.value, handler) }
          .recover { case e: Exception ⇒ failedToMakePreview(handler, e.getMessage) }
      case false ⇒ Future.successful(notAnImage(handler))
    }
  }

  private def sizeBoundingFlow(maxSize: Long) = Flow[ByteString].transform {
    () ⇒
      new PushStage[ByteString, ByteString] {
        var length: Int = 0

        def onPush(elem: ByteString, ctx: Context[ByteString]) =
          if (length > maxSize) {
            ctx.fail(new Exception(Failures.Messages.ContentTooLong))
          } else {
            length += elem.length
            ctx.push(elem)
          }
      }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy