forked from keshin/squbs-seed
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
paypal/squbs#12: Completed Scala template.
- Loading branch information
Akara Sucharitakul
committed
Dec 7, 2015
1 parent
05d827d
commit 892db81
Showing
13 changed files
with
334 additions
and
143 deletions.
There are no files selected for viewing
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
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
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,8 @@ akka { | |
|
||
spray.can.server { | ||
request-timeout = 5 s | ||
} | ||
|
||
default-listener { | ||
aliases = [ "admin-listener" ] | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,71 @@ | ||
package org.squbs.sample | ||
|
||
import akka.actor._ | ||
import org.squbs.unicomplex.RouteDefinition | ||
import spray.http.HttpHeaders.`Content-Type` | ||
import spray.http._ | ||
import spray.routing.Route | ||
import spray.routing._ | ||
import Directives._ | ||
|
||
class SampleSvc extends RouteDefinition { | ||
override def route: Route = path("actor") {ctx => | ||
// actor path = /user/ + cube-shortname + / + actor name | ||
context.actorSelection("/user/squbs-seed/sample") ! ctx | ||
} ~ { | ||
// otherwise go to default response | ||
complete("Hello world") | ||
} | ||
} | ||
|
||
import scala.concurrent.duration._ | ||
|
||
// Messages for interacting with this app. | ||
case class PingRequest(who: String) | ||
case class PingResponse(message: String) | ||
case class ChunkRequest(who: String, delay: FiniteDuration) | ||
case object ChunkEnd | ||
case object EmptyRequest | ||
|
||
/** | ||
* The dispatcher serves as a singleton registered entry point. It creates/manages actors to handle | ||
* the actual request and allows multiple access methods to this service. Only HTTP is shown | ||
* but it would be rather simple to add other access methods like messaging/streams, etc. | ||
* We could use actors with routers or any other method that has a static entry point, instead. | ||
*/ | ||
class SampleDispatcher extends Actor with ActorLogging { | ||
override def receive: Receive = { | ||
case ctx: RequestContext => | ||
context.actorOf(Props[SampleActor]) forward ctx | ||
case request => | ||
context.actorOf(Props[SampleActor]) forward request | ||
} | ||
} | ||
|
||
/** | ||
* This is the actor that handles the request messages. | ||
*/ | ||
class SampleActor extends Actor with ActorLogging { | ||
val system = context.system | ||
import system.dispatcher | ||
import system.scheduler | ||
import concurrent.duration._ | ||
|
||
case class SampleAck(remaining: Int) | ||
|
||
override def receive: Receive = { | ||
case ctx:RequestContext => | ||
val user = ctx.request.uri.query.get("user").getOrElse("there") | ||
val messages = s"Hello $user, welcome to Squbs!".split("") | ||
context.become(chunkResponse(ctx.responder, messages)) | ||
// Have to use text/html for some specific browser like Safari | ||
// https://code.google.com/p/chromium/issues/detail?id=156023 | ||
ctx.responder ! ChunkedResponseStart(HttpResponse().withHeaders(`Content-Type`(MediaTypes.`text/html`))) | ||
.withAck(SampleAck(messages.length)) | ||
|
||
case other => | ||
log.warning(s"Get unexpected message: $other") | ||
context.stop(self) | ||
} | ||
|
||
def chunkResponse(responder: ActorRef, messages: Array[String]): Actor.Receive = { | ||
case SampleAck(0) => | ||
responder ! ChunkedMessageEnd | ||
log.info(s"No remaining messages, stop the actor") | ||
case PingRequest(who) => | ||
if (who.trim.nonEmpty) sender() ! PingResponse(s"Hello $who welcome to squbs!") | ||
else sender() ! EmptyRequest | ||
context.stop(self) | ||
|
||
case SampleAck(remaining) => scheduler.scheduleOnce(50 millis) { | ||
responder ! MessageChunk(messages(messages.length - remaining)).withAck(SampleAck(remaining - 1)) | ||
} | ||
case ChunkRequest(who, delay) => | ||
val requester = sender() // Save the requester for use in the scheduler. | ||
val responses = Iterator("Hello ", who, " welcome ", "to ", "squbs!") | ||
if (delay.toMillis > 0) { | ||
val scheduler = context.system.scheduler.schedule(delay, delay) { | ||
if (responses.hasNext) requester ! PingResponse(responses.next()) | ||
else { | ||
requester ! ChunkEnd | ||
self ! ChunkEnd | ||
} | ||
} | ||
context.become(cancelReceive(scheduler)) | ||
} | ||
else { | ||
responses foreach { requester ! PingResponse(_) } | ||
requester ! ChunkEnd | ||
context.stop(self) | ||
} | ||
|
||
case _ => | ||
context.stop(self) | ||
} | ||
|
||
def cancelReceive(scheduler: Cancellable): Receive = { | ||
case ChunkEnd => | ||
scheduler.cancel() | ||
context.stop(self) | ||
} | ||
} |
Oops, something went wrong.