Skip to content

Commit

Permalink
Configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
benjben committed Aug 14, 2023
1 parent adf8035 commit cd968bb
Show file tree
Hide file tree
Showing 29 changed files with 838 additions and 422 deletions.
15 changes: 12 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* governing permissions and limitations there under.
*/
import com.typesafe.sbt.packager.docker._
import sbtbuildinfo.BuildInfoPlugin.autoImport.buildInfoPackage
import sbtbuildinfo.BuildInfoPlugin.autoImport._

lazy val commonDependencies = Seq(
// Java
Expand Down Expand Up @@ -90,7 +90,7 @@ lazy val buildSettings = Seq(
name := "snowplow-stream-collector",
description := "Scala Stream Collector for Snowplow raw events",
scalaVersion := "2.12.10",
scalacOptions ++= Seq("-Ypartial-unification"),
scalacOptions ++= Seq("-Ypartial-unification", "-Ywarn-macros:after"),
javacOptions := Seq("-source", "11", "-target", "11"),
resolvers ++= Dependencies.resolutionRepos
)
Expand All @@ -100,6 +100,11 @@ lazy val dynVerSettings = Seq(
ThisBuild / dynverSeparator := "-" // to be compatible with docker
)

lazy val http4sBuildInfoSettings = Seq(
buildInfoKeys := Seq[BuildInfoKey](name, dockerAlias, version),
buildInfoOptions += BuildInfoOption.Traits("com.snowplowanalytics.snowplow.collector.core.AppInfo")
)

lazy val allSettings = buildSettings ++
BuildSettings.sbtAssemblySettings ++
BuildSettings.formatting ++
Expand Down Expand Up @@ -134,6 +139,9 @@ lazy val http4s = project
Dependencies.Libraries.badRows,
Dependencies.Libraries.collectorPayload,
Dependencies.Libraries.slf4j,
Dependencies.Libraries.decline,
Dependencies.Libraries.circeGeneric,
Dependencies.Libraries.circeConfig,
Dependencies.Libraries.specs2
)
)
Expand Down Expand Up @@ -262,13 +270,14 @@ lazy val nsqDistroless = project
.dependsOn(core % "test->test;compile->compile")

lazy val stdoutSettings =
allSettings ++ buildInfoSettings ++ Seq(
allSettings ++ buildInfoSettings ++ http4sBuildInfoSettings ++ Seq(
moduleName := "snowplow-stream-collector-stdout",
Docker / packageName := "scala-stream-collector-stdout"
)

lazy val stdout = project
.settings(stdoutSettings)
.settings(buildInfoPackage := s"com.snowplowanalytics.snowplow.collector.stdout")
.enablePlugins(JavaAppPackaging, SnowplowDockerPlugin, BuildInfoPlugin)
.dependsOn(http4s % "test->test;compile->compile")

Expand Down
83 changes: 83 additions & 0 deletions http4s/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
collector {
paths {}

p3p {
policyRef = "/w3c/p3p.xml"
CP = "NOI DSP COR NID PSA OUR IND COM NAV STA"
}

crossDomain {
enabled = false
domains = [ "*" ]
secure = true
}

cookie {
enabled = true
expiration = 365 days
domains = []
name = sp
secure = true
httpOnly = true
sameSite = "None"
}

doNotTrackCookie {
enabled = false
name = ""
value = ""
}

cookieBounce {
enabled = false
name = "n3pc"
fallbackNetworkUserId = "00000000-0000-4000-A000-000000000000"
}

redirectMacro {
enabled = false
}

rootResponse {
enabled = false
statusCode = 302
headers = {}
body = ""
}

cors {
accessControlMaxAge = 60 minutes
}

streams {
useIpAddressAsPartitionKey = false

buffer {
byteLimit = 3145728
recordLimit = 500
timeLimit = 5000
}
}

monitoring {
metrics {
statsd {
enabled = false
hostname = localhost
port = 8125
period = 10 seconds
prefix = snowplow.collector
}
}
}

ssl {
enable = false
redirect = false
port = 443
}

enableDefaultRedirect = false

redirectDomains = []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.snowplowanalytics.snowplow.collector.core

import cats.effect.{ExitCode, IO, Sync}
import cats.effect.kernel.Resource

import com.monovore.decline.effect.CommandIOApp
import com.monovore.decline.Opts

import io.circe.Decoder

import com.snowplowanalytics.snowplow.collector.core.model.Sinks

abstract class App[SinkConfig: Decoder](appInfo: AppInfo)
extends CommandIOApp(
name = App.helpCommand(appInfo),
header = "Snowplow application that collects tracking events",
version = appInfo.version
) {

def mkSinks[F[_]: Sync](config: Config.Streams[SinkConfig]): Resource[F, Sinks[F]]

final def main: Opts[IO[ExitCode]] = Run.fromCli[IO, SinkConfig](appInfo, mkSinks)
}

object App {
private def helpCommand(appInfo: AppInfo) = s"docker run ${appInfo.dockerAlias}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.snowplowanalytics.snowplow.collector.core

trait AppInfo {
def name: String
def version: String
def dockerAlias: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package com.snowplowanalytics.snowplow.collector.core

import scala.concurrent.duration.FiniteDuration

import io.circe.config.syntax._
import io.circe.generic.semiauto._
import io.circe.Decoder
import io.circe._

import org.http4s.SameSite

case class Config[+SinkConfig](
interface: String,
port: Int,
paths: Map[String, String],
p3p: Config.P3P,
crossDomain: Config.CrossDomain,
cookie: Config.Cookie,
doNotTrackCookie: Config.DoNotTrackCookie,
cookieBounce: Config.CookieBounce,
redirectMacro: Config.RedirectMacro,
rootResponse: Config.RootResponse,
cors: Config.CORS,
streams: Config.Streams[SinkConfig],
monitoring: Config.Monitoring,
ssl: Config.SSL,
enableDefaultRedirect: Boolean,
redirectDomains: Set[String]
)

object Config {

case class P3P(
policyRef: String,
CP: String
)

case class CrossDomain(
enabled: Boolean,
domains: List[String],
secure: Boolean
)

case class Cookie(
enabled: Boolean,
name: String,
expiration: FiniteDuration,
domains: List[String],
fallbackDomain: Option[String],
secure: Boolean,
httpOnly: Boolean,
sameSite: Option[SameSite]
)

case class DoNotTrackCookie(
enabled: Boolean,
name: String,
value: String
)

case class CookieBounce(
enabled: Boolean,
name: String,
fallbackNetworkUserId: String,
forwardedProtocolHeader: Option[String]
)

case class RedirectMacro(
enabled: Boolean,
placeholder: Option[String]
)

case class RootResponse(
enabled: Boolean,
statusCode: Int,
headers: Map[String, String],
body: String
)

case class CORS(
accessControlMaxAge: FiniteDuration
)

case class Streams[+SinkConfig](
good: String,
bad: String,
useIpAddressAsPartitionKey: Boolean,
sink: SinkConfig,
buffer: Buffer
)

trait Sink {
val maxBytes: Int
}

case class Buffer(
byteLimit: Long,
recordLimit: Long,
timeLimit: Long
)

case class Monitoring(
metrics: Metrics
)

case class Metrics(
statsd: Statsd
)

case class Statsd(
enabled: Boolean,
hostname: String,
port: Int,
period: FiniteDuration,
prefix: String
)

case class SSL(
enable: Boolean,
redirect: Boolean,
port: Int
)

implicit def decoder[SinkConfig: Decoder]: Decoder[Config[SinkConfig]] = {
implicit val p3p = deriveDecoder[P3P]
implicit val crossDomain = deriveDecoder[CrossDomain]
implicit val sameSite: Decoder[SameSite] = Decoder.instance { cur =>
cur.as[String].map(_.toLowerCase) match {
case Right("none") => Right(SameSite.None)
case Right("strict") => Right(SameSite.Strict)
case Right("lax") => Right(SameSite.Lax)
case Right(other) =>
Left(DecodingFailure(s"sameSite $other is not supported. Accepted values: None, Strict, Lax", cur.history))
case Left(err) => Left(err)
}
}
implicit val cookie = deriveDecoder[Cookie]
implicit val doNotTrackCookie = deriveDecoder[DoNotTrackCookie]
implicit val cookieBounce = deriveDecoder[CookieBounce]
implicit val redirectMacro = deriveDecoder[RedirectMacro]
implicit val rootResponse = deriveDecoder[RootResponse]
implicit val cors = deriveDecoder[CORS]
implicit val buffer = deriveDecoder[Buffer]
implicit val streams = deriveDecoder[Streams[SinkConfig]]
implicit val statsd = deriveDecoder[Statsd]
implicit val metrics = deriveDecoder[Metrics]
implicit val monitoring = deriveDecoder[Monitoring]
implicit val ssl = deriveDecoder[SSL]
deriveDecoder[Config[SinkConfig]]
}
}
Loading

0 comments on commit cd968bb

Please sign in to comment.