2014-12-22 16:18:26 +01:00
|
|
|
/**
|
2016-01-25 10:16:14 +01:00
|
|
|
* Copyright (C) 2014-2016 Typesafe Inc. <http://www.typesafe.com>
|
2014-12-22 16:18:26 +01:00
|
|
|
*/
|
2015-04-16 02:24:01 +02:00
|
|
|
package docs.stream.io
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2015-01-28 18:02:07 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicReference
|
2015-04-16 02:24:01 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
import akka.stream._
|
2015-04-24 13:15:02 +02:00
|
|
|
import akka.stream.scaladsl.Tcp._
|
2015-01-28 14:19:50 +01:00
|
|
|
import akka.stream.scaladsl._
|
2014-12-22 16:18:26 +01:00
|
|
|
import akka.stream.testkit.AkkaSpec
|
2015-01-28 18:02:07 +01:00
|
|
|
import akka.testkit.TestProbe
|
2014-12-22 16:18:26 +01:00
|
|
|
import akka.util.ByteString
|
2015-03-26 20:56:49 +02:00
|
|
|
import docs.utils.TestUtils
|
2015-01-28 14:19:50 +01:00
|
|
|
|
|
|
|
|
import scala.concurrent.Future
|
2014-12-22 16:18:26 +01:00
|
|
|
|
|
|
|
|
class StreamTcpDocSpec extends AkkaSpec {
|
|
|
|
|
|
|
|
|
|
implicit val ec = system.dispatcher
|
2015-12-11 14:45:24 +01:00
|
|
|
implicit val materializer = ActorMaterializer()
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2015-01-28 18:02:07 +01:00
|
|
|
// silence sysout
|
|
|
|
|
def println(s: String) = ()
|
|
|
|
|
|
2015-04-10 07:44:43 +02:00
|
|
|
"simple server connection" in {
|
2015-03-26 20:56:49 +02:00
|
|
|
{
|
|
|
|
|
//#echo-server-simple-bind
|
2015-09-29 23:08:11 +02:00
|
|
|
val binding: Future[ServerBinding] =
|
|
|
|
|
Tcp().bind("127.0.0.1", 8888).to(Sink.ignore).run()
|
|
|
|
|
|
|
|
|
|
binding.map { b =>
|
|
|
|
|
b.unbind() onComplete {
|
|
|
|
|
case _ => // ...
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-26 20:56:49 +02:00
|
|
|
//#echo-server-simple-bind
|
|
|
|
|
}
|
|
|
|
|
{
|
2015-11-13 09:01:16 +01:00
|
|
|
val (host, port) = TestUtils.temporaryServerHostnameAndPort()
|
2015-03-26 20:56:49 +02:00
|
|
|
//#echo-server-simple-handle
|
2015-05-05 15:02:11 +02:00
|
|
|
import akka.stream.io.Framing
|
|
|
|
|
|
2015-11-13 09:01:16 +01:00
|
|
|
val connections: Source[IncomingConnection, Future[ServerBinding]] =
|
|
|
|
|
Tcp().bind(host, port)
|
2015-03-26 20:56:49 +02:00
|
|
|
connections runForeach { connection =>
|
|
|
|
|
println(s"New connection from: ${connection.remoteAddress}")
|
|
|
|
|
|
|
|
|
|
val echo = Flow[ByteString]
|
2015-08-28 09:35:23 +03:00
|
|
|
.via(Framing.delimiter(
|
|
|
|
|
ByteString("\n"),
|
|
|
|
|
maximumFrameLength = 256,
|
|
|
|
|
allowTruncation = true))
|
2015-06-23 16:55:27 +02:00
|
|
|
.map(_.utf8String)
|
2015-03-26 20:56:49 +02:00
|
|
|
.map(_ + "!!!\n")
|
|
|
|
|
.map(ByteString(_))
|
|
|
|
|
|
|
|
|
|
connection.handleWith(echo)
|
|
|
|
|
}
|
|
|
|
|
//#echo-server-simple-handle
|
2014-12-22 16:18:26 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 07:44:43 +02:00
|
|
|
"initial server banner echo server" in {
|
2015-03-26 20:56:49 +02:00
|
|
|
val localhost = TestUtils.temporaryServerAddress()
|
2015-04-24 13:15:02 +02:00
|
|
|
val connections = Tcp().bind(localhost.getHostName, localhost.getPort) // TODO getHostString in Java7
|
2015-01-28 18:02:07 +01:00
|
|
|
val serverProbe = TestProbe()
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2015-05-05 15:02:11 +02:00
|
|
|
import akka.stream.io.Framing
|
2014-12-22 16:18:26 +01:00
|
|
|
//#welcome-banner-chat-server
|
2015-05-05 15:02:11 +02:00
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
connections.runForeach { connection =>
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
// server logic, parses incoming commands
|
|
|
|
|
val commandParser = Flow[String].takeWhile(_ != "BYE").map(_ + "!")
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
import connection._
|
|
|
|
|
val welcomeMsg = s"Welcome to: $localAddress, you are: $remoteAddress!"
|
|
|
|
|
val welcome = Source.single(welcomeMsg)
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
val serverLogic = Flow[ByteString]
|
|
|
|
|
.via(Framing.delimiter(
|
|
|
|
|
ByteString("\n"),
|
|
|
|
|
maximumFrameLength = 256,
|
|
|
|
|
allowTruncation = true))
|
|
|
|
|
.map(_.utf8String)
|
|
|
|
|
//#welcome-banner-chat-server
|
|
|
|
|
.map { command ⇒ serverProbe.ref ! command; command }
|
|
|
|
|
//#welcome-banner-chat-server
|
|
|
|
|
.via(commandParser)
|
|
|
|
|
// merge in the initial banner after parser
|
|
|
|
|
.merge(welcome)
|
|
|
|
|
.map(_ + "\n")
|
|
|
|
|
.map(ByteString(_))
|
2014-12-22 16:18:26 +01:00
|
|
|
|
|
|
|
|
connection.handleWith(serverLogic)
|
|
|
|
|
}
|
2015-08-28 09:35:23 +03:00
|
|
|
//#welcome-banner-chat-server
|
2015-01-28 18:02:07 +01:00
|
|
|
|
2015-05-05 15:02:11 +02:00
|
|
|
import akka.stream.io.Framing
|
2014-12-22 16:18:26 +01:00
|
|
|
|
2015-01-28 18:02:07 +01:00
|
|
|
val input = new AtomicReference("Hello world" :: "What a lovely day" :: Nil)
|
|
|
|
|
def readLine(prompt: String): String = {
|
|
|
|
|
input.get() match {
|
|
|
|
|
case all @ cmd :: tail if input.compareAndSet(all, tail) ⇒ cmd
|
|
|
|
|
case _ ⇒ "q"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-24 12:31:23 +02:00
|
|
|
{
|
|
|
|
|
//#repl-client
|
2015-04-24 13:15:02 +02:00
|
|
|
val connection = Tcp().outgoingConnection("127.0.0.1", 8888)
|
2015-04-24 12:31:23 +02:00
|
|
|
//#repl-client
|
|
|
|
|
}
|
2015-01-28 18:02:07 +01:00
|
|
|
|
2015-04-24 12:31:23 +02:00
|
|
|
{
|
2015-04-24 13:15:02 +02:00
|
|
|
val connection = Tcp().outgoingConnection(localhost)
|
2015-04-24 12:31:23 +02:00
|
|
|
//#repl-client
|
|
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
val replParser =
|
|
|
|
|
Flow[String].takeWhile(_ != "q")
|
|
|
|
|
.concat(Source.single("BYE"))
|
|
|
|
|
.map(elem => ByteString(s"$elem\n"))
|
2015-01-28 18:02:07 +01:00
|
|
|
|
2015-04-24 12:31:23 +02:00
|
|
|
val repl = Flow[ByteString]
|
2015-08-28 09:35:23 +03:00
|
|
|
.via(Framing.delimiter(
|
|
|
|
|
ByteString("\n"),
|
|
|
|
|
maximumFrameLength = 256,
|
|
|
|
|
allowTruncation = true))
|
2015-06-23 16:55:27 +02:00
|
|
|
.map(_.utf8String)
|
2015-04-24 12:31:23 +02:00
|
|
|
.map(text => println("Server: " + text))
|
|
|
|
|
.map(_ => readLine("> "))
|
2016-02-11 16:39:25 +01:00
|
|
|
.via(replParser)
|
2015-01-28 18:02:07 +01:00
|
|
|
|
2015-04-24 12:31:23 +02:00
|
|
|
connection.join(repl).run()
|
|
|
|
|
}
|
2015-01-28 18:02:07 +01:00
|
|
|
//#repl-client
|
|
|
|
|
|
|
|
|
|
serverProbe.expectMsg("Hello world")
|
|
|
|
|
serverProbe.expectMsg("What a lovely day")
|
|
|
|
|
serverProbe.expectMsg("BYE")
|
2014-12-22 16:18:26 +01:00
|
|
|
}
|
|
|
|
|
}
|