Skip to content
Permalink
Browse files

Minor tweaks to UI functionality and replacement of powerscala-io wit…

…h migration of IO into youi-core with a few improvements
  • Loading branch information...
darkfrog26 committed Jun 29, 2019
1 parent 4e90c5d commit 90077296bd34c285af398456e8ec4c1b8ae7ded2
Showing with 356 additions and 28 deletions.
  1. +1 −1 app/jvm/src/main/scala/io/youi/app/ServerApplication.scala
  2. +5 −13 build.sbt
  3. +1 −1 client/jvm/src/main/scala/io/youi/client/JVMHttpClientImplementation.scala
  4. +1 −1 core/jvm/src/main/scala/io/youi/http/StreamZipContent.scala
  5. +1 −1 core/jvm/src/main/scala/io/youi/http/content/FileContent.scala
  6. +1 −1 core/jvm/src/main/scala/io/youi/http/content/URLContent.scala
  7. +75 −0 core/jvm/src/main/scala/io/youi/stream/IO.scala
  8. +23 −0 core/jvm/src/main/scala/io/youi/stream/Monitor.scala
  9. +7 −0 core/jvm/src/main/scala/io/youi/stream/Reader.scala
  10. +8 −0 core/jvm/src/main/scala/io/youi/stream/Writer.scala
  11. +93 −0 core/jvm/src/main/scala/io/youi/stream/package.scala
  12. +9 −0 core/jvm/src/main/scala/io/youi/stream/watcher/EventKind.scala
  13. +7 −0 core/jvm/src/main/scala/io/youi/stream/watcher/PathEvent.scala
  14. +107 −0 core/jvm/src/main/scala/io/youi/stream/watcher/Watcher.scala
  15. +1 −1 optimizer/src/main/scala/io/youi/optimizer/HTMLOptimizer.scala
  16. +1 −1 server/src/main/scala/io/youi/server/handler/ProxyCache.scala
  17. +1 −1 serverUndertow/src/main/scala/io/youi/server/UndertowServerImplementation.scala
  18. +1 −1 stream/src/main/scala/io/youi/stream/HTMLParser.scala
  19. +2 −2 ui/js/src/main/scala/io/youi/component/AbstractContainer.scala
  20. +1 −1 ui/js/src/main/scala/io/youi/component/extras/ComponentPosition.scala
  21. +7 −0 ui/js/src/main/scala/io/youi/component/extras/HTMLComponentPosition.scala
  22. +1 −1 utilities/src/main/scala/io/youi/util/GoogleFontBuilder.scala
  23. +1 −1 utilities/src/main/scala/io/youi/util/KeyBuilder.scala
  24. +1 −1 utilities/src/main/scala/io/youi/util/SwaggerClientBuilder.scala
@@ -13,7 +13,7 @@ import io.youi.stream.{ByTag, Delta, HTMLParser, Selector}
import io.youi.{ErrorSupport, JavaScriptError, JavaScriptLog, Priority, http}
import net.sf.uadetector.UserAgentType
import net.sf.uadetector.service.UADetectorServiceFactory
import org.powerscala.io._
import io.youi.stream._
import profig.{JsonUtil, Profig}
import reactify.{Channel, Var}

@@ -3,7 +3,7 @@ import sbtcrossproject.CrossPlugin.autoImport.crossProject

name := "youi"
organization in ThisBuild := "io.youi"
version in ThisBuild := "0.11.10"
version in ThisBuild := "0.11.11-SNAPSHOT"
scalaVersion in ThisBuild := "2.12.8"
crossScalaVersions in ThisBuild := List("2.12.8", "2.11.12")
resolvers in ThisBuild += Resolver.sonatypeRepo("releases")
@@ -28,7 +28,6 @@ developers in ThisBuild := List(

val profigVersion = "2.3.5"
val scribeVersion = "2.7.7"
val powerScalaVersion = "2.0.5"
val reactifyVersion = "3.0.3"
val hasherVersion = "1.2.1"
val hookupVersion = "2.0.2"
@@ -101,8 +100,7 @@ lazy val core = crossProject(JSPlatform, JVMPlatform).in(file("core"))
)
.jvmSettings(
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
"org.powerscala" %% "powerscala-io" % powerScalaVersion
"com.typesafe.akka" %% "akka-actor" % akkaVersion
)
)
.jsSettings(
@@ -125,8 +123,7 @@ lazy val client = crossProject(JSPlatform, JVMPlatform).in(file("client"))
)
.jvmSettings(
libraryDependencies ++= Seq(
"com.squareup.okhttp3" % "okhttp" % okHttpVersion,
"org.powerscala" %% "powerscala-io" % powerScalaVersion
"com.squareup.okhttp3" % "okhttp" % okHttpVersion
)
)
.dependsOn(core)
@@ -153,10 +150,7 @@ lazy val spatialJVM = spatial.jvm

lazy val stream = project.in(file("stream"))
.settings(
name := "youi-stream",
libraryDependencies ++= Seq(
"org.powerscala" %% "powerscala-io" % powerScalaVersion
)
name := "youi-stream"
)
.dependsOn(coreJVM)

@@ -222,7 +216,6 @@ lazy val optimizer = project.in(file("optimizer"))
fork := true,
libraryDependencies ++= Seq(
"com.google.javascript" % "closure-compiler" % closureCompilerVersion,
"org.powerscala" %% "powerscala-io" % powerScalaVersion,
"com.outr" %% "scribe" % scribeVersion,
"com.outr" %% "hasher" % hasherVersion
)
@@ -274,8 +267,7 @@ lazy val utilities = project.in(file("utilities"))
name := "youi-utilities",
fork := true,
libraryDependencies ++= Seq(
"org.jsoup" % "jsoup" % jSoupVersion,
"org.powerscala" %% "powerscala-io" % powerScalaVersion
"org.jsoup" % "jsoup" % jSoupVersion
)
)
.dependsOn(coreJVM)
@@ -10,7 +10,7 @@ import io.youi.http._
import io.youi.http.content._
import io.youi.net.ContentType
import okhttp3.Dns
import org.powerscala.io._
import io.youi.stream._

import scala.collection.JavaConverters._
import scala.concurrent.{ExecutionContext, Future, Promise}
@@ -5,7 +5,7 @@ import java.util.zip.{ZipEntry, ZipOutputStream}

import io.youi.http.content.Content
import io.youi.net.ContentType
import org.powerscala.io._
import io.youi.stream._

class StreamZipContent(entries: List[ZipFileEntry],
lastModified: Long = System.currentTimeMillis(),
@@ -3,7 +3,7 @@ package io.youi.http.content
import java.io.File

import io.youi.net.ContentType
import org.powerscala.io.IO
import io.youi.stream.IO

case class FileContent(file: File, contentType: ContentType, lastModifiedOverride: Option[Long] = None) extends Content {
assert(file.isFile, s"Cannot send back ${file.getAbsolutePath} as it is a directory or does not exist!")
@@ -3,7 +3,7 @@ package io.youi.http.content
import java.net.{HttpURLConnection, JarURLConnection, URL}

import io.youi.net.ContentType
import org.powerscala.io.IO
import io.youi.stream.IO
import sun.net.www.protocol.file.FileURLConnection

case class URLContent(url: URL, contentType: ContentType, lastModifiedOverride: Option[Long] = None) extends Content {
@@ -0,0 +1,75 @@
package io.youi.stream

import java.io.{File, IOException}

import scala.annotation.tailrec

object IO {
@tailrec
final def stream(reader: Reader,
writer: Writer,
monitor: Monitor = Monitor.Ignore,
buffer: Array[Byte] = new Array[Byte](512),
closeOnComplete: Boolean = true): Writer = {
monitor.open(reader.length)
val len = reader.read(buffer)
if (len == -1) {
writer.flush()
if (closeOnComplete) {
writer.close()
reader.close()
monitor.closed()
}
writer.complete()
monitor.completed()
writer
} else {
try {
writer.write(buffer, 0, len)
monitor.written(len)
} catch {
case t: Throwable => {
monitor.failure(t)
throw new IOException(s"IO failed to write to writer with length: $len with reader: $reader, writer: $writer.", t)
}
}
stream(reader, writer, monitor, buffer, closeOnComplete)
}
}

/**
* Uses IO.stream, but supports recursive directory copying.
*
* @param source file or directory
* @param destination file or directory
*/
def copy(source: File, destination: File): Unit = if (source.isDirectory) {
destination.mkdirs()
assert(destination.isDirectory, s"Destination ${destination.getAbsolutePath} is a file, not a directory!")
source.listFiles().foreach { file =>
copy(file, new File(destination, file.getName))
}
} else if (source.isFile) {
if (destination.isDirectory) {
stream(source, new File(destination, source.getName))
} else {
stream(source, destination)
}
}

def delete(file: File): Boolean = {
if (file.isDirectory) {
deleteFiles(file.listFiles().toList)
}
file.delete()
}

@tailrec
final def deleteFiles(files: List[File]): Unit = {
if (files.nonEmpty) {
val f = files.head
delete(f)
deleteFiles(files.tail)
}
}
}
@@ -0,0 +1,23 @@
package io.youi.stream

trait Monitor {
def open(length: Option[Long]): Unit
def written(length: Long): Unit
def failure(t: Throwable): Unit
def closed(): Unit
def completed(): Unit
}

object Monitor {
object Ignore extends Monitor {
override def open(length: Option[Long]): Unit = {}

override def written(length: Long): Unit = {}

override def failure(t: Throwable): Unit = {}

override def completed(): Unit = {}

override def closed(): Unit = {}
}
}
@@ -0,0 +1,7 @@
package io.youi.stream

trait Reader {
def length: Option[Long]
def read(buffer: Array[Byte]): Int
def close(): Unit
}
@@ -0,0 +1,8 @@
package io.youi.stream

trait Writer {
def write(buffer: Array[Byte], offset: Int, length: Int): Unit
def flush(): Unit
def complete(): Unit
def close(): Unit
}
@@ -0,0 +1,93 @@
package io.youi

import java.io.{ByteArrayInputStream, File, FileInputStream, FileOutputStream, InputStream, OutputStream}
import java.net.URL
import java.nio.file.{Files, Path}

import scala.language.implicitConversions

package object stream {
implicit class InputStreamReader(input: InputStream) extends Reader {
override def length: Option[Long] = None

override def read(buffer: Array[Byte]): Int = input.read(buffer)

override def close(): Unit = input.close()
}

implicit def javaReader2Reader(reader: java.io.Reader): Reader = new Reader {
override def length: Option[Long] = None

override def read(buffer: Array[Byte]): Int = {
val b = new Array[Char](buffer.length)
val len = reader.read(b)
b.zipWithIndex.foreach {
case (c, index) => buffer(index) = c.toByte
}
len
}

override def close(): Unit = reader.close()
}

implicit def file2Reader(file: File): InputStreamReader = new InputStreamReader(new FileInputStream(file)) {
override def length: Option[Long] = Some(file.length())
}

implicit def path2Reader(path: Path): InputStreamReader = file2Reader(path.toFile)

implicit def url2Reader(url: URL): InputStreamReader = {
val connection = url.openConnection()
val len = connection.getContentLengthLong
new InputStreamReader(connection.getInputStream) {
override def length: Option[Long] = len match {
case _ if len < 0 => None
case _ => Some(len)
}
}
}

implicit def youiURL2Reader(url: net.URL): InputStreamReader = url2Reader(new URL(url.toString))

implicit def string2Reader(s: String): InputStreamReader = new InputStreamReader(new ByteArrayInputStream(s.getBytes)) {
override def length: Option[Long] = Some(s.length)
}

implicit class OutputStreamWriter(output: OutputStream) extends Writer {
override def write(buffer: Array[Byte], offset: Int, length: Int): Unit = output.write(buffer, offset, length)

override def flush(): Unit = output.flush()

override def close(): Unit = output.close()

override def complete(): Unit = {}
}

implicit def file2Writer(file: File): OutputStreamWriter = {
val temp = new File(file.getParentFile, s".${file.getName}.temp")
new OutputStreamWriter(new FileOutputStream(temp)) {
override def complete(): Unit = {
super.complete()

file.delete() // Make sure the original file doesn't exist
temp.renameTo(file) // Two-stage write to avoid partials
}
}
}

implicit def path2Writer(path: Path): OutputStreamWriter = file2Writer(path.toFile)

implicit class StringBuilderWriter(sb: StringBuilder) extends Writer {
override def write(buffer: Array[Byte], offset: Int, length: Int): Unit = {
sb.append(new String(buffer, offset, length))
}

override def flush(): Unit = {}

override def close(): Unit = {}

override def complete(): Unit = {}

override def toString: String = sb.toString()
}
}
@@ -0,0 +1,9 @@
package io.youi.stream.watcher

sealed trait EventKind

object EventKind {
case object Create extends EventKind
case object Modify extends EventKind
case object Delete extends EventKind
}
@@ -0,0 +1,7 @@
package io.youi.stream.watcher

import java.nio.file.Path

case class PathEvent(path: Path, directory: Path, kinds: Set[EventKind], lastModified: Long) {
override def toString: String = s"PathEvent(path: $path, directory: $directory, kinds: $kinds, lastModified: $lastModified)"
}

0 comments on commit 9007729

Please sign in to comment.
You can’t perform that action at this time.