summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlihaoyi <haoyi.sg@gmail.com>2013-11-17 16:22:30 -0800
committerlihaoyi <haoyi.sg@gmail.com>2013-11-17 16:22:30 -0800
commitf48a24f376bc97064a9679f3b80b266e24cc76ba (patch)
tree53adf12615ba0947658981f0c27d094dff6fdf43
parent12d6290b225dbec02bc04b13d14a2a29132e7da2 (diff)
downloadworkbench-f48a24f376bc97064a9679f3b80b266e24cc76ba.tar.gz
workbench-f48a24f376bc97064a9679f3b80b266e24cc76ba.tar.bz2
workbench-f48a24f376bc97064a9679f3b80b266e24cc76ba.zip
first real commit
-rw-r--r--package.scala112
-rw-r--r--plugin/build.sbt6
-rw-r--r--plugin/src/main/scala/scala/scalajs/js/resource/Plugin.scala54
-rw-r--r--project/Build.scala21
-rw-r--r--project/plugins.sbt1
-rw-r--r--runtime/build.sbt1
-rw-r--r--runtime/project/plugins.sbt1
-rw-r--r--runtime/src/main/scala/scala/scalajs/js/Resource.scala30
-rw-r--r--workbench_template.js25
9 files changed, 154 insertions, 97 deletions
diff --git a/package.scala b/package.scala
new file mode 100644
index 0000000..cee84bc
--- /dev/null
+++ b/package.scala
@@ -0,0 +1,112 @@
+package scala.js
+
+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
+
+package object workbench extends sbt.Plugin {
+ val refreshBrowsers = taskKey[Unit]("Sends a message to all connected web pages asking them to refresh the page")
+ 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")
+
+ 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", message))
+ def trace(t: => Throwable): Unit = server.value.send(Json.arr("print", t.toString))
+ }
+ }
+ val currentFunction = extraLoggers.value
+ (key: ScopedKey[_]) => clientLogger +: currentFunction(key)
+ },
+ refreshBrowsers := {
+ streams.value.log("Reloading Pages...")
+ server.value.send(Json.arr("reload"))
+ },
+ generateClient := {
+ val clientTemplate = IO.readStream(getClass.getClassLoader.getResourceAsStream("workbench_template.js"))
+ val transformed = clientTemplate.replace("<host>", localUrl.value._1).replace("<port>", localUrl.value._2.toString)
+ val outputFile = (crossTarget in Compile).value / fileName.value
+ IO.write(outputFile, transformed)
+ outputFile
+ }
+ )
+
+ 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)
+
+ 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 =>
+ }
+ }
+}
diff --git a/plugin/build.sbt b/plugin/build.sbt
deleted file mode 100644
index 554cd1b..0000000
--- a/plugin/build.sbt
+++ /dev/null
@@ -1,6 +0,0 @@
-sbtPlugin := true
-
-
-addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.1-SNAPSHOT")
-
-libraryDependencies += "commons-codec" % "commons-codec" % "1.8"
diff --git a/plugin/src/main/scala/scala/scalajs/js/resource/Plugin.scala b/plugin/src/main/scala/scala/scalajs/js/resource/Plugin.scala
deleted file mode 100644
index c8960c8..0000000
--- a/plugin/src/main/scala/scala/scalajs/js/resource/Plugin.scala
+++ /dev/null
@@ -1,54 +0,0 @@
-package scala.scalajs.js.resource
-
-import sbt._
-import Keys._
-import scala.scalajs.sbtplugin.ScalaJSPlugin.ScalaJSKeys._
-import org.apache.commons.codec.binary.Base64
-
-
-object Plugin extends sbt.Plugin {
-
- val resourceSettings = Seq(
- watchSources := {
- watchSources.value ++ (resources in Compile).value ++ Path.allSubpaths((sourceDirectory in Compile).value / "js").map(_._1).toSeq
- },
- packageJS := {
- val bundledJSResults: Set[sbt.File] = FileFunction.cached(
- cacheDirectory.value,
- FilesInfo.lastModified,
- FilesInfo.exists
- ){(inFiles: Set[File]) =>
- val pathMap = Path.relativeTo((resources in Compile).value)
- val bundle = crossTarget.value / "resources.js"
- val fileLines = for(file <- inFiles) yield {
- val b64 = Base64.encodeBase64String(IO.readBytes(file))
- " \"" + pathMap(file).get + "\": \"" + b64 + "\""
- }
- IO.write(bundle, "\nScalaJS.resources = {\n" + fileLines.mkString(",\n") + "\n}" )
- Set(bundle)
- }(
- for{
- (resourceRoot: File) <- (resources in Compile).value.toSet
- (file, path) <- Path.allSubpaths(resourceRoot)
- } yield file
- )
-
- val copiedJSFiles = FileFunction.cached(
- cacheDirectory.value,
- FilesInfo.lastModified,
- FilesInfo.exists
- ){(inFiles: Set[File]) =>
- val pathMap = Path.relativeTo((sourceDirectory in Compile).value / "js")
- IO.copy(inFiles.map{f => f -> crossTarget.value / pathMap(f).get})
- }(
- for{
- (file, path) <- Path.allSubpaths((sourceDirectory in Compile).value / "js").toSet
- } yield file
-
- )
- val normalResults: Seq[sbt.File] = (packageJS in Compile).value
-
- normalResults ++ bundledJSResults ++ copiedJSFiles
- }
- )
-}
diff --git a/project/Build.scala b/project/Build.scala
index 50dda40..726d8fd 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -1,10 +1,23 @@
import sbt._
+import Keys._
+
object Build extends sbt.Build {
import sbt._
- lazy val runtime = Project("runtime", file("runtime"))
- lazy val plugin = Project("plugin", file("plugin"))
-
-
+ override lazy val projects = Seq(root)
+ lazy val root =
+ Project("scala-js-workbench", file("."))
+ .dependsOn(uri("../WebSockets"))
+ .settings(
+ sbtPlugin := true,
+ (resources in Compile) := {(resources in Compile).value ++ (baseDirectory.value * "*.js").get},
+ resolvers += "spray repo" at "http://repo.spray.io",
+ resolvers += "typesafe" at "http://repo.typesafe.com/typesafe/releases/",
+ libraryDependencies ++= Seq(
+ "io.spray" % "spray-can" % "1.2-RC3",
+ "com.typesafe.akka" %% "akka-actor" % "2.2.3",
+ "com.typesafe.play" %% "play-json" % "2.2.0-RC1"
+ )
+ )
} \ No newline at end of file
diff --git a/project/plugins.sbt b/project/plugins.sbt
deleted file mode 100644
index 142a3c7..0000000
--- a/project/plugins.sbt
+++ /dev/null
@@ -1 +0,0 @@
-addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.1-SNAPSHOT") \ No newline at end of file
diff --git a/runtime/build.sbt b/runtime/build.sbt
deleted file mode 100644
index fa2803f..0000000
--- a/runtime/build.sbt
+++ /dev/null
@@ -1 +0,0 @@
-scalaJSSettings \ No newline at end of file
diff --git a/runtime/project/plugins.sbt b/runtime/project/plugins.sbt
deleted file mode 100644
index 142a3c7..0000000
--- a/runtime/project/plugins.sbt
+++ /dev/null
@@ -1 +0,0 @@
-addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.1-SNAPSHOT") \ No newline at end of file
diff --git a/runtime/src/main/scala/scala/scalajs/js/Resource.scala b/runtime/src/main/scala/scala/scalajs/js/Resource.scala
deleted file mode 100644
index 632ebb9..0000000
--- a/runtime/src/main/scala/scala/scalajs/js/Resource.scala
+++ /dev/null
@@ -1,30 +0,0 @@
-package scala.scalajs
-package js
-
-
-object Resource {
- println("Resource")
- val fileDict = {
- val fileDict = js.Dynamic.global.ScalaJS.resources.asInstanceOf[js.Object]
- for(key <- js.Object.keys(fileDict)){
- val data = fileDict.asInstanceOf[js.Dictionary](key).asInstanceOf[String]
- fileDict.asInstanceOf[js.Dictionary](key) = new Resource(data).asInstanceOf[js.Any]
- }
- fileDict
- }
-
- println("Resource Initialized")
- def apply(path: String) = {
- js.Dynamic.global
- .ScalaJS
- .resources
- .asInstanceOf[js.Dictionary]
- .apply(path)
- .asInstanceOf[Resource]
- }
- def create(value: String) = new Resource(value)
-}
-
-class Resource(base64: String){
- lazy val string = js.Dynamic.global.atob(base64).asInstanceOf[js.String]
-} \ No newline at end of file
diff --git a/workbench_template.js b/workbench_template.js
new file mode 100644
index 0000000..e5ae48d
--- /dev/null
+++ b/workbench_template.js
@@ -0,0 +1,25 @@
+var socket = (function(){
+ var open = false
+ var start = function(){
+ socket = new WebSocket("ws://<host>:<port>/")
+ socket.onopen = function(event){
+ open = true
+ console.log("Host connection Opened")
+ }
+ socket.onmessage = function(event){
+ var data = JSON.parse(event.data)
+ if (data[0] == "reload") {
+ console.log("Reloading page...")
+ location.reload(true)
+ }
+ if (data[0] == "print") console[data[1]](data[2])
+ }
+ socket.onclose = function(event){
+ if (open) console.log("Host connection Closed")
+ open = false
+ setTimeout(function(){start()}, 1000)
+ }
+ }
+ start()
+ return socket
+})()