2015-04-16 02:24:01 +02:00
|
|
|
/**
|
2016-02-23 12:58:39 +01:00
|
|
|
* Copyright (C) 2015-2016 Lightbend Inc. <http://www.lightbend.com>
|
2015-04-16 02:24:01 +02:00
|
|
|
*/
|
2015-05-29 16:43:02 +02:00
|
|
|
package akka.stream.impl.io
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2016-04-25 19:25:26 +10:00
|
|
|
import java.io.InputStream
|
|
|
|
|
import java.nio.file.Path
|
2015-04-16 02:24:01 +02:00
|
|
|
|
|
|
|
|
import akka.stream._
|
2015-10-31 14:46:10 +01:00
|
|
|
import akka.stream.ActorAttributes.Dispatcher
|
2016-02-16 16:56:06 +01:00
|
|
|
import akka.stream.IOResult
|
2015-04-16 02:24:01 +02:00
|
|
|
import akka.stream.impl.StreamLayout.Module
|
2015-11-14 22:42:22 +01:00
|
|
|
import akka.stream.impl.Stages.DefaultAttributes.IODispatcher
|
2015-04-16 02:24:01 +02:00
|
|
|
import akka.stream.impl.{ ErrorPublisher, SourceModule }
|
2015-11-14 22:42:22 +01:00
|
|
|
import akka.util.ByteString
|
2015-04-16 02:24:01 +02:00
|
|
|
import org.reactivestreams._
|
2015-11-14 22:42:22 +01:00
|
|
|
import scala.concurrent.{ Future, Promise }
|
2015-04-16 02:24:01 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* INTERNAL API
|
2016-04-25 19:25:26 +10:00
|
|
|
* Creates simple synchronous Source backed by the given file.
|
2015-04-16 02:24:01 +02:00
|
|
|
*/
|
2016-04-25 19:25:26 +10:00
|
|
|
private[akka] final class FileSource(f: Path, chunkSize: Int, val attributes: Attributes, shape: SourceShape[ByteString])
|
2016-01-21 18:06:42 +02:00
|
|
|
extends SourceModule[ByteString, Future[IOResult]](shape) {
|
2015-11-14 22:42:22 +01:00
|
|
|
require(chunkSize > 0, "chunkSize must be greater than 0")
|
2015-04-16 02:24:01 +02:00
|
|
|
override def create(context: MaterializationContext) = {
|
2015-10-31 14:46:10 +01:00
|
|
|
// FIXME rewrite to be based on GraphStage rather than dangerous downcasts
|
2016-05-03 18:58:26 -07:00
|
|
|
val materializer = ActorMaterializerHelper.downcast(context.materializer)
|
2015-12-11 14:45:24 +01:00
|
|
|
val settings = materializer.effectiveSettings(context.effectiveAttributes)
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2016-01-21 18:06:42 +02:00
|
|
|
val ioResultPromise = Promise[IOResult]()
|
|
|
|
|
val props = FilePublisher.props(f, ioResultPromise, chunkSize, settings.initialInputBufferSize, settings.maxInputBufferSize)
|
2015-11-14 22:42:22 +01:00
|
|
|
val dispatcher = context.effectiveAttributes.get[Dispatcher](IODispatcher).dispatcher
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2015-12-11 14:45:24 +01:00
|
|
|
val ref = materializer.actorOf(context, props.withDispatcher(dispatcher))
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2016-01-21 18:06:42 +02:00
|
|
|
(akka.stream.actor.ActorPublisher[ByteString](ref), ioResultPromise.future)
|
2015-04-16 02:24:01 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-21 18:06:42 +02:00
|
|
|
override protected def newInstance(shape: SourceShape[ByteString]): SourceModule[ByteString, Future[IOResult]] =
|
2015-11-14 22:42:22 +01:00
|
|
|
new FileSource(f, chunkSize, attributes, shape)
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2015-06-23 17:32:55 +02:00
|
|
|
override def withAttributes(attr: Attributes): Module =
|
2015-11-14 22:42:22 +01:00
|
|
|
new FileSource(f, chunkSize, attr, amendShape(attr))
|
2016-03-11 17:08:30 +01:00
|
|
|
|
|
|
|
|
override protected def label: String = s"FileSource($f, $chunkSize)"
|
2015-04-16 02:24:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* INTERNAL API
|
|
|
|
|
* Source backed by the given input stream.
|
|
|
|
|
*/
|
2015-06-23 17:32:55 +02:00
|
|
|
private[akka] final class InputStreamSource(createInputStream: () ⇒ InputStream, chunkSize: Int, val attributes: Attributes, shape: SourceShape[ByteString])
|
2016-01-21 18:06:42 +02:00
|
|
|
extends SourceModule[ByteString, Future[IOResult]](shape) {
|
2015-04-16 02:24:01 +02:00
|
|
|
override def create(context: MaterializationContext) = {
|
2016-05-03 18:58:26 -07:00
|
|
|
val materializer = ActorMaterializerHelper.downcast(context.materializer)
|
2016-01-21 18:06:42 +02:00
|
|
|
val ioResultPromise = Promise[IOResult]()
|
2015-04-16 02:24:01 +02:00
|
|
|
|
|
|
|
|
val pub = try {
|
|
|
|
|
val is = createInputStream() // can throw, i.e. FileNotFound
|
|
|
|
|
|
2016-01-21 18:06:42 +02:00
|
|
|
val props = InputStreamPublisher.props(is, ioResultPromise, chunkSize)
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2015-12-11 14:45:24 +01:00
|
|
|
val ref = materializer.actorOf(context, props)
|
2015-04-16 02:24:01 +02:00
|
|
|
akka.stream.actor.ActorPublisher[ByteString](ref)
|
|
|
|
|
} catch {
|
|
|
|
|
case ex: Exception ⇒
|
2016-01-21 18:06:42 +02:00
|
|
|
ioResultPromise.failure(ex)
|
2015-04-16 02:24:01 +02:00
|
|
|
ErrorPublisher(ex, attributes.nameOrDefault("inputStreamSource")).asInstanceOf[Publisher[ByteString]]
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-21 18:06:42 +02:00
|
|
|
(pub, ioResultPromise.future)
|
2015-04-16 02:24:01 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-21 18:06:42 +02:00
|
|
|
override protected def newInstance(shape: SourceShape[ByteString]): SourceModule[ByteString, Future[IOResult]] =
|
2015-04-16 02:24:01 +02:00
|
|
|
new InputStreamSource(createInputStream, chunkSize, attributes, shape)
|
|
|
|
|
|
2015-06-23 17:32:55 +02:00
|
|
|
override def withAttributes(attr: Attributes): Module =
|
2015-04-16 02:24:01 +02:00
|
|
|
new InputStreamSource(createInputStream, chunkSize, attr, amendShape(attr))
|
|
|
|
|
}
|