Обработка зависимости от будущего завершения в Scala Play (2.6) EssentialFilter - PullRequest
0 голосов
/ 03 мая 2018

Предположим, у меня есть EssentialFilter с именем AbcFilter, цель которого - добавить заголовок к каждому запросу. Однако, чтобы решить, что ему нужно добавить, он должен вызвать библиотеку, которая возвращает Future. В способе, который я сейчас реализовал, он использует Await, так как мне нужно Future для завершения, так что я знаю, как создать заголовок, который мне нужно добавить. Вот реализация:

import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.mvc._

import scala.concurrent.duration.{Duration, _}
import scala.concurrent.{Await, Future}

class AbcFilter () extends EssentialFilter {
  def apply(nextFilter: EssentialAction) = new EssentialAction {
    def apply(requestHeader: RequestHeader) = {
       // This call returns a future
       val future: Future[String] = asyncLibrary.doSomething(requestHeader)
       //Is there any way to avoid using Await here?
       val futureResult = Await.result[String](future, Duration(5, SECONDS))
       val newHeader = "New-Header-Name"-> futureResult 
       //I do need the future to complete in order to create this header!
       val data = requestHeader.headers.toSimpleMap.toSeq :+ newHeader
       val newHeaders = new Headers(_headers = data)
       nextFilter(requestHeader.withHeaders(newHeaders))
    }
  }
}

Есть ли способ реализовать это без Await?

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Мне удалось решить эту проблему, используя Filter вместо EssentialFilter и используя flatMap. FlatMap можно применить к первому будущему, которое мы получим в следующем примере кода, но, надеюсь, это даст представление о шаблоне.

    class AbcFilter () extends Filter{
      def apply(nextFilter: RequestHeader => Future[Result])
        (requestHeader: RequestHeader): Future[Result] = {
          val newHeaderFut: Future[(String, String)] = asyncLibrary.doSomething(requestHeader)
            .map(s => "New-Header-Name" -> s)
          val newHeaders: Future[Headers] = newHeaderFut.map(requestHeader.headers.add)
          newHeaders.flatMap { h => { nextFilter(requestHeader.withHeaders(newHeaders))
           }
         }                 
       }        
     }      
   } }
0 голосов
/ 03 мая 2018

Чтобы не использовать Await, оставайтесь в контексте Future:

class AbcFilter () extends EssentialFilter {
  def apply(nextFilter: EssentialAction) = new EssentialAction {
    def apply(requestHeader: RequestHeader) = {
      val newHeaderFut: Future[(String, String)] = asyncLibrary.doSomething(requestHeader)
        .map(s => "New-Header-Name" -> s)

      val newHeaders: Future[Headers] = newHeaderFut.map(requestHeader.headers.add)

      val accumulator: Accumulator[ByteString, Result] = nextFilter(requestHeader)
      accumulator.mapFuture { result =>
        newHeaders.map(h => result.withHeaders(h.headers: _*))
      }
    }
  }
}
...