Last active
August 29, 2015 14:08
-
-
Save William-Yeh/dd6316b8f93175ab80c7 to your computer and use it in GitHub Desktop.
modified spray-can example from https://github.com/spray/spray
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sbt._ | |
import Keys._ | |
import com.typesafe.sbt.osgi.SbtOsgi._ | |
import sbtunidoc.Plugin._ | |
import UnidocKeys._ | |
import sbtassembly.Plugin._ | |
import AssemblyKeys._ | |
object Build extends Build { | |
import BuildSettings._ | |
import Dependencies._ | |
// configure prompt to show current project | |
override lazy val settings = super.settings :+ { | |
shellPrompt := { s => Project.extract(s).currentProject.id + " > " } | |
} | |
// ------------------------------------------------------------------------------------------------------------------- | |
// Root Project | |
// ------------------------------------------------------------------------------------------------------------------- | |
lazy val root = Project("root",file(".")) | |
.aggregate(docs, examples, site, sprayCaching, sprayCan, sprayCanTests, sprayClient, sprayHttp, sprayHttpx, | |
sprayIO, sprayIOTests, sprayRouting, sprayRoutingTests, sprayServlet, sprayTestKit, sprayUtil) | |
.settings(basicSettings: _*) | |
.settings(noPublishing: _*) | |
.settings(unidocSettings: _*) | |
.settings( | |
unidocProjectFilter in (ScalaUnidoc, unidoc) := inAnyProject -- inProjects(docs, examples, site, sprayCanTests, | |
sprayCanExamples, sprayClientExamples, sprayIOExamples, sprayRoutingExamples, sprayServletExamples, | |
serverBenchmark, simpleHttpClient, simpleHttpServer, simpleSprayClient, echoServerExample, onJetty, onSprayCan, | |
simpleRoutingApp, simpleSprayServletServer), | |
target in (ScalaUnidoc, unidoc) := (resourceManaged in Compile in site).value / "api" / version.value, | |
scalacOptions in (ScalaUnidoc, unidoc) += "-Ymacro-no-expand") | |
// ------------------------------------------------------------------------------------------------------------------- | |
// Modules | |
// ------------------------------------------------------------------------------------------------------------------- | |
lazy val sprayCaching = Project("spray-caching", file("spray-caching")) | |
.dependsOn(sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.caching")): _*) | |
.settings(libraryDependencies ++= | |
provided(akkaActor) ++ | |
compile(clHashMap) ++ | |
test(specs2) | |
) | |
lazy val sprayCan = Project("spray-can", file("spray-can")) | |
.dependsOn(sprayIO, sprayHttp, sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.can")): _*) | |
.settings(libraryDependencies ++= | |
provided(akkaActor) ++ | |
test(akkaTestKit, specs2) | |
) | |
lazy val sprayCanTests = Project("spray-can-tests", file("spray-can-tests")) | |
.dependsOn(sprayCan, sprayHttp, sprayHttpx, sprayIO, sprayTestKit, sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(noPublishing: _*) | |
.settings(libraryDependencies ++= test(akkaActor, specs2)) | |
lazy val sprayClient = Project("spray-client", file("spray-client")) | |
.dependsOn(sprayCan, sprayHttp, sprayHttpx, sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.client")): _*) | |
.settings(libraryDependencies ++= | |
provided(akkaActor) ++ | |
test(akkaTestKit, specs2) | |
) | |
lazy val sprayHttp = Project("spray-http", file("spray-http")) | |
.dependsOn(sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.http")): _*) | |
.settings(libraryDependencies ++= | |
compile(parboiled) ++ | |
provided(akkaActor) ++ | |
test(specs2) | |
) | |
lazy val sprayHttpx = Project("spray-httpx", file("spray-httpx")) | |
.dependsOn(sprayHttp, sprayUtil, | |
sprayIO) // for access to akka.io.Tcp, can go away after upgrade to Akka 2.2 | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.httpx"), imports = Seq( | |
"spray.json.*;resolution := optional", | |
"net.liftweb.*;resolution := optional", | |
"org.json4s.*;resolution := optional", | |
"twirl.*;resolution := optional", | |
"play.*;resolution := optional" | |
)): _*) | |
.settings(libraryDependencies ++= | |
compile(mimepull) ++ | |
provided(akkaActor, sprayJson, twirlApi, playTwirlApi, liftJson, json4sNative, json4sJackson, playJson) ++ | |
test(specs2) | |
) | |
lazy val sprayIO = Project("spray-io", file("spray-io")) | |
.dependsOn(sprayUtil, sprayHttp) | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.io", "akka.io")): _*) | |
.settings(libraryDependencies ++= provided(akkaActor, scalaReflect)) | |
lazy val sprayIOTests = Project("spray-io-tests", file("spray-io-tests")) | |
.dependsOn(sprayIO, sprayTestKit, sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(noPublishing: _*) | |
.settings(libraryDependencies ++= test(akkaActor, specs2, scalatest)) | |
lazy val sprayRouting = Project("spray-routing", file("spray-routing")) | |
.dependsOn( | |
sprayCaching % "provided", // for the CachingDirectives trait and CachedUserPassAuthenticator object | |
sprayCan % "provided", // for the SimpleRoutingApp trait | |
sprayHttp, sprayHttpx, sprayUtil, | |
sprayIO) // for access to akka.io.Tcp, can go away after upgrade to Akka 2.2 | |
.settings(sprayModuleSettings: _*) | |
.settings(spray.boilerplate.BoilerplatePlugin.Boilerplate.settings: _*) | |
.settings(osgiSettings(exports = Seq("spray.routing"), imports = Seq( | |
"spray.caching.*;resolution:=optional", | |
"spray.can.*;resolution:=optional", | |
"spray.io.*;resolution:=optional" | |
)): _*) | |
.settings(libraryDependencies ++= | |
compile(shapeless) ++ | |
provided(akkaActor) | |
) | |
lazy val sprayRoutingTests = Project("spray-routing-tests", file("spray-routing-tests")) | |
.dependsOn(sprayCaching, sprayHttp, sprayHttpx, sprayRouting, sprayTestKit, sprayUtil) | |
.settings(sprayModuleSettings: _*) | |
.settings(noPublishing: _*) | |
.settings(libraryDependencies ++= test(akkaActor, specs2, shapeless, sprayJson)) | |
lazy val sprayServlet = Project("spray-servlet", file("spray-servlet")) | |
.dependsOn(sprayHttp, sprayUtil, | |
sprayIO) // for access to akka.io.Tcp, can go away after upgrade to Akka 2.2 | |
.settings(sprayModuleSettings: _*) | |
.settings(osgiSettings(exports = Seq("spray.servlet"), imports = Seq("javax.servlet.*;version=\"[2.6,4.0)\"")): _*) | |
.settings(libraryDependencies ++= | |
provided(akkaActor, servlet30) ++ | |
test(specs2) | |
) | |
lazy val sprayTestKit = Project("spray-testkit", file("spray-testkit")) | |
.dependsOn( | |
sprayHttp % "provided", | |
sprayHttpx % "provided", | |
sprayIO % "provided", | |
sprayRouting % "provided", | |
sprayUtil | |
) | |
.settings(sprayModuleSettings: _*) | |
.settings(libraryDependencies ++= akkaTestKit +: provided(akkaActor, scalatest, specs2)) | |
lazy val sprayUtil = Project("spray-util", file("spray-util")) | |
.settings(sprayModuleSettings: _*) | |
.settings(sprayVersionConfGeneration: _*) | |
.settings(osgiSettings(exports = Seq("spray.util", "akka.spray")): _*) | |
.settings(libraryDependencies ++= | |
provided(akkaActor, scalaReflect) ++ | |
test(akkaTestKit, specs2) | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
// Site Project | |
// ------------------------------------------------------------------------------------------------------------------- | |
lazy val site = Project("site", file("site")) | |
.dependsOn(sprayCaching, sprayCan, sprayRouting) | |
.enablePlugins(play.twirl.sbt.SbtTwirl) | |
.settings(siteSettings: _*) | |
.settings(SphinxSupport.settings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor, sprayJson) ++ | |
runtime(akkaSlf4j, logback) ++ | |
test(specs2) | |
) | |
lazy val docs = Project("docs", file("docs")) | |
.dependsOn(sprayCaching, sprayCan, sprayClient, sprayHttp, sprayHttpx, sprayIO, sprayRouting, | |
sprayServlet, sprayTestKit, sprayUtil) | |
.settings(docsSettings: _*) | |
.settings(libraryDependencies ++= test(akkaActor, sprayJson, specs2, json4sNative)) | |
// ------------------------------------------------------------------------------------------------------------------- | |
// Example Projects | |
// ------------------------------------------------------------------------------------------------------------------- | |
lazy val examples = Project("examples", file("examples")) | |
.aggregate(sprayCanExamples, sprayClientExamples, sprayIOExamples, sprayRoutingExamples, sprayServletExamples) | |
.settings(exampleSettings: _*) | |
lazy val sprayCanExamples = Project("spray-can-examples", file("examples/spray-can")) | |
.aggregate(serverBenchmark, simpleHttpClient, simpleHttpServer) | |
.settings(exampleSettings: _*) | |
lazy val serverBenchmark = Project("server-benchmark", file("examples/spray-can/server-benchmark")) | |
.dependsOn(sprayCan, sprayHttp) | |
.settings(benchmarkSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor, sprayJson) ++ | |
runtime(akkaSlf4j, logback) | |
) | |
lazy val simpleHttpClient = Project("simple-http-client", file("examples/spray-can/simple-http-client")) | |
.dependsOn(sprayCan, sprayHttp) | |
.settings(exampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor) ++ | |
runtime(akkaSlf4j, logback) | |
) | |
lazy val simpleHttpServer = Project("simple-http-server", file("examples/spray-can/simple-http-server")) | |
.dependsOn(sprayCan, sprayHttp) | |
.settings(standaloneServerExampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor, mimepull) ++ | |
runtime(akkaSlf4j, logback) | |
) | |
.settings(assemblySettings: _*) | |
lazy val sprayClientExamples = Project("spray-client-examples", file("examples/spray-client")) | |
.aggregate(simpleSprayClient) | |
.settings(exampleSettings: _*) | |
lazy val simpleSprayClient = Project("simple-spray-client", file("examples/spray-client/simple-spray-client")) | |
.dependsOn(sprayClient) | |
.settings(exampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor, sprayJson) ++ | |
runtime(akkaSlf4j, logback) | |
) | |
lazy val sprayIOExamples = Project("spray-io-examples", file("examples/spray-io")) | |
.aggregate(echoServerExample) | |
.settings(exampleSettings: _*) | |
lazy val echoServerExample = Project("echo-server", file("examples/spray-io/echo-server")) | |
.dependsOn(sprayIO) | |
.settings(standaloneServerExampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor) ++ | |
runtime(akkaSlf4j, logback) | |
) | |
lazy val sprayRoutingExamples = Project("spray-routing-examples", file("examples/spray-routing")) | |
.aggregate(onJetty, onSprayCan, simpleRoutingApp) | |
.settings(exampleSettings: _*) | |
lazy val onJetty = Project("on-jetty", file("examples/spray-routing/on-jetty")) | |
.dependsOn(sprayCaching, sprayServlet, sprayRouting, sprayTestKit % "test") | |
.settings(jettyExampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor) ++ | |
test(specs2) ++ | |
runtime(akkaSlf4j, logback) ++ | |
container(jettyWebApp, servlet30) | |
) | |
lazy val onSprayCan = Project("on-spray-can", file("examples/spray-routing/on-spray-can")) | |
.dependsOn(sprayCaching, sprayCan, sprayRouting, sprayTestKit % "test") | |
.settings(standaloneServerExampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor) ++ | |
test(specs2) ++ | |
runtime(akkaSlf4j, logback) | |
) | |
lazy val simpleRoutingApp = Project("simple-routing-app", file("examples/spray-routing/simple-routing-app")) | |
.dependsOn(sprayCan, sprayRouting) | |
.settings(standaloneServerExampleSettings: _*) | |
.settings(libraryDependencies ++= compile(akkaActor)) | |
lazy val sprayServletExamples = Project("spray-servlet-examples", file("examples/spray-servlet")) | |
.aggregate(simpleSprayServletServer) | |
.settings(exampleSettings: _*) | |
lazy val simpleSprayServletServer = Project("simple-spray-servlet-server", | |
file("examples/spray-servlet/simple-spray-servlet-server")) | |
.dependsOn(sprayHttp, sprayServlet, | |
sprayIO) // for access to akka.io.Tcp, can go away after upgrade to Akka 2.2 | |
.settings(jettyExampleSettings: _*) | |
.settings(exampleSettings: _*) | |
.settings(libraryDependencies ++= | |
compile(akkaActor) ++ | |
runtime(akkaSlf4j, logback) ++ | |
container(jettyWebApp, servlet30) | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package spray.examples | |
import scala.concurrent.duration._ | |
import akka.pattern.ask | |
import akka.util.Timeout | |
import akka.actor._ | |
import spray.can.Http | |
import spray.can.server.Stats | |
import spray.util._ | |
import spray.http._ | |
import HttpMethods._ | |
import MediaTypes._ | |
import spray.can.Http.RegisterChunkHandler | |
class DemoService extends Actor with ActorLogging { | |
implicit val timeout: Timeout = 1.second // for the actor 'asks' | |
import context.dispatcher // ExecutionContext for the futures and scheduler | |
def receive = { | |
// when a new connection comes in we register ourselves as the connection handler | |
case _: Http.Connected => sender ! Http.Register(self) | |
case HttpRequest(GET, Uri.Path("/"), _, _, _) => | |
sender ! index | |
// add a new ECHO endpoint: /echo/text_to_be_echoed | |
case HttpRequest(GET, Uri.Path(path), _, _, _) if path startsWith "/echo/" => | |
val text = path.drop(6) | |
sender ! HttpResponse(entity = text) | |
log.info(text) | |
case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => | |
sender ! HttpResponse(entity = "PONG!") | |
case HttpRequest(GET, Uri.Path("/stream"), _, _, _) => | |
val peer = sender // since the Props creator is executed asyncly we need to save the sender ref | |
context actorOf Props(new Streamer(peer, 25)) | |
case HttpRequest(GET, Uri.Path("/server-stats"), _, _, _) => | |
val client = sender | |
context.actorFor("/user/IO-HTTP/listener-0") ? Http.GetStats onSuccess { | |
case x: Stats => client ! statsPresentation(x) | |
} | |
case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => | |
sender ! HttpResponse(entity = "About to throw an exception in the request handling actor, " + | |
"which triggers an actor restart") | |
sys.error("BOOM!") | |
case HttpRequest(GET, Uri.Path(path), _, _, _) if path startsWith "/timeout" => | |
log.info("Dropping request, triggering a timeout") | |
case HttpRequest(GET, Uri.Path("/stop"), _, _, _) => | |
sender ! HttpResponse(entity = "Shutting down in 1 second ...") | |
sender ! Http.Close | |
context.system.scheduler.scheduleOnce(1.second) { context.system.shutdown() } | |
case r@HttpRequest(POST, Uri.Path("/file-upload"), headers, entity: HttpEntity.NonEmpty, protocol) => | |
// emulate chunked behavior for POST requests to this path | |
val parts = r.asPartStream() | |
val client = sender | |
val handler = context.actorOf(Props(new FileUploadHandler(client, parts.head.asInstanceOf[ChunkedRequestStart]))) | |
parts.tail.foreach(handler !) | |
case s@ChunkedRequestStart(HttpRequest(POST, Uri.Path("/file-upload"), _, _, _)) => | |
val client = sender | |
val handler = context.actorOf(Props(new FileUploadHandler(client, s))) | |
sender ! RegisterChunkHandler(handler) | |
case _: HttpRequest => sender ! HttpResponse(status = 404, entity = "Unknown resource!") | |
case Timedout(HttpRequest(_, Uri.Path("/timeout/timeout"), _, _, _)) => | |
log.info("Dropping Timeout message") | |
case Timedout(HttpRequest(method, uri, _, _, _)) => | |
sender ! HttpResponse( | |
status = 500, | |
entity = "The " + method + " request to '" + uri + "' has timed out..." | |
) | |
} | |
////////////// helpers ////////////// | |
lazy val index = HttpResponse( | |
entity = HttpEntity(`text/html`, | |
<html> | |
<body> | |
<h1>Say hello to <i>spray-can</i>!</h1> | |
<p>Defined resources:</p> | |
<ul> | |
<li><a href="/ping">/ping</a></li> | |
<li><a href="/stream">/stream</a></li> | |
<li><a href="/server-stats">/server-stats</a></li> | |
<li><a href="/crash">/crash</a></li> | |
<li><a href="/timeout">/timeout</a></li> | |
<li><a href="/timeout/timeout">/timeout/timeout</a></li> | |
<li><a href="/stop">/stop</a></li> | |
<li>ADDED: <a href="/echo"><code><b>/echo/</b></code><i>text_to_be_echoed</i></a></li> | |
</ul> | |
<p>Test file upload</p> | |
<form action ="/file-upload" enctype="multipart/form-data" method="post"> | |
<input type="file" name="datafile" multiple=""></input> | |
<br/> | |
<input type="submit">Submit</input> | |
</form> | |
</body> | |
</html>.toString() | |
) | |
) | |
def statsPresentation(s: Stats) = HttpResponse( | |
entity = HttpEntity(`text/html`, | |
<html> | |
<body> | |
<h1>HttpServer Stats</h1> | |
<table> | |
<tr><td>uptime:</td><td>{s.uptime.formatHMS}</td></tr> | |
<tr><td>totalRequests:</td><td>{s.totalRequests}</td></tr> | |
<tr><td>openRequests:</td><td>{s.openRequests}</td></tr> | |
<tr><td>maxOpenRequests:</td><td>{s.maxOpenRequests}</td></tr> | |
<tr><td>totalConnections:</td><td>{s.totalConnections}</td></tr> | |
<tr><td>openConnections:</td><td>{s.openConnections}</td></tr> | |
<tr><td>maxOpenConnections:</td><td>{s.maxOpenConnections}</td></tr> | |
<tr><td>requestTimeouts:</td><td>{s.requestTimeouts}</td></tr> | |
</table> | |
</body> | |
</html>.toString() | |
) | |
) | |
class Streamer(client: ActorRef, count: Int) extends Actor with ActorLogging { | |
log.debug("Starting streaming response ...") | |
// we use the successful sending of a chunk as trigger for scheduling the next chunk | |
client ! ChunkedResponseStart(HttpResponse(entity = " " * 2048)).withAck(Ok(count)) | |
def receive = { | |
case Ok(0) => | |
log.info("Finalizing response stream ...") | |
client ! MessageChunk("\nStopped...") | |
client ! ChunkedMessageEnd | |
context.stop(self) | |
case Ok(remaining) => | |
log.info("Sending response chunk ...") | |
context.system.scheduler.scheduleOnce(100 millis span) { | |
client ! MessageChunk(DateTime.now.toIsoDateTimeString + ", ").withAck(Ok(remaining - 1)) | |
} | |
case x: Http.ConnectionClosed => | |
log.info("Canceling response stream due to {} ...", x) | |
context.stop(self) | |
} | |
// simple case class whose instances we use as send confirmation message for streaming chunks | |
case class Ok(remaining: Int) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package spray.examples | |
import akka.actor.{ActorSystem, Props} | |
import akka.io.IO | |
import spray.can.Http | |
object Main extends App with MySslConfiguration { | |
implicit val system = ActorSystem() | |
// the handler actor replies to incoming HttpRequests | |
val handler = system.actorOf(Props[DemoService], name = "handler") | |
IO(Http) ! Http.Bind(handler, interface = "0.0.0.0", port = 8080) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resolvers += "spray repo" at "http://repo.spray.io" | |
libraryDependencies ++= Seq( | |
"com.decodified" %% "scala-ssh" % "0.6.4", | |
"org.bouncycastle" % "bcprov-jdk16" % "1.46", | |
"com.jcraft" % "jzlib" % "1.1.3" | |
) | |
addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2") | |
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.0.2") | |
addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.5.9") | |
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2") | |
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") | |
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") | |
addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.7.0") | |
addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.3.1") | |
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.2") | |
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "1.0.0-M7") | |
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Used in conjunction with Docker-Spray-HttpServer.