This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Topic[VReq, V] { | |
def record(request: VReq): RIO[Blocking, UUID] | |
def records: ZManaged[RecordConsumer.Env, Throwable, ZStream[Any, Nothing, V]] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Job description | |
case class CronJob(id: UUID, cronString: CronExpr) | |
// App state | |
case class CronulaSate(jobs: Map[UUID, CronJob] = Map.empty[UUID, CronJob]) | |
// Events | |
sealed trait CronulaEvent | |
case class RecordJob(id: UUID, cronString: CronExpr) extends CronulaEvent | |
case class DeleteJob(id: UUID) extends CronulaEvent | |
case class Updatejob(id: UUID, cronString: CronExpr) extends CronulaEvent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def run(args: List[String]): IO[ExitCode] = (for { | |
config <- loadConfigF[IO, Config] | |
userCredentialStore <- UserStore(config.users.head, config.users.tail: _*) | |
http <- httpApp(userCredentialStore) | |
res <- BlazeServerBuilder[IO] | |
.bindHttp(host = config.http.host, port = config.http.port.getOrElse(0)) | |
.withHttpApp(http) | |
.serve | |
.compile | |
.drain |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class HttpConfig(host: String, port: Option[Int]) | |
case class Config(http: HttpConfig, users: List[UsernamePasswordCredentials]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
http { | |
host = ${ENV_PROVIDED_HOST} | |
port = ${ENV_PROVIDED_PORT} | |
} | |
users = [ | |
{ | |
username = ${ENV_PROVIDED_USERNAME} | |
password = ${ENV_PROVIDED_PASSWORD} | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def authenticator(userStore: IdentityStore[IO, UserId, User]) = for { | |
tokens <- Ref.of[IO, Map[SecureRandomId, TSecBearerToken[UserId]]](Map.empty) | |
} yield BearerTokenAuthenticator[IO, UserId, User]( | |
userStore, | |
tokenStore(tokens), | |
TSecTokenSettings( | |
expiryDuration = 10.minutes, | |
maxIdle = None | |
)) | |
def httpApp(userStore: UserStore) = authenticator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
implicit val loginUserDecoder: Decoder[UsernamePasswordCredentials] = deriveDecoder | |
implicit val entityLoginUserDecoder: EntityDecoder[IO, UsernamePasswordCredentials] = | |
jsonOf[IO, UsernamePasswordCredentials] | |
def loginRoute( | |
auth: BearerTokenAuthenticator[IO, UserId, User], | |
checkPassword: UsernamePasswordCredentials => IO[Option[User]]): HttpRoutes[IO] = | |
HttpRoutes.of[IO] { | |
case req @ POST -> Root / "login" => | |
(for { | |
user <- req.as[UsernamePasswordCredentials] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object UserStore { | |
def apply(user: UsernamePasswordCredentials, users: UsernamePasswordCredentials*): IO[UserStore] = | |
for { | |
userList <- (user +: users) | |
.map(u => UserStore.newUser(u.username, u.password)) | |
.toList | |
.sequence | |
users <- Ref.of[IO, Map[UserId, User]](userList.map(u => u.id -> u).toMap) | |
} yield | |
new UserStore( |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def validateUser(credentials: UsernamePasswordCredentials)( | |
users: List[User]): IO[Option[User]] = | |
users.findM( | |
user => | |
BCrypt | |
.checkpwBool[IO](credentials.password, user.password) | |
.map(_ && credentials.username == user.username), | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def newUser(username: String, password: String): IO[User] = | |
Applicative[IO].map2( | |
FUUID.randomFUUID[IO].map(tagFUUIDAsUserId), | |
BCrypt.hashpw[IO](password) | |
)(User(_, username, _)) |