diff --git a/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala index 8a1b829d3a..50b9d93e85 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala @@ -6,8 +6,10 @@ package docs.http import akka.actor.ActorSystem import akka.http.model._ -import akka.stream.scaladsl.Flow +import akka.stream.scaladsl._ import akka.stream.testkit.AkkaSpec +import scala.concurrent.Future +import akka.http.Http class HttpServerExampleSpec extends AkkaSpec("akka.actor.default-mailbox.mailbox-type = akka.dispatch.UnboundedMailbox") { @@ -21,11 +23,13 @@ class HttpServerExampleSpec implicit val system = ActorSystem() implicit val materializer = ActorFlowMaterializer() - val serverSource = Http(system).bind(interface = "localhost", port = 8080) - serverSource.runForeach { connection => // foreach materializes the source + 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 - } + }).run() //#bind-example } @@ -48,12 +52,17 @@ class HttpServerExampleSpec entity = HttpEntity(MediaTypes.`text/html`, "Hello world!")) - case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => HttpResponse(entity = "PONG!") - case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => sys.error("BOOM!") - case _: HttpRequest => HttpResponse(404, entity = "Unknown resource!") + case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => + HttpResponse(entity = "PONG!") + + case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => + sys.error("BOOM!") + + case _: HttpRequest => + HttpResponse(404, entity = "Unknown resource!") } - val bindingFuture = serverSource.to(Sink.foreach { connection => + val bindingFuture: Future[Http.ServerBinding] = serverSource.to(Sink.foreach { connection => println("Accepted new connection from " + connection.remoteAddress) connection handleWithSyncHandler requestHandler diff --git a/akka-docs-dev/rst/scala/http/server.rst b/akka-docs-dev/rst/scala/http/server.rst index f69cb100c9..7b9c25f339 100644 --- a/akka-docs-dev/rst/scala/http/server.rst +++ b/akka-docs-dev/rst/scala/http/server.rst @@ -60,16 +60,16 @@ Arguments to the ``Http.bind`` method specify the interface and port to bind to HTTP connections. Additionally, the method also allows you to define socket options as well as a larger number of settings for configuring the server according to your needs. -The result of the ``bind`` method is a ``Http.ServerBinding`` which is immediately returned. The ``ServerBinding.connections`` -returns a ``Source[IncomingConnection]`` which is used to handle incoming connections. The actual binding is only done when this -source is materialized as part of a bigger processing pipeline. In case the bind fails (e.g. because the port is already -busy) the error will be reported by flagging an error on the ``IncomingConnection`` stream. +The result of the ``bind`` method is a ``Source[IncomingConnection]`` which is used to handle incoming connections. +The actual binding is only done when this source is materialized as part of a bigger processing pipeline. In case the +bind fails (e.g. because the port is already busy) the error will be reported by flagging an error on the materialized +stream. The binding is released and the underlying listening socket is closed when all subscribers of the +source have cancelled their subscription. +Connections are handled by materializing a pipeline which uses the ``Source[IncomingConnection]``. This source +materializes to ``Future[ServerBinding]`` which is completed when server successfully binds to the specified port. After materialization ``ServerBinding.localAddress`` returns the actual local address of the bound socket. - -Connections are handled by materializing a pipeline which uses the ``Source[IncomingConnection]`` returned by -``ServerBinding.connections``. The binding is released and the underlying listening socket is closed when all -subscribers of the ``connections`` source have cancelled their subscription. +``ServerBinding.unbind()`` can be used to asynchronously trigger unbinding of the server port. (todo: explain even lower level serverFlowToTransport API) @@ -79,9 +79,9 @@ subscribers of the ``connections`` source have cancelled their subscription. Request-Response Cycle ---------------------- -When a new connection has been accepted it will be published by by the ``ServerBinding.connections`` source as an -``Http.IncomingConnection`` which consists of the remote address, and methods to provide a ``Flow[HttpRequest, HttpResponse]`` -to handle requests coming in over this connection. +When a new connection has been accepted it will be published as an ``Http.IncomingConnection`` which consists +of the remote address, and methods to provide a ``Flow[HttpRequest, HttpResponse]`` to handle requests coming in over +this connection. Requests are handled by calling one of the ``IncomingConnection.handleWithX`` methods with a handler, which can either be