From c6b408eda19d3c22828138fdcb544c146abe9c89 Mon Sep 17 00:00:00 2001 From: James Ward Date: Sat, 31 Mar 2012 00:05:26 -0600 Subject: [PATCH] koans compile in a seperate process with communication via rabbitmq --- .gitignore | 19 +++++++------- app/Global.scala | 20 +++++++++++++++ app/controllers/Application.scala | 38 +++++++++++++--------------- app/koanrunner/KoanRunner.scala | 41 +++++++++++++++++++++++++++++++ app/messaging/MessageBus.scala | 28 +++++++++++++++++++++ conf/application.conf | 1 + project/Build.scala | 19 +++++++------- 7 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 app/Global.scala create mode 100644 app/koanrunner/KoanRunner.scala create mode 100644 app/messaging/MessageBus.scala diff --git a/.gitignore b/.gitignore index 2641b25..f65c324 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,10 @@ -logs -project/project -project/target -target -tmp -.history -dist -.idea -*.iml \ No newline at end of file +/logs +/project/project +/project/target +/target +/tmp +/.history +/dist +/.idea +/*.iml +/out diff --git a/app/Global.scala b/app/Global.scala new file mode 100644 index 0000000..4780c5b --- /dev/null +++ b/app/Global.scala @@ -0,0 +1,20 @@ +import com.rabbitmq.client.AMQP.BasicProperties +import com.rabbitmq.client.{GetResponse, Channel, ConnectionFactory} +import messaging.MessageBus +import play.api.GlobalSettings + +import play.api.Application + +object Global extends GlobalSettings { + + override def onStart(app: Application) { + + app.configuration.getString("rabbitmq.uri") map { uri => + MessageBus.setup(uri) + } getOrElse { + sys.error("No rabbitmq.uri specified") + } + + } + +} diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala index 8ca744b..0510971 100644 --- a/app/controllers/Application.scala +++ b/app/controllers/Application.scala @@ -1,16 +1,17 @@ package controllers -import play.api.mvc._ -import play.api.data._ -import play.api.data.Forms._ -import views.html +import scala.collection.mutable.Map -import com.twitter.util.Eval -import support.KoanSuite -import org.scalatest.{Filter, Stopper, Tracker} -import koanrunner.{TestResult, KoanReporter} +import messaging.MessageBus +import com.rabbitmq.client.RpcClient +import koanrunner.TestResult + +import play.api.mvc.Controller +import play.api.mvc.Action +import play.api.data.Form +import play.api.data.Forms.{single, nonEmptyText} +import com.codahale.jerkson.Json -import scala.collection.mutable.Map object Application extends Controller { @@ -28,20 +29,15 @@ object Application extends Controller { implicit request => scalaCodeForm.bindFromRequest.value map { case (inputScala) => { - val outputScala = doEval(inputScala) - Ok(html.output(outputScala)) - } - } getOrElse BadRequest - } - - def doEval(scalaCode: String) = { - val suite = Eval[KoanSuite](scalaCode) - - val results = Map[String, TestResult]() + // send message to rabbitmq + val rpcClient = new RpcClient(MessageBus.channel, MessageBus.exchangeName, MessageBus.routingKey, MessageBus.timeout) + val response = rpcClient.stringCall(inputScala) - suite.run(None, new KoanReporter(results), new Stopper {}, Filter(), scala.collection.immutable.Map[String, Any](), None, new Tracker) + val testResults = Json.parse[Map[String, TestResult]](response) - results + Ok(views.html.output(testResults)) + } + } getOrElse BadRequest } } \ No newline at end of file diff --git a/app/koanrunner/KoanRunner.scala b/app/koanrunner/KoanRunner.scala new file mode 100644 index 0000000..f197723 --- /dev/null +++ b/app/koanrunner/KoanRunner.scala @@ -0,0 +1,41 @@ +package koanrunner + +import messaging.MessageBus +import util.Properties +import com.rabbitmq.client.StringRpcServer +import support.KoanSuite +import com.twitter.util.Eval +import org.scalatest.{Filter, Tracker, Stopper} +import com.codahale.jerkson.Json + +import scala.collection.mutable.Map + +object KoanRunner extends App { + + Properties.envOrNone("RABBITMQ_URL") map { uri => + + MessageBus.setup(uri) + + val server: StringRpcServer = new StringRpcServer(MessageBus.channel, MessageBus.queueName) { + override def handleStringCall(request: String) = { + println("received: " + request) + + val suite = Eval[KoanSuite](request) + + val results = Map[String, TestResult]() + + suite.run(None, new KoanReporter(results), new Stopper {}, Filter(), scala.collection.immutable.Map[String, Any](), None, new Tracker) + + val json = Json.generate(results) + println("returning: " + json) + json + } + } + + server.mainloop() + + } getOrElse { + sys.error("RABBITMQ_URL environment variable not found") + } + +} diff --git a/app/messaging/MessageBus.scala b/app/messaging/MessageBus.scala new file mode 100644 index 0000000..0aaef14 --- /dev/null +++ b/app/messaging/MessageBus.scala @@ -0,0 +1,28 @@ +package messaging + +import com.rabbitmq.client.AMQP.BasicProperties +import com.rabbitmq.client.{RpcClient, ConnectionFactory, StringRpcServer, Channel} + + +object MessageBus { + + val exchangeName: String = "koan-exchange" + val routingKey: String = "koan-routing-key" + val exchangeType: String = "direct" + val timeout = 20000 + + var channel: Channel = _ + var queueName: String = _ + + def setup(uri: String) { + val factory = new ConnectionFactory() + factory.setUri(uri) + + val conn = factory.newConnection() + channel = conn.createChannel() + channel.exchangeDeclare(exchangeName, exchangeType, true) + queueName = channel.queueDeclare().getQueue + channel.queueBind(queueName, exchangeName, routingKey) + } + +} diff --git a/conf/application.conf b/conf/application.conf index 0375aab..bacdcb4 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -45,3 +45,4 @@ logger.play=INFO # Logger provided to your application: logger.application=DEBUG +rabbitmq.uri="amqp://guest:guest@localhost:5672/%2f" \ No newline at end of file diff --git a/project/Build.scala b/project/Build.scala index 75bb876..87ce0c7 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -4,16 +4,17 @@ import PlayProject._ object ApplicationBuild extends Build { - val appName = "scalaKoansOnline" - val appVersion = "1.0-SNAPSHOT" + val appName = "scalaKoansOnline" + val appVersion = "1.0-SNAPSHOT" - val appDependencies = Seq( - "com.twitter" % "util-eval" % "3.0.0", - "org.scalatest" %% "scalatest" % "1.7.1" - ) + val appDependencies = Seq( + "com.twitter" % "util-eval" % "3.0.0", + "org.scalatest" %% "scalatest" % "1.7.1", + "com.rabbitmq" % "amqp-client" % "2.8.1" + ) - val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings( - // Add your own project settings here - ) + val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings( + + ) }