Skip to content

Commit db5ab74

Browse files
committed
2015 live coding updates
1 parent 994a5d3 commit db5ab74

File tree

5 files changed

+179
-18
lines changed

5 files changed

+179
-18
lines changed

sbt-skeleton/build.sbt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ libraryDependencies := Seq(
44
"com.typesafe.akka" %% "akka-actor" % "2.3.11",
55
"io.spray" %% "spray-can" % "1.3.3",
66
"io.spray" %% "spray-routing" % "1.3.3",
7-
"io.spray" %% "spray-json" % "1.3.2"
7+
"io.spray" %% "spray-json" % "1.3.2",
8+
"com.typesafe.slick" %% "slick" % "3.0.0",
9+
"org.slf4j" % "slf4j-nop" % "1.6.4",
10+
"com.h2database" % "h2" % "1.4.187"
811
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
polyglot2015 = {
2+
url = "jdbc:h2:mem:polyglot2015"
3+
driver = org.h2.Driver
4+
connectionPool = disabled
5+
keepAliveConnection = true
6+
}

sbt-skeleton/src/main/scala/com/cluonflux/polyglot/NumberGuessWeb.scala

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import scala.concurrent.ExecutionContext.Implicits.global
99
import scala.concurrent.Future
1010
import scala.concurrent.Await
1111

12-
object NumberGuessWeb extends App with SimpleRoutingApp with spray.httpx.SprayJsonSupport {
12+
object NumberGuessWeb extends App
13+
with SimpleRoutingApp
14+
with spray.httpx.SprayJsonSupport
15+
{
1316
implicit val system = ActorSystem("my-system")
1417

1518
val game = system.actorOf(Props(new NumberGameActor))
@@ -36,7 +39,7 @@ object NumberGuessWeb extends App with SimpleRoutingApp with spray.httpx.SprayJs
3639
implicit val taggedHighF = new JsonWriter[High] {
3740
def write(high: High): JsValue = {
3841
highF.write(high) match {
39-
case JsObject(fields) =>
42+
case JsObject(fields) =>
4043
JsObject(fields + ("status" -> JsString("High")))
4144
}
4245
}
@@ -62,33 +65,33 @@ object NumberGuessWeb extends App with SimpleRoutingApp with spray.httpx.SprayJs
6265
startServer(interface = "localhost", port = 8080) {
6366
path("restgame") {
6467
get {
65-
complete(
66-
game.ask(QueryGuesses).mapTo[RemainingGuesses]
67-
)
68+
complete(
69+
game.ask(QueryGuesses).mapTo[RemainingGuesses]
70+
)
6871
} ~ post {
69-
entity(as[Guess]) { guess =>
72+
entity(as[Guess]) { guess =>
7073
val jsonFuture = game.ask(guess).map {
71-
case w: Won.type => JsObject(Map("status" -> JsString("Won")))
72-
case l: Lost.type => JsObject(Map("status" -> JsString("Lost")))
74+
case w: Won.type => JsObject(Map("status" -> JsString("Won")))
75+
case l: Lost.type => JsObject(Map("status" -> JsString("Lost")))
7376

74-
case h: High => h.toJson
77+
case h: High => h.toJson
7578
case l: Low => l.toJson
76-
}
79+
}
7780

78-
complete(jsonFuture.map(_.prettyPrint))
79-
}
80-
}
81-
} ~ path("game") {
82-
get {
83-
complete {
81+
complete(jsonFuture.map(_.prettyPrint))
82+
}
83+
}
84+
} ~ path("game") {
85+
get {
86+
complete {
8487
<xml:group>
8588
<h1>Welcome to the Number Game</h1>
8689
{form("/game")}
8790
</xml:group>
8891
}
8992
} ~ post {
9093
formFields('guessed.as[Int]) { (guessed) =>
91-
val htmlFuture = game.ask(Guess(guessed)) map {
94+
val htmlFuture = game.ask(Guess(guessed)) map {
9295
case Won => <h1>You won!</h1>
9396
case Lost => <h1>You lost! :(</h1>
9497

@@ -104,6 +107,7 @@ object NumberGuessWeb extends App with SimpleRoutingApp with spray.httpx.SprayJs
104107
{form("/game")}
105108
</xml:group>
106109
}
110+
107111
complete(htmlFuture)
108112
}
109113
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.cluonflux.polyglot.polyglot2015
2+
3+
import java.util.UUID
4+
5+
import slick.ast.ScalaBaseType
6+
import slick.driver.H2Driver.api._
7+
import slick.lifted.{ProvenShape, ForeignKeyQuery}
8+
import scala.concurrent.ExecutionContext.Implicits.global
9+
import scala.util.{Success, Failure}
10+
11+
case class Guid[T](raw: UUID) extends AnyVal
12+
13+
object Guid {
14+
def apply[T](): Guid[T] = Guid[T](UUID.randomUUID())
15+
def apply[T](s: String): Guid[T] = Guid[T](UUID.fromString(s))
16+
}
17+
18+
// case class Cage(guid: Guid[Cage], name: String)
19+
20+
trait AnimalsSchema {
21+
implicit def guidMapper[T] = MappedColumnType.base[Guid[T], String](_.raw.toString, Guid[T](_))
22+
23+
class Cage(tag: Tag) extends Table[(Guid[Cage], String)](tag, "cages") {
24+
def guid = column[Guid[Cage]]("guid", O.PrimaryKey)
25+
def name = column[String]("name")
26+
27+
def * = (guid, name)
28+
}
29+
30+
val cageQuery = TableQuery[Cage]
31+
32+
class Animal(tag: Tag) extends Table[(Guid[Animal], Guid[Cage], String)](tag, "animals") {
33+
def guid = column[Guid[Animal]]("guid", O.PrimaryKey)
34+
def cageGuid = column[Guid[Cage]]("cage_guid")
35+
def name = column[String]("name")
36+
37+
def fk_cageGuid = foreignKey("fk_animal_cage", cageGuid, cageQuery)(_.guid)
38+
39+
def * = (guid, cageGuid, name)
40+
}
41+
42+
val animalQuery = TableQuery[Animal]
43+
}
44+
45+
object DB extends AnimalsSchema {
46+
val db = Database.forConfig("polyglot2015")
47+
48+
val cageGuid = Guid[Cage]()
49+
50+
val setup = DBIO.seq(
51+
(cageQuery.schema ++ animalQuery.schema).create,
52+
53+
cageQuery += (cageGuid, "The big one"),
54+
animalQuery ++= Seq(
55+
(Guid[Animal](), cageGuid, "Fluffy the cat"),
56+
(Guid[Animal](), cageGuid, "Dumbo the elephant")
57+
)
58+
)
59+
60+
def main(args: Array[String]): Unit = {
61+
try {
62+
val setupFuture = db.run(setup)
63+
setupFuture.onComplete {
64+
case Success(()) =>
65+
// It's a database!
66+
val shorties = for {
67+
animal <- animalQuery
68+
if animal.name === args(0)
69+
} yield animal.guid
70+
71+
val xx = db.run(shorties.result)
72+
xx.foreach { guids =>
73+
guids.foreach { guid =>
74+
println(guid)
75+
}
76+
}
77+
78+
case Failure(t) =>
79+
throw t
80+
}
81+
Thread.sleep(10000)
82+
} finally {
83+
db.close()
84+
}
85+
}
86+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.cluonflux.polyglot.polyglot2015
2+
3+
import akka.actor.SupervisorStrategy.Escalate
4+
import akka.actor._
5+
6+
import scala.concurrent.duration._
7+
8+
object Unreliable {
9+
def main(args: Array[String]): Unit = {
10+
val sys = ActorSystem("unreliable")
11+
12+
sys.actorOf(Props(new RootActor()))
13+
}
14+
}
15+
16+
final class RootActor extends Actor with ActorLogging {
17+
override def supervisorStrategy: SupervisorStrategy = OneForOneStrategy(10, 10.minute) {
18+
case e: RuntimeException =>
19+
Escalate
20+
}
21+
22+
override def preStart(): Unit = {
23+
self ! 'init
24+
}
25+
26+
var child: Option[ActorRef] = None
27+
28+
override def receive: Receive = {
29+
case 'init =>
30+
log.info("Parent is initializing!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
31+
val ref = context.actorOf(Props(new ChildActor()))
32+
33+
child = Some(ref)
34+
context.watch(ref)
35+
36+
case 'panic =>
37+
child.foreach(context.stop)
38+
39+
case Terminated(victim) =>
40+
log.info("O NOESS!!! {} died!", victim)
41+
}
42+
}
43+
44+
final class ChildActor extends Actor with ActorLogging {
45+
private val rnd = new scala.util.Random()
46+
47+
override def preStart(): Unit = {
48+
self ! 'init
49+
}
50+
51+
override def receive: Actor.Receive = {
52+
case 'init =>
53+
import scala.concurrent.ExecutionContext.Implicits.global
54+
55+
context.system.scheduler.schedule(1.second, 1.second, self, 'tick)
56+
57+
case 'tick =>
58+
log.info("Tick!")
59+
60+
if (rnd.nextInt() % 10 == 0) sys.error("Whoops!")
61+
}
62+
}

0 commit comments

Comments
 (0)