web-dev-qa-db-fra.com

Comment convertir la source [ByteString, Any] en InputStream

akka-http représente un fichier téléchargé en utilisant le codage multipart/form-data comme Source[ByteString, Any]. Je dois le démarsaler en utilisant Java qui attend un InputStream.

Comment Source[ByteString, Any] peut être transformé en InputStream?

30
kostya

À partir de la version 2.x, vous y arrivez avec le code suivant:

import akka.stream.scaladsl.StreamConverters
...
val inputStream: InputStream = entity.dataBytes
        .runWith(
           StreamConverters.asInputStream(FiniteDuration(3, TimeUnit.SECONDS))
        )

Voir: http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0.1/scala/migration-guide-1.0-2.x-scala.html

Remarque: a été cassé dans la version 2.0.2 et corrigé dans 2.4.2

23
Bennie Krijger

Vous pouvez essayer d'utiliser un OutputStreamSink qui écrit dans un PipedOutputStream et l'introduire dans un PipedInputStream que votre autre code utilise comme flux d'entrée. C'est un peu approximatif mais ça pourrait marcher. Le code ressemblerait à ceci:

import akka.util.ByteString
import akka.stream.scaladsl.Source
import Java.io.PipedInputStream
import Java.io.PipedOutputStream
import akka.stream.io.OutputStreamSink
import Java.io.BufferedReader
import Java.io.InputStreamReader
import akka.actor.ActorSystem
import akka.stream.ActorFlowMaterializer

object PipedStream extends App{
  implicit val system = ActorSystem("flowtest")
  implicit val mater = ActorFlowMaterializer()

  val lines = for(i <- 1 to 100) yield ByteString(s"This is line $i\n")
  val source = Source(lines)

  val pipedIn = new PipedInputStream()
  val pipedOut = new PipedOutputStream(pipedIn)      
  val flow = source.to(OutputStreamSink(() => pipedOut))
  flow.run()

  val reader = new BufferedReader(new InputStreamReader(pipedIn))
  var line:String = reader.readLine
  while(line != null){
    println(s"Reader received line: $line")
    line = reader.readLine
  }           
}
7
cmbaxter

Vous pouvez extraire un interator de ByteString puis obtenir InputStream. Quelque chose comme ça (pseudocode):

source.map { data: ByteString =>
  data.iterator.asInputStream
}

Mise à jour

Un exemple plus élaboré commençant par un Multipart.FormData

def isSourceFromFormData(formData: Multipart.FormData): Source[InputStream, Any] = 
 formData.parts.map { part => 
   part.entity.dataBytes
   .map(_.iterator.asInputStream)
}.flatten(FlattenStrategy.concat)