Permalink
Browse files

init

  • Loading branch information...
jamesward committed May 21, 2015
1 parent 4ef3567 commit 5cc050f0dab16e8cb14296d811a965df9616ca0b

This file was deleted.

Oops, something went wrong.
4 README

This file was deleted.

Oops, something went wrong.
@@ -0,0 +1,4 @@
import play.api.mvc.WithFilters
import play.filters.gzip.GzipFilter

object Global extends WithFilters(new GzipFilter(1000 * 1024))
@@ -1,12 +1,124 @@
package controllers

import java.io.{FileNotFoundException, BufferedInputStream}

import org.joda.time.DateTimeZone
import org.joda.time.format.{DateTimeFormat, DateTimeFormatter}
import play.api.libs.json.Json
import utils.MavenCentral
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import play.api._
import play.api.libs.MimeTypes
import play.api.mvc._
import play.api.Play.current

import utils.MavenCentral.UnexpectedResponseException

import scala.util.{Failure, Success}

object Application extends Controller {

def index = Action {
Ok(views.html.index("Your new application is ready."))
def file(groupId: String, artifactId: String, webJarVersion: String, file: String) = CorsAction {
Action.async { request =>
val pathPrefix = s"META-INF/resources/webjars/$artifactId/"

Future.fromTry {
MavenCentral.getFile(groupId, artifactId, webJarVersion).map { case (jarInputStream, inputStream) =>
Stream.continually(jarInputStream.getNextJarEntry).takeWhile(_ != null).find { jarEntry =>
// this allows for sloppyness where the webJarVersion and path differ
// todo: eventually be more strict but since this has been allowed many WebJars do not have version and path consistency
jarEntry.getName.startsWith(pathPrefix) && jarEntry.getName.endsWith(s"/$file")
}.fold {
jarInputStream.close()
inputStream.close()
NotFound(s"Found WebJar ($groupId : $artifactId : $webJarVersion) but could not find: $pathPrefix$webJarVersion/$file")
} { jarEntry =>
val bis = new BufferedInputStream(jarInputStream)
val bArray = Stream.continually(bis.read).takeWhile(_ != -1).map(_.toByte).toArray
bis.close()
jarInputStream.close()
inputStream.close()

//// From Play's Assets controller
val contentType = MimeTypes.forFileName(file).map(m => m + addCharsetIfNeeded(m)).getOrElse(BINARY)
////

Ok(bArray).as(contentType).withHeaders(
CACHE_CONTROL -> "max-age=290304000, public",
DATE -> df.print((new java.util.Date).getTime),
LAST_MODIFIED -> df.print(jarEntry.getLastModifiedTime.toMillis)
)
}
}
} recover {
case nf: FileNotFoundException =>
NotFound(s"WebJar Not Found $groupId : $artifactId : $webJarVersion")
case ure: UnexpectedResponseException =>
Status(ure.response.status)(s"Problems retrieving WebJar ($groupId : $artifactId : $webJarVersion) - ${ure.response.statusText}")
case e: Exception =>
InternalServerError(s"Could not find WebJar ($groupId : $artifactId : $webJarVersion)\n${e.getMessage}")
}
}
}

def fileOptions(file: String) = CorsAction {
Action { request =>
Ok.withHeaders(ACCESS_CONTROL_ALLOW_HEADERS -> Seq(CONTENT_TYPE).mkString(","))
}
}

def listFiles(groupId: String, artifactId: String, version: String) = CorsAction {
Action {
MavenCentral.fetchFileList(groupId, artifactId, version) match {
case Success(fileList) =>
Ok(Json.toJson(fileList))
case Failure(e: FileNotFoundException) =>
NotFound(s"WebJar Not Found $groupId : $artifactId : $version")
case Failure(ure: UnexpectedResponseException) =>
Status(ure.response.status)(s"Problems retrieving WebJar ($groupId : $artifactId : $version) - ${ure.response.statusText}")
case Failure(e) =>
InternalServerError(e.getMessage)
}
}
}

case class CorsAction[A](action: Action[A]) extends Action[A] {

def apply(request: Request[A]): Future[Result] = {
action(request).map(result => result.withHeaders(ACCESS_CONTROL_ALLOW_ORIGIN -> "*"))
}

lazy val parser = action.parser
}

def corsPreflight(path: String) = Action {
Ok.withHeaders(
ACCESS_CONTROL_ALLOW_ORIGIN -> "*",
ACCESS_CONTROL_ALLOW_METHODS -> "GET"
)
}


//// From Play's Asset controller

private val timeZoneCode = "GMT"

//Dateformatter is immutable and threadsafe
private val df: DateTimeFormatter =
DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss '" + timeZoneCode + "'").withLocale(java.util.Locale.ENGLISH).withZone(DateTimeZone.forID(timeZoneCode))

//Dateformatter is immutable and threadsafe
private val dfp: DateTimeFormatter =
DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss").withLocale(java.util.Locale.ENGLISH).withZone(DateTimeZone.forID(timeZoneCode))

private lazy val defaultCharSet = Play.configuration.getString("default.charset").getOrElse("utf-8")

private def addCharsetIfNeeded(mimeType: String): String =
if (MimeTypes.isText(mimeType))
"; charset=" + defaultCharSet
else ""

////

}
@@ -0,0 +1,74 @@
package utils

import java.io.{File, InputStream}
import java.net.{URLEncoder, URL}
import java.nio.file.Files
import java.util.jar.JarInputStream

import org.webjars.WebJarAssetLocator
import play.api.Play
import play.api.libs.ws.WSResponse

import scala.util.{Success, Try}

object MavenCentral {

lazy val tempDir: File = Files.createTempDirectory("webjars").toFile

val primaryBaseJarUrl = Play.current.configuration.getString("webjars.jarUrl.primary").get
val fallbackBaseJarUrl = Play.current.configuration.getString("webjars.jarUrl.fallback").get

def getFile(groupId: String, artifactId: String, version: String): Try[(JarInputStream, InputStream)] = {
val tmpFile = new File(tempDir, s"$groupId-$artifactId-$version.jar")

if (tmpFile.exists()) {
val fileInputStream = Files.newInputStream(tmpFile.toPath)
Success((new JarInputStream(fileInputStream), fileInputStream))
}
else {
val fileInputStreamFuture = getFileInputStream(primaryBaseJarUrl, groupId, artifactId, version).recoverWith {
case _ =>
getFileInputStream(fallbackBaseJarUrl, groupId, artifactId, version)
}

fileInputStreamFuture.map { fileInputStream =>
// todo: not thread safe!
// write to the fs
Files.copy(fileInputStream, tmpFile.toPath)
fileInputStream.close()

val tmpFileInputStream = Files.newInputStream(tmpFile.toPath)
// read it from the fs since we've drained the http response
(new JarInputStream(tmpFileInputStream), tmpFileInputStream)
}
}
}

def getFileInputStream(baseJarUrl: String, groupId: String, artifactId: String, version: String): Try[InputStream] = {
Try {
val url = new URL(baseJarUrl.format(groupId.replace(".", "/"), artifactId, URLEncoder.encode(version, "UTF-8"), artifactId, URLEncoder.encode(version, "UTF-8")))
url.openConnection().getInputStream
}
}


def fetchFileList(groupId: String, artifactId: String, version: String): Try[List[String]] = {
getFile(groupId, artifactId, version).map { case (jarInputStream, inputStream) =>
val webJarFiles = Stream.continually(jarInputStream.getNextJarEntry).
takeWhile(_ != null).
filterNot(_.isDirectory).
map(_.getName).
filter(_.startsWith(WebJarAssetLocator.WEBJARS_PATH_PREFIX)).
toList
jarInputStream.close()
inputStream.close()
webJarFiles
}
}

case class UnexpectedResponseException(response: WSResponse) extends RuntimeException {
override def getMessage: String = response.statusText
}

}

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
@@ -7,8 +7,19 @@ lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
jdbc,
anorm,
cache,
ws
ws,
filters,
"org.webjars" %% "webjars-play" % "2.3.0-3"
)

javacOptions ++= Seq("-source", "1.8", "-target", "1.8")

onLoad in Global := (onLoad in Global).value.andThen { state =>
if (sys.props("java.specification.version") != "1.8") {
sys.error("Java 8 is required for this project.")
state.exit(ok = false)
}
else {
state
}
}
@@ -8,7 +8,7 @@
# This must be changed for production, but we recommend not changing it in this file.
#
# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
application.secret=">3RdZ3P>Pl>fcAwE`CII]i;GpiyEO_@iJtnPc4AHH5cuAf=3Dh3@ZF/`9[?v3u/W"
application.secret="changeme"

# The application languages
# ~~~~~
@@ -60,3 +60,5 @@ logger.play=INFO
# Logger provided to your application:
logger.application=DEBUG

webjars.jarUrl.primary="http://repo1.maven.org/maven2/%s/%s/%s/%s-%s.jar"
webjars.jarUrl.fallback="http://uk.maven.org/maven2/%s/%s/%s/%s-%s.jar"
@@ -2,8 +2,13 @@
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET / controllers.Application.index
GET /files/org.webjars/:artifactId/:version/*file controllers.Application.file(groupId = "org.webjars", artifactId, version, file)
GET /files/org.webjars.bower/:artifactId/:version/*file controllers.Application.file(groupId = "org.webjars.bower", artifactId, version, file)
GET /files/org.webjars.npm/:artifactId/:version/*file controllers.Application.file(groupId = "org.webjars.npm", artifactId, version, file)
GET /files/:artifactId/:version/*file controllers.Application.file(groupId = "org.webjars", artifactId, version, file)
OPTIONS /files/*file controllers.Application.fileOptions(file)

# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
GET /listfiles/:artifactId/:version controllers.Application.listFiles(groupId = "org.webjars", artifactId, version)
GET /listfiles/:groupId/:artifactId/:version controllers.Application.listFiles(groupId, artifactId, version)

OPTIONS /*path controllers.Application.corsPreflight(path: String)
@@ -1,4 +1,4 @@
#Activator-generated Properties
#Fri May 22 15:37:13 MDT 2015
#Thu May 21 11:33:58 MDT 2015
template.uuid=8c85e1d5-e23e-4b73-b401-1ebbb916198b
sbt.version=0.13.8
@@ -1,18 +1,4 @@
resolvers += "Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/"

// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.9")

// web plugins

addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.6")

addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.3")

addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.7")

addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.0.2")
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.9")
BIN -687 Bytes public/images/favicon.png
Binary file not shown.

This file was deleted.

Oops, something went wrong.
No changes.

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.

0 comments on commit 5cc050f

Please sign in to comment.