summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-02-15 19:23:13 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-02-15 19:23:13 -0800
commit87b9753514c627ed89b4343db159f378fa583cb1 (patch)
treeb3504a6b67f7e0428f2fc558a300304f235f1272
parentea92879d7f521c27d829101a8f79c125f73339d2 (diff)
downloadworkbench-87b9753514c627ed89b4343db159f378fa583cb1.tar.gz
workbench-87b9753514c627ed89b4343db159f378fa583cb1.tar.bz2
workbench-87b9753514c627ed89b4343db159f378fa583cb1.zip
add ocde
-rw-r--r--Plugin.scala131
1 files changed, 131 insertions, 0 deletions
diff --git a/Plugin.scala b/Plugin.scala
new file mode 100644
index 0000000..d6cea03
--- /dev/null
+++ b/Plugin.scala
@@ -0,0 +1,131 @@
+package scala.js.workbench
+
+import akka.actor.{Props, ActorRef, Actor, ActorSystem}
+import akka.io
+import akka.util.ByteString
+import play.api.libs.json.JsArray
+
+import play.api.libs.json.Json
+import spray.can.Http
+import spray.can.server.websockets.model.Frame
+import spray.can.server.websockets.model.OpCode
+import spray.can.server.websockets.Sockets
+import sbt._
+import Keys._
+
+import com.typesafe.config.ConfigFactory
+import scala.collection.mutable
+import akka.io.Tcp
+import spray.http.{StatusCodes, HttpResponse, HttpRequest}
+import spray.http.HttpHeaders.Connection
+import spray.can.server.websockets.model.OpCode.Text
+
+object Plugin extends sbt.Plugin {
+ val refreshBrowsers = taskKey[Unit]("Sends a message to all connected web pages asking them to refresh the page")
+ val updateBrowsers = taskKey[Unit]("partially resets some of the stuff in the browser")
+ val generateClient = taskKey[File]("generates a .js file that can be embedded in your web page")
+ val localUrl = settingKey[(String, Int)]("localUrl")
+ val server = settingKey[ActorRef]("local websocket server")
+ val fileName = settingKey[String]("name of the generated javascript file")
+ val bootSnippet = settingKey[String]("piece of javascript to make things happen")
+ implicit val system = ActorSystem(
+ "SystemLol",
+ config = ConfigFactory.load(ActorSystem.getClass.getClassLoader),
+ classLoader = ActorSystem.getClass.getClassLoader
+ )
+
+ implicit class pimpedActor(server: ActorRef){
+ def send(x: JsArray) = {
+ server ! Frame(
+ opcode = OpCode.Text,
+ data = ByteString(x.toString())
+ )
+ }
+ }
+
+ val buildSettingsX = Seq(
+ localUrl := ("localhost", 12345),
+ fileName := "workbench.js",
+ server := {
+ implicit val server = system.actorOf(Props(new SocketServer()))
+ val host = localUrl.value
+ io.IO(Sockets) ! Http.Bind(server, host._1, host._2)
+ server
+ },
+
+ extraLoggers := {
+ val clientLogger = FullLogger{
+ new Logger {
+ def log(level: Level.Value, message: => String): Unit =
+ if(level >= Level.Info) server.value.send(Json.arr("print", level.toString(), message))
+ def success(message: => String): Unit = server.value.send(Json.arr("print", "info", message))
+ def trace(t: => Throwable): Unit = server.value.send(Json.arr("print", "error", t.toString))
+ }
+ }
+ clientLogger.setSuccessEnabled(true)
+ val currentFunction = extraLoggers.value
+ (key: ScopedKey[_]) => clientLogger +: currentFunction(key)
+ },
+ refreshBrowsers := {
+ streams.value.log.info("workbench: Reloading Pages...")
+ server.value.send(Json.arr("reload"))
+ },
+ updateBrowsers := {
+
+ server.value send Json.arr("clear")
+ ((crossTarget in Compile).value * "*.js").get.map{ (x: File) =>
+ streams.value.log.info("workbench: Checking " + x.getName)
+ FileFunction.cached(streams.value.cacheDirectory / x.getName, FilesInfo.lastModified, FilesInfo.lastModified){ (f: Set[File]) =>
+ streams.value.log.info("workbench: Refreshing " + x.getName)
+ server.value send Json.arr("run", f.head.getAbsolutePath, bootSnippet.value)
+ f
+ }(Set(x))
+ }
+ },
+ generateClient := {
+ FileFunction.cached(streams.value.cacheDirectory / "workbench"/ "workbench.js", FilesInfo.full, FilesInfo.exists){ (f: Set[File]) =>
+ val transformed =
+ IO.read(f.head)
+ .replace("<host>", localUrl.value._1)
+ .replace("<port>", localUrl.value._2.toString)
+ .replace("<bootSnippet>", bootSnippet.value)
+ val outputFile = (crossTarget in Compile).value / fileName.value
+ IO.write(outputFile, transformed)
+ Set(outputFile)
+ }(Set(new File(getClass.getClassLoader.getResource("workbench_template.ts").toURI))).head
+ }
+ )
+
+ class SocketServer() extends Actor{
+ val sockets: mutable.Set[ActorRef] = mutable.Set.empty
+ def receive = {
+ case x: Tcp.Connected => sender ! Tcp.Register(self) // normal Http server init
+
+ case req: HttpRequest =>
+ // Upgrade the connection to websockets if you think the incoming
+ // request looks good
+ if (req.headers.contains(Connection("Upgrade"))){
+ sender ! Sockets.UpgradeServer(Sockets.acceptAllFunction(req), self)
+ }else{
+ sender ! HttpResponse(
+ StatusCodes.OK,
+ entity="i am a cow"
+ )
+ }
+
+ case Sockets.Upgraded =>
+ sockets.add(sender)
+ println("Browser Open n=" + sockets.size)
+ self send Json.arr("boot")
+
+ case f @ Frame(fin, rsv, Text, maskingKey, data) =>
+ sockets.foreach(_ ! f.copy(maskingKey=None))
+
+ case _: Tcp.ConnectionClosed =>
+ if (sockets.contains(sender)) println("Browser Closed n=" + sockets.size )
+ sockets.remove(sender)
+
+ case x =>
+ }
+ }
+}