Skip to content

Commit

Permalink
feat: #159 Expose config of optional modules
Browse files Browse the repository at this point in the history
Closes: #159
  • Loading branch information
rlemaitre committed Sep 12, 2024
1 parent 9b5b09e commit 776ac24
Show file tree
Hide file tree
Showing 17 changed files with 52 additions and 30 deletions.
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/pillars/AdminServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object AdminServer:
enabled: Boolean,
http: HttpServer.Config = defaultHttp,
openApi: HttpServer.Config.OpenAPI = HttpServer.Config.OpenAPI()
)
) extends pillars.Config

given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
given Codec[Config] = Codec.AsObject.derivedConfigured
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/pillars/ApiServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object ApiServer:
enabled: Boolean,
http: HttpServer.Config = defaultHttp,
openApi: HttpServer.Config.OpenAPI = HttpServer.Config.OpenAPI()
)
) extends pillars.Config

given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
given Codec[Config] = Codec.AsObject.derivedConfigured
Expand Down
4 changes: 3 additions & 1 deletion modules/core/src/main/scala/pillars/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ import scodec.bits.ByteVector

def config[F[_]](using p: Pillars[F]): Config.PillarsConfig = p.config

trait Config

object Config:
case class PillarsConfig(
name: App.Name,
log: Logging.Config = Logging.Config(),
api: ApiServer.Config,
admin: AdminServer.Config,
observability: Observability.Config
)
) extends pillars.Config

object PillarsConfig:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/pillars/HttpServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ object HttpServer:
host: Host,
port: Port,
logging: Logging.HttpConfig = Logging.HttpConfig()
)
) extends pillars.Config

object Config:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down
4 changes: 2 additions & 2 deletions modules/core/src/main/scala/pillars/Logging.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ object Logging:
format: Logging.Format = Logging.Format.Enhanced,
output: Logging.Output = Logging.Output.Console,
excludeHikari: Boolean = false
)
) extends pillars.Config

object Config:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand All @@ -147,7 +147,7 @@ object Logging:
level: Level = Level.Debug,
headers: Boolean = false,
body: Boolean = true
):
) extends pillars.Config:
def logAction[F[_]: Sync]: Option[String => F[Unit]] = Some(scribe.cats.effect[F].log(level, MDC.instance, _))
end HttpConfig

Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/pillars/Observability.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ object Observability:
metrics: Config.Metrics = Config.Metrics(),
traces: Config.Traces = Config.Traces(),
serviceName: ServiceName = ServiceName("pillars")
)
) extends pillars.Config

object Config:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down
3 changes: 3 additions & 0 deletions modules/core/src/main/scala/pillars/modules.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import pillars.probes.Probe
import scribe.Scribe

trait Module[F[_]]:
type ModuleConfig <: Config
def probes: List[Probe[F]] = Nil

def adminControllers: List[Controller[F]] = Nil

def config: ModuleConfig

end Module

object Module:
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/pillars/probes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ object probes:
timeout: FiniteDuration = 5.seconds,
interval: FiniteDuration = 10.seconds,
failureCount: Int = 3
)
) extends pillars.Config

object ProbeConfig:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down
7 changes: 4 additions & 3 deletions modules/db-doobie/src/main/scala/pillars/db_doobie/db.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import pillars.Modules
import pillars.Pillars
import pillars.probes.*

final case class DB[F[_]: MonadCancelThrow](transactor: Transactor[F]) extends Module[F]:
final case class DB[F[_]: MonadCancelThrow](config: DatabaseConfig, transactor: Transactor[F]) extends Module[F]:
override type ModuleConfig = DatabaseConfig

override def probes: List[Probe[F]] =
val probe = new Probe[F]:
Expand Down Expand Up @@ -56,7 +57,7 @@ class DBLoader extends Loader:
config <- Resource.eval(reader.read[DatabaseConfig]("db"))
_ <- Resource.eval(logger.info("DB module loaded"))
xa <- HikariTransactor.fromHikariConfig[F](config.toHikariConfig)
yield DB(xa)
yield DB(config, xa)
end for
end load
end DBLoader
Expand All @@ -72,7 +73,7 @@ final case class DatabaseConfig(
statementCache: StatementCacheConfig = StatementCacheConfig(),
debug: Boolean = false,
probe: ProbeConfig
):
) extends pillars.Config:
def toHikariConfig: HikariConfig =
val cfg = new HikariConfig
cfg.setDriverClassName(driverClassName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import pillars.logger
final case class DBMigration[F[_]: Async: Console: Tracer: Network: Files](
config: MigrationConfig
) extends Module[F]:
override type ModuleConfig = MigrationConfig

private def flyway(schema: DatabaseSchema, table: DatabaseTable, location: String) = Flyway
.configure()
.loggers("slf4j")
Expand Down Expand Up @@ -101,7 +103,7 @@ final case class MigrationConfig(
systemSchema: DatabaseSchema = DatabaseSchema.public,
appSchema: DatabaseSchema = DatabaseSchema.public,
baselineVersion: String = "0"
)
) extends pillars.Config
object MigrationConfig:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults

Expand Down
9 changes: 6 additions & 3 deletions modules/db-skunk/src/main/scala/pillars/db/db.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import skunk.util.Typer

def sessions[F[_]](using p: Pillars[F]): DB[F] = p.module[DB[F]](DB.Key)

final case class DB[F[_]: Async: Network: Tracer: Console](pool: Resource[F, Session[F]]) extends Module[F]:
final case class DB[F[_]: Async: Network: Tracer: Console](config: DatabaseConfig, pool: Resource[F, Session[F]])
extends Module[F]:

override type ModuleConfig = DatabaseConfig
export pool.*

override def probes: List[Probe[F]] =
Expand Down Expand Up @@ -76,7 +79,7 @@ class DBLoader extends Loader:
ssl = config.ssl
)
_ <- Resource.eval(logger.info("DB module loaded"))
yield DB(poolRes)
yield DB(config, poolRes)
end for
end load
end DBLoader
Expand All @@ -102,7 +105,7 @@ final case class DatabaseConfig(
parseCache: Int = 1024,
readTimeout: Duration = Duration.Inf,
redactionStrategy: RedactionStrategy = RedactionStrategy.OptIn
)
) extends pillars.Config

object DatabaseConfig:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down
13 changes: 9 additions & 4 deletions modules/flags/src/main/scala/pillars/flags/FlagManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import pillars.Modules
import pillars.Pillars

trait FlagManager[F[_]: Sync] extends Module[F]:
override type ModuleConfig = FlagsConfig
def isEnabled(flag: Flag): F[Boolean]
def config: FlagsConfig
def getFlag(name: Flag): F[Option[FeatureFlag]]
def flags: F[List[FeatureFlag]]

Expand All @@ -36,9 +38,10 @@ object FlagManager:
case object Key extends Module.Key:
def name: String = "feature-flags"
end Key
def noop[F[_]: Sync]: FlagManager[F] =
def noop[F[_]: Sync](conf: FlagsConfig): FlagManager[F] =
new FlagManager[F]:
def isEnabled(flag: Flag): F[Boolean] = false.pure[F]
override def config: FlagsConfig = conf
def getFlag(name: Flag): F[Option[FeatureFlag]] = None.pure[F]
def flags: F[List[FeatureFlag]] = List.empty.pure[F]
private[flags] def setStatus(flag: Flag, status: Status) = None.pure[F]
Expand All @@ -64,16 +67,18 @@ class FlagManagerLoader extends Loader:
yield manager
end load

private[flags] def createManager[F[_]: Async: Network: Tracer: Console](config: FlagsConfig): F[FlagManager[F]] =
if !config.enabled then Sync[F].pure(FlagManager.noop[F])
private[flags] def createManager[F[_]: Async: Network: Tracer: Console](conf: FlagsConfig): F[FlagManager[F]] =
if !conf.enabled then Sync[F].pure(FlagManager.noop[F](conf))
else
val flags = config.flags.groupBy(_.name).map((name, flags) => name -> flags.head)
val flags = conf.flags.groupBy(_.name).map((name, flags) => name -> flags.head)
Ref
.of[F, Map[Flag, FeatureFlag]](flags)
.map: ref =>
new FlagManager[F]:
def flags: F[List[FeatureFlag]] = ref.get.map(_.values.toList)

override def config: FlagsConfig = conf

def getFlag(name: Flag): F[Option[FeatureFlag]] =
ref.get.map(_.get(name))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import io.circe.Codec
final case class FlagsConfig(
enabled: Boolean = true,
flags: List[FeatureFlag] = List.empty
) derives Codec.AsObject
) extends pillars.Config derives Codec.AsObject
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,16 @@ class Loader extends pillars.Loader:
|> metrics.middleware
|> logging
|> followRedirect
|> HttpClient.apply
|> HttpClient(conf)
_ <- Resource.eval(logger.info("HTTP client module loaded"))
yield client
end for
end load
end Loader

final case class HttpClient[F[_]: Async](client: org.http4s.client.Client[F])
final case class HttpClient[F[_]: Async](config: HttpClient.Config)(client: org.http4s.client.Client[F])
extends pillars.Module[F]:
override type ModuleConfig = HttpClient.Config
export client.*

private val interpreter = Http4sClientInterpreter[F](Http4sClientOptions.default)
Expand Down Expand Up @@ -129,7 +130,8 @@ object HttpClient:
followRedirect: Boolean = true,
userAgent: `User-Agent` = Config.defaultUserAgent,
logging: Logging.HttpConfig = Logging.HttpConfig()
)
) extends pillars.Config

object Config:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
given Decoder[`User-Agent`] = Decoder.decodeString.emap(s =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.http4s.client.Client
import sttp.tapir.*

class HttpClientSuite extends munit.CatsEffectSuite, munit.Http4sMUnitSyntax:
val fixture = Client.partialFixture(client => Resource.pure(HttpClient(client))) {
val fixture = Client.partialFixture(client => Resource.pure(HttpClient(HttpClient.Config())(client))) {
case GET -> Root / "success" / input => Ok("Success")
case GET -> Root / "error" => NotFound("Error")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import scala.language.postfixOps
extension [F[_]](p: Pillars[F])
def rabbit: RabbitMQ[F] = p.module[RabbitMQ[F]](RabbitMQ.Key)

final case class RabbitMQ[F[_]: Async](client: RabbitClient[F]) extends Module[F]:
final case class RabbitMQ[F[_]: Async](config: RabbitMQConfig, client: RabbitClient[F]) extends Module[F]:
override type ModuleConfig = RabbitMQConfig
export client.*

override def probes: List[Probe[F]] =
Expand All @@ -51,7 +52,7 @@ object RabbitMQ:
def apply[F[_]](using p: Pillars[F]): RabbitMQ[F] = p.module[RabbitMQ[F]](RabbitMQ.Key)

def apply[F[_]: Async](config: RabbitMQConfig): Resource[F, RabbitMQ[F]] =
RabbitClient.default[F](config.convert).resource.map(apply)
RabbitClient.default[F](config.convert).resource.map(apply(config, _))

end RabbitMQ

Expand Down Expand Up @@ -89,7 +90,7 @@ case class RabbitMQConfig(
requestedHeartbeat: FiniteDuration = 60 seconds,
automaticRecovery: Boolean = true,
clientProvidedConnectionName: Option[RabbitMQConnectionName] = None
)
) extends pillars.Config

object RabbitMQConfig:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import pillars.probes.*
extension [F[_]](p: Pillars[F])
def redis: Redis[F] = p.module[Redis[F]](Redis.Key)

final case class Redis[F[_]: MonadCancelThrow](connection: Resource[F, RedisConnection[F]])(using c: Concurrent[F])
extends Module[F]:
final case class Redis[F[_]: MonadCancelThrow](config: RedisConfig, connection: Resource[F, RedisConnection[F]])(using
c: Concurrent[F]
) extends Module[F]:
override type ModuleConfig = RedisConfig
export connection.*

override def probes: List[Probe[F]] =
Expand Down Expand Up @@ -63,6 +65,7 @@ class RedisLoader extends Loader:
_ <- Resource.eval(logger.info("Loading Redis module"))
config <- Resource.eval(reader.read[RedisConfig]("redis"))
connection = Redis(
config,
RedisConnection.queued[F]
.withHost(config.host)
.withPort(config.port)
Expand All @@ -86,7 +89,7 @@ final case class RedisConfig(
username: Option[RedisUser],
password: RedisPassword,
probe: ProbeConfig
)
) extends pillars.Config

object RedisConfig:
given Configuration = Configuration.default.withKebabCaseMemberNames.withKebabCaseConstructorNames.withDefaults
Expand Down

0 comments on commit 776ac24

Please sign in to comment.