Skip to content
This repository has been archived by the owner on Dec 10, 2018. It is now read-only.

Commit

Permalink
Merge 1f8d212 into 3816587
Browse files Browse the repository at this point in the history
  • Loading branch information
maizy committed May 15, 2016
2 parents 3816587 + 1f8d212 commit f0064c0
Show file tree
Hide file tree
Showing 25 changed files with 566 additions and 105 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ _TBA_
Dev requirements: node 4.1+, npm 2.5+.

Run server in dev mode
`sbt -DassetsMode=dev server/run`
`sbt -DassetsMode=dev -Dlogback.configurationFile=server/src/main/etc/logback.dev.xml server/run`

Compile assets:
`sbt server/compile:assets`
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/scala/ru/maizy/cheesecake/api/Stub.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ package ru.maizy.cheesecake.api
* See LICENSE.txt for details.
*/

case class Stub(val name: String) // FIXME: tmp
case class Stub(stub: String) // FIXME: tmp
65 changes: 43 additions & 22 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,50 @@ lazy val commonSettings = Seq(
version := "0.0.2",
scalaVersion := "2.11.8",
scalacOptions ++= Seq(
"-target:jvm-1.8",
"-encoding", "UTF-8",
"-deprecation",
"-unchecked",
"-explaintypes",
"-Xfatal-warnings",
"-Xlint:_",
"-Ywarn-dead-code",
"-Ywarn-inaccessible",
"-Ywarn-infer-any",
"-Ywarn-nullary-override",
"-Ywarn-nullary-unit",
"-Ywarn-numeric-widen",
"-Ywarn-unused",
"-Ywarn-unused-import"
"-target:jvm-1.8",
"-encoding", "UTF-8",
"-deprecation",
"-unchecked",
"-explaintypes",
"-Xfatal-warnings",
"-Xlint:_",
"-Ywarn-dead-code",
"-Ywarn-inaccessible",
"-Ywarn-infer-any",
"-Ywarn-nullary-override",
"-Ywarn-nullary-unit",
"-Ywarn-numeric-widen",
"-Ywarn-unused",
"-Ywarn-unused-import"
)
)

lazy val api = project.
in(file("api")).
settings(commonSettings: _*)
lazy val commonDependencies = Seq(
libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.3.0",
"org.scalatest" %% "scalatest" % "2.2.6" % "test"
)
)

lazy val core = project
.in(file("core"))
.settings(commonDependencies: _*)
.settings(commonSettings: _*)

lazy val api = project
.in(file("api"))
.settings(commonSettings: _*)

lazy val client = project
.in(file("client"))
.settings(commonDependencies: _*)
.settings(commonSettings: _*)
.dependsOn(core)
.dependsOn(api)

lazy val server = project.
in(file("server")).
settings(commonSettings: _*).
dependsOn(api)
lazy val server = project
.in(file("server"))
.settings(commonDependencies: _*)
.settings(commonSettings: _*)
.dependsOn(core)
.dependsOn(api)
10 changes: 10 additions & 0 deletions client/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name := "cheesecake-client"


// Scalastyle setup
lazy val testScalastyle = taskKey[Unit]("testScalastyle")
lazy val testScalastyleInCompile = taskKey[Unit]("testScalastyleInCompile")
testScalastyle := org.scalastyle.sbt.ScalastylePlugin.scalastyle.in(Test).toTask("").value
testScalastyleInCompile := org.scalastyle.sbt.ScalastylePlugin.scalastyle.in(Compile).toTask("").value
(test in Test) <<= (test in Test) dependsOn (testScalastyle, testScalastyleInCompile)
scalastyleFailOnError := true
11 changes: 11 additions & 0 deletions client/src/main/scala/ru/maizy/cheesecake/client/Stub.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ru.maizy.cheesecake.client

import ru.maizy.cheesecake.api
import ru.maizy.cheesecake.core.utils.CollectionsUtils

/**
* Copyright (c) Nikita Kovaliov, maizy.ru, 2016
* See LICENSE.txt for details.
*/

case class Stub(stub: String, apiDep: api.Stub, coreDep: CollectionsUtils.type) // FIXME: tmp
9 changes: 9 additions & 0 deletions core/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name := "cheesecake-core"

// Scalastyle setup
lazy val testScalastyle = taskKey[Unit]("testScalastyle")
lazy val testScalastyleInCompile = taskKey[Unit]("testScalastyleInCompile")
testScalastyle := org.scalastyle.sbt.ScalastylePlugin.scalastyle.in(Test).toTask("").value
testScalastyleInCompile := org.scalastyle.sbt.ScalastylePlugin.scalastyle.in(Compile).toTask("").value
(test in Test) <<= (test in Test) dependsOn (testScalastyle, testScalastyleInCompile)
scalastyleFailOnError := true
122 changes: 122 additions & 0 deletions core/src/main/scala/ru/maizy/cheesecake/core/RichTypesafeConfig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package ru.maizy.cheesecake.core

/**
* Copyright (c) Nikita Kovaliov, maizy.ru, 2016
* See LICENSE.txt for details.
*/

import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.JavaConverters.asScalaSetConverter
import scala.util.{ Failure, Success, Try }
import com.typesafe.config.{ Config, ConfigException, ConfigObject }

object RichTypesafeConfig {

type WarnMessages = Seq[String]
case class ConfigLookupResults[T](result: T, warnings: WarnMessages)

sealed trait ConfigError {
def errorMessage: String
override def toString: String = errorMessage
}
case class MissingValue(errorMessage: String) extends ConfigError
case class WrongType(errorMessage: String) extends ConfigError
case class UnknownError(errorMessage: String, cause: Option[Throwable] = None) extends ConfigError

private def wrapExceptionToEitherWithEmptyForMissing[T](
path: String,
typeName: String,
empty: T)(getter: String => T): Either[ConfigError, T] = {

Try(getter(path)) match {
case Failure(e: ConfigException.Missing) =>
Right(empty)
case Failure(e: ConfigException.WrongType) =>
Left(WrongType(s"value for path `$path` isn't $typeName"))
case Failure(e: Throwable) =>
Left(UnknownError(s"unable to get value for path `$path`: $e", Some(e)))
case Success(c) => Right(c)
}
}

private def wrapExceptionToEither[T](path: String, typeName: String)(getter: String => T): Either[ConfigError, T] = {
Try(getter(path)) match {
case Failure(e: ConfigException.Missing) =>
Left(MissingValue(s"value for path `$path` is missing"))
case Failure(e: ConfigException.WrongType) =>
Left(WrongType(s"value for path `$path` isn't $typeName"))
case Failure(e: Throwable) =>
Left(UnknownError(s"unable to get value for path `$path`: $e", Some(e)))
case Success(c) => Right(c)
}
}

implicit class ConfigListImplicits(val config: Config) extends AnyVal {

@throws[ConfigException]
def asScalaConfigList(path: String): IndexedSeq[Config] = config.getConfigList(path).toIndexedSeq

def eitherConfigList(path: String, allowEmpty: Boolean = false): Either[ConfigError, IndexedSeq[Config]] =
wrapExceptionToEitherWithEmptyForMissing[IndexedSeq[Config]](path, "list", IndexedSeq.empty) { asScalaConfigList }

def optConfigList(path: String, allowEmpty: Boolean = false): Option[IndexedSeq[Config]] =
eitherConfigList(path, allowEmpty).right.toOption
}


implicit class StringImplicits(val config: Config) extends AnyVal {

def eitherString(path: String): Either[ConfigError, String] =
wrapExceptionToEither(path, "string") { config.getString }

def optString(path: String): Option[String] = eitherString(path).right.toOption
}


implicit class IntImplicits(val config: Config) extends AnyVal {

def eitherInt(path: String): Either[ConfigError, Int] =
wrapExceptionToEither(path, "int") { config.getInt }

def optInt(path: String): Option[Int] = eitherInt(path).right.toOption
}

implicit class ObjectImplicits(val config: Config) extends AnyVal {

def eitherObject(path: String): Either[ConfigError, ConfigObject] =
wrapExceptionToEither(path, "object") { config.getObject }

def optObject(path: String): Option[ConfigObject] = eitherObject(path).right.toOption

def eitherStringMapWithWarnings(path: String): ConfigLookupResults[Either[ConfigError, Map[String, String]]] = {
eitherObject(path) match {
case Right(obj) =>
val entiries = obj.entrySet.asScala.toIndexedSeq
ConfigLookupResults(
Right(
entiries
.filter(_.getValue.unwrapped.isInstanceOf[String])
.map(e => (e.getKey, e.getValue.unwrapped.asInstanceOf[String]))
.toMap
),
entiries
.filterNot(_.getValue.unwrapped.isInstanceOf[String])
.map(wrongValue => s"Value for `${wrongValue.getKey}` isn't string")
)
case Left(error) => ConfigLookupResults(Left(error), Seq.empty)
}
}

def eitherStringMap(path: String): Either[ConfigError, Map[String, String]] =
eitherStringMapWithWarnings(path).result

def optStringMapWithWarnings(path: String): ConfigLookupResults[Option[Map[String, String]]] = {
val eitherMapResults = eitherStringMapWithWarnings(path)
ConfigLookupResults(eitherMapResults.result.right.toOption, eitherMapResults.warnings)
}

def optStringMap(path: String): Option[Map[String, String]] = optStringMapWithWarnings(path).result
}


}
7 changes: 4 additions & 3 deletions server/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ val humanizeDuration = "3.7.1"

libraryDependencies ++= Seq(
"ch.qos.logback" % "logback-classic" % "1.1.3",
"com.github.scopt" %% "scopt" % "3.3.0",
"com.typesafe.scala-logging" %% "scala-logging" % "3.4.0",
"com.github.scopt" %% "scopt" % "3.4.0",
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
"com.typesafe.akka" %% "akka-slf4j" % akkaVersion,
"com.typesafe.akka" %% "akka-stream" % akkaStreamsVersion,
"com.typesafe.akka" %% "akka-http-core" % akkaStreamsVersion,
"com.typesafe.akka" %% "akka-http-experimental" % akkaStreamsVersion,
"com.typesafe.akka" %% "akka-http-spray-json-experimental" % akkaStreamsVersion,
"com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test",
"org.scalatest" %% "scalatest" % "2.2.6" % "test"
"com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test"
)


Expand All @@ -39,6 +39,7 @@ resourceGenerators in Compile += Def.task {
val contents = Seq(
s"version=${version.value}",
s"name=${name.value}",
s"organization=${organization.value}",
s"buildTime=${System.currentTimeMillis()}",
s"frontend.immutable=$immutableJsVersion",
s"frontend.react=$reactVersion",
Expand Down
72 changes: 72 additions & 0 deletions server/docs/sample-config.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// HOCON syntax: https://github.com/typesafehub/config/blob/master/HOCON.md

cheesecake.services: [
{
name: nginx
endpoints: [

// default endpoint keys
{
// only the "http" type currenly supported
type: http
host: localhost
port: 80
// path to check
path: /
}

// so simply some keys may be omitted
{
port: 8080
path: /status
}

// ip http endpoint (DNS resolving not used)
{
type: http
ip: 127.0.0.1
}

// symbolic http endpoint (DNS resolving used for every check)
{
type: http
host: example.com
}

// all http endpoint params
{
type: http
// ip: 127.0.0.1
host: localhost
path: "/some/path?with_arguments=%2Fquoted%2F"
headers: {"X-Checker": "cheesecake", "Accept": "application/json"}

}
]
}
// other services
{
name: myapp
endpoints: [
{
type: http
ip: 192.168.1.33
path: /status
}
]

}
// myself
{
name: myself
endpoints: [
{
type: http
port: 52022
path: /status
}
]

}
// ...
]
21 changes: 21 additions & 0 deletions server/src/main/etc/logback.dev.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%gray(%d{HH:mm:ss.SSS}) %highlight(%.-1level) [%cyan(%logger{5}) %green(%X{akkaSource})]: %msg%n</pattern>
</encoder>
</appender>

<logger name="akka" level="INFO"/>
<logger name="ru.maizy.cheesecake" level="DEBUG"/>

<!-- suppress some verbose loggers -->
<logger name="akka.serialization" level="INFO" />

<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>

</configuration>
6 changes: 3 additions & 3 deletions server/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%gray(%d{HH:mm:ss.SSS}) %highlight(%.-1level) [%cyan(%logger{5}) %green(%X{akkaSource})]: %msg%n</pattern>
<pattern>%d{HH:mm:ss.SSS} %.-1level [%logger{5} %X{akkaSource}]: %msg%n</pattern>
</encoder>
</appender>

<logger name="akka" level="INFO"/>
<logger name="ru.maizy.cheesecake" level="DEBUG"/>
<logger name="ru.maizy.cheesecake" level="INFO"/>

<!-- suppress some verbose loggers -->
<logger name="akka.serialization" level="INFO" />

<root level="DEBUG">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>

Expand Down
Loading

0 comments on commit f0064c0

Please sign in to comment.