Hi Alain, to see the difference between your two implementations try downloading a file using curl and see the difference between the generated responses.
In your sample server implementation you are streaming contents when using akka-http. You can do the same in Play Framework <https://www.playframework.com/documentation/2.4.x/ScalaStream> as well. On Thu, Jul 2, 2015 at 11:35 AM, alain marcel <[email protected]> wrote: > If I replace Play server with Akka-http server (see source bellow), then I > can download large file (about 650Mb). > So, where is the trouble with the couple Play/Akka-Http ? > Thanks > > > Server.scala > ============ > package app > > import java.io.FileInputStream > import java.nio.channels.FileChannel > import java.nio.file.{Path, Paths, StandardOpenOption} > import java.nio.{ByteBuffer, MappedByteBuffer} > > import scala.util.Failure > import scala.util.Success > import akka.actor.ActorSystem > > import java.nio.channels.FileChannel > import java.nio.file.{Path, Paths, StandardOpenOption} > import java.nio.{ByteBuffer, MappedByteBuffer} > > import akka.actor.ActorSystem > import akka.http.scaladsl.Http > import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart > import akka.http.scaladsl.model._ > import akka.stream.ActorMaterializer > import akka.stream.scaladsl.{Sink, Source} > import akka.util.{ByteString, Timeout} > > import scala.concurrent.Future > import scala.concurrent.duration._ > import scala.util.Try > import scala.util.control.NonFatal > > import com.typesafe.config.Config > import com.typesafe.config.ConfigFactory > > class ByteBufferIterator(buffer:ByteBuffer, chunkSize:Int) extends > Iterator[ByteString] { > require(buffer.isReadOnly) > require(chunkSize > 0) > > override def hasNext = buffer.hasRemaining > > override def next(): ByteString = { > val size = chunkSize min buffer.remaining() > val temp = buffer.slice() > temp.limit(size) > buffer.position(buffer.position() + size) > ByteString(temp) > } > } > > object Server extends App { > > // def map(path: Path) : MappedByteBuffer = { > // val channel = FileChannel.open(path, StandardOpenOption.READ) > // val result = channel.map(FileChannel.MapMode.READ_ONLY, 0L, > channel.size()) > // channel.close() > // result > // } > > def map1(path: String) : MappedByteBuffer = { > val inputStream = new FileInputStream(path) > val channel: FileChannel = inputStream.getChannel(); > val result = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size); > channel.close() > result > } > > > implicit val system = ActorSystem() > > implicit val materializer = ActorMaterializer() > implicit val askTimeout: Timeout = 500.millis > > import HttpMethods._ > > val requestHandler: HttpRequest => HttpResponse = { > case HttpRequest(GET, uri, headers, _, _) => > // val path = "c:/tmp1/toto.txt" > // val path = "c:/tmp1/jfxrt.jar" > val path = "c:/tmp1/garcons.avi" > println("=========== path=" + path) > val result = Try { > val mappedByteBuffer = map1(path) > val iterator = new ByteBufferIterator(mappedByteBuffer, 4096) > var alainCnt = 0 > val chunks = Source(() => iterator).map { x => > if ( alainCnt % 10000 == 0 ) > println("Chunk of size " + x.size + " cnt=" + alainCnt) > alainCnt += 1 > ChunkStreamPart(x) > } > HttpResponse(entity = > HttpEntity.Chunked(MediaTypes.`application/octet-stream`, chunks)) > } recover { > case NonFatal(cause) => > HttpResponse(StatusCodes.InternalServerError, entity = cause.getMessage) > } > result.get > > case _: HttpRequest => > HttpResponse(StatusCodes.NotFound, entity = "Unknown resource!") > } > > > // OK: > val serverSource: Source[Http.IncomingConnection, > Future[Http.ServerBinding]] = Http(system).bind(interface = "localhost", > port = 8080) > > val bindingFuture: Future[Http.ServerBinding] = > serverSource.to(Sink.foreach { connection => > // foreach materializes the source > println("Accepted new connection from " + connection.remoteAddress) > // ... and then actually handle the connection > connection.handleWithSyncHandler(requestHandler) > }).run() > > System.in.read() > system.shutdown() > system.awaitTermination() > } > > -- > >>>>>>>>>> Read the docs: http://akka.io/docs/ > >>>>>>>>>> Check the FAQ: > http://doc.akka.io/docs/akka/current/additional/faq.html > >>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user > --- > You received this message because you are subscribed to the Google Groups > "Akka User List" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/akka-user. > For more options, visit https://groups.google.com/d/optout. > -- Martynas Mickevičius Typesafe <http://typesafe.com/> – Reactive <http://www.reactivemanifesto.org/> Apps on the JVM -- >>>>>>>>>> Read the docs: http://akka.io/docs/ >>>>>>>>>> Check the FAQ: >>>>>>>>>> http://doc.akka.io/docs/akka/current/additional/faq.html >>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user --- You received this message because you are subscribed to the Google Groups "Akka User List" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/akka-user. For more options, visit https://groups.google.com/d/optout.
