Akka-http 1.0-RC4 on android 5.0.1 : that rocks !

114 views
Skip to first unread message

alain marcel

unread,
Jul 3, 2015, 3:05:50 AM7/3/15
to akka...@googlegroups.com
Hi everybody !
Following code is a server realized with akka-http on android that serves files.
For this to work, just call new ServerForDownloadFile() in an android AsyncTask.

class ServerForDownloadTask extends AsyncTask[AnyRef, Void, AnyRef] {
protected def doInBackground(args: AnyRef*): AnyRef = {
try {
new ServerForDownloadFile()
} catch { case e: Exception => println(e) }
}
return null
}

protected def onProgressUpdate(progress: Integer*) {}
protected def onPostExecute(result: Long) {}
}

Take care : this will work only with scala 2.11 (not with scala 2.12) because android is java 6 compatible (not java 8).


ServerForDownloadFile.scala
======================
package app

import java.io.File
import java.io.FileInputStream
import java.nio.channels.FileChannel
import java.nio.ByteBuffer
import java.nio.MappedByteBuffer
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.Try
import scala.util.control.NonFatal
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
import akka.stream.scaladsl.Source
import akka.util.ByteString
import akka.util.Timeout

import android.os.Environment

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)
}
}

class ServerForDownloadFile {
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 dir: File = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val path: String = dir.getPath.toString + "/myfile.avi"
println("=========== path=" + path)
val result = Try {
val mappedByteBuffer = map1(path)
val iterator = new ByteBufferIterator(mappedByteBuffer, 4096)
var cnt = 0
val chunks = Source(() => iterator).map { x =>
if ( cnt % 10000 == 0 )
println("Chunk of size " + x.size + "  cnt=" + cnt)
cnt += 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!")
}

val address = "localhost"
val serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] = Http(system).bind(interface = address, 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()

while (true )
Thread.sleep(100)
}

Johannes Rudolph

unread,
Jul 10, 2015, 5:09:34 AM7/10/15
to akka...@googlegroups.com
Hi Alain,


On Friday, July 3, 2015 at 9:05:50 AM UTC+2, alain marcel wrote:
Following code is a server realized with akka-http on android that serves files.
For this to work, just call new ServerForDownloadFile() in an android AsyncTask.

Thanks for sharing! Any reason you are using a iterator over a memory mapped file instead of a SynchronousFileSource from akka-stream?

Johannes
Reply all
Reply to author
Forward
0 new messages