# Conflicts: # Sources/src/main/kotlin/allin/entities/UserEntity.kt # Sources/src/main/kotlin/allin/routing/UserRouter.ktpull/10/head
commit
a877762d2d
@ -0,0 +1,12 @@
|
|||||||
|
package allin.data
|
||||||
|
|
||||||
|
abstract class AllInDataSource {
|
||||||
|
|
||||||
|
abstract val userDataSource: UserDataSource
|
||||||
|
|
||||||
|
|
||||||
|
abstract val betDataSource: BetDataSource
|
||||||
|
|
||||||
|
|
||||||
|
abstract val participationDataSource: ParticipationDataSource
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package allin.data
|
||||||
|
|
||||||
|
import allin.model.Bet
|
||||||
|
import allin.model.UpdatedBetData
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
interface BetDataSource {
|
||||||
|
fun getAllBets(): List<Bet>
|
||||||
|
fun getBetById(id: String): Bet?
|
||||||
|
fun getBetsNotFinished(): List<Bet>
|
||||||
|
fun addBet(bet: Bet)
|
||||||
|
fun removeBet(id: String): Boolean
|
||||||
|
fun updateBet(data: UpdatedBetData): Boolean
|
||||||
|
fun updateBetStatuses(date: ZonedDateTime)
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package allin.data
|
||||||
|
|
||||||
|
import allin.model.Participation
|
||||||
|
|
||||||
|
interface ParticipationDataSource {
|
||||||
|
|
||||||
|
|
||||||
|
fun addParticipation(participation: Participation)
|
||||||
|
|
||||||
|
|
||||||
|
fun getParticipationFromBetId(betid: String): List<Participation>
|
||||||
|
|
||||||
|
|
||||||
|
fun getParticipationFromUserId(username: String, betid: String): List<Participation>
|
||||||
|
|
||||||
|
|
||||||
|
fun deleteParticipation(id: String): Boolean
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package allin.data
|
||||||
|
|
||||||
|
import allin.dto.UserDTO
|
||||||
|
import allin.model.User
|
||||||
|
|
||||||
|
interface UserDataSource {
|
||||||
|
|
||||||
|
fun getUserByUsername(username: String): Pair<UserDTO?, String?>
|
||||||
|
|
||||||
|
|
||||||
|
fun addUser(user: User)
|
||||||
|
|
||||||
|
|
||||||
|
fun deleteUser(username: String): Boolean
|
||||||
|
|
||||||
|
|
||||||
|
fun modifyUserCoins(username: String, amount: Int)
|
||||||
|
|
||||||
|
|
||||||
|
fun userExists(username: String, email: String): Boolean
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package allin.data.mock
|
||||||
|
|
||||||
|
import allin.data.BetDataSource
|
||||||
|
import allin.model.Bet
|
||||||
|
import allin.model.BetStatus
|
||||||
|
import allin.model.UpdatedBetData
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
class MockBetDataSource : BetDataSource {
|
||||||
|
override fun getAllBets(): List<Bet> = bets
|
||||||
|
override fun getBetById(id: String): Bet? =
|
||||||
|
bets.find { it.id == id }
|
||||||
|
|
||||||
|
override fun removeBet(id: String): Boolean =
|
||||||
|
bets.removeIf { it.id == id }
|
||||||
|
|
||||||
|
override fun updateBet(data: UpdatedBetData): Boolean {
|
||||||
|
return bets.find { it.id == data.id }?.let {
|
||||||
|
it.isPrivate = data.isPrivate
|
||||||
|
} != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBetsNotFinished(): List<Bet> =
|
||||||
|
bets.filter { it.endBet >= ZonedDateTime.now() }
|
||||||
|
|
||||||
|
override fun addBet(bet: Bet) {
|
||||||
|
bets += bet
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateBetStatuses(date: ZonedDateTime) {
|
||||||
|
bets.forEachIndexed { idx, bet ->
|
||||||
|
if (date >= bet.endRegistration) {
|
||||||
|
if (date >= bet.endBet) {
|
||||||
|
bets[idx] = bet.copy(status = BetStatus.WAITING)
|
||||||
|
} else {
|
||||||
|
bets[idx] = bet.copy(status = BetStatus.CLOSING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val bets by lazy { mutableListOf<Bet>() }
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package allin.data.mock
|
||||||
|
|
||||||
|
import allin.data.AllInDataSource
|
||||||
|
import allin.data.BetDataSource
|
||||||
|
import allin.data.ParticipationDataSource
|
||||||
|
import allin.data.UserDataSource
|
||||||
|
|
||||||
|
class MockDataSource : AllInDataSource() {
|
||||||
|
override val userDataSource: UserDataSource = MockUserDataSource()
|
||||||
|
override val betDataSource: BetDataSource = MockBetDataSource()
|
||||||
|
override val participationDataSource: ParticipationDataSource = MockParticipationDataSource()
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package allin.data.mock
|
||||||
|
|
||||||
|
import allin.data.ParticipationDataSource
|
||||||
|
import allin.model.Participation
|
||||||
|
|
||||||
|
class MockParticipationDataSource : ParticipationDataSource {
|
||||||
|
override fun addParticipation(participation: Participation) {
|
||||||
|
participations += participations
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParticipationFromBetId(betid: String): List<Participation> =
|
||||||
|
participations.filter { it.betId == betid }
|
||||||
|
|
||||||
|
override fun getParticipationFromUserId(username: String, betid: String): List<Participation> =
|
||||||
|
participations.filter { it.betId == betid && it.username == username }
|
||||||
|
|
||||||
|
override fun deleteParticipation(id: String): Boolean =
|
||||||
|
participations.removeIf { it.id == id }
|
||||||
|
|
||||||
|
private val participations by lazy { mutableListOf<Participation>() }
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package allin.data.mock
|
||||||
|
|
||||||
|
import allin.data.UserDataSource
|
||||||
|
import allin.dto.UserDTO
|
||||||
|
import allin.model.User
|
||||||
|
|
||||||
|
class MockUserDataSource : UserDataSource {
|
||||||
|
override fun getUserByUsername(username: String): Pair<UserDTO?, String?> =
|
||||||
|
users.find { it.username == username }?.let {
|
||||||
|
Pair(
|
||||||
|
UserDTO(
|
||||||
|
id = it.id,
|
||||||
|
username = it.username,
|
||||||
|
email = it.email,
|
||||||
|
nbCoins = it.nbCoins,
|
||||||
|
token = it.token
|
||||||
|
),
|
||||||
|
it.password
|
||||||
|
)
|
||||||
|
} ?: Pair(null, null)
|
||||||
|
|
||||||
|
override fun addUser(user: User) {
|
||||||
|
users += user
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteUser(username: String): Boolean =
|
||||||
|
users.removeIf { it.username == username }
|
||||||
|
|
||||||
|
override fun modifyUserCoins(username: String, amount: Int) {
|
||||||
|
users.find { it.username == username }?.let {
|
||||||
|
it.nbCoins += amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun userExists(username: String, email: String): Boolean =
|
||||||
|
users.any { it.username == username && it.email == email }
|
||||||
|
|
||||||
|
private val users by lazy {
|
||||||
|
mutableListOf<User>()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package allin.data.postgres
|
||||||
|
|
||||||
|
import allin.data.BetDataSource
|
||||||
|
import allin.entities.BetsEntity
|
||||||
|
import allin.entities.NO_VALUE
|
||||||
|
import allin.entities.ResponsesEntity
|
||||||
|
import allin.entities.ResponsesEntity.response
|
||||||
|
import allin.entities.YES_VALUE
|
||||||
|
import allin.model.Bet
|
||||||
|
import allin.model.BetStatus
|
||||||
|
import allin.model.BetType
|
||||||
|
import allin.model.UpdatedBetData
|
||||||
|
import org.ktorm.database.Database
|
||||||
|
import org.ktorm.dsl.*
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class PostgresBetDataSource(private val database: Database) : BetDataSource {
|
||||||
|
|
||||||
|
private fun QueryRowSet.toBet() =
|
||||||
|
Bet(
|
||||||
|
id = this[BetsEntity.id].toString(),
|
||||||
|
theme = this[BetsEntity.theme].toString(),
|
||||||
|
sentenceBet = this[BetsEntity.sentenceBet].toString(),
|
||||||
|
endRegistration = this[BetsEntity.endRegistration]!!.atZone(ZoneId.of("Europe/Paris")),
|
||||||
|
endBet = this[BetsEntity.endBet]!!.atZone(ZoneId.of("Europe/Paris")),
|
||||||
|
isPrivate = this[BetsEntity.isPrivate] ?: false,
|
||||||
|
status = this[BetsEntity.status] ?: BetStatus.IN_PROGRESS,
|
||||||
|
type = this[BetsEntity.type] ?: BetType.CUSTOM,
|
||||||
|
createdBy = this[BetsEntity.createdBy].toString(),
|
||||||
|
response = let {
|
||||||
|
val idBet = this[BetsEntity.id].toString()
|
||||||
|
val type = this[BetsEntity.type] ?: BetType.CUSTOM
|
||||||
|
if (type == BetType.CUSTOM) {
|
||||||
|
database.from(ResponsesEntity)
|
||||||
|
.select(response)
|
||||||
|
.where { ResponsesEntity.id eq UUID.fromString(idBet) }
|
||||||
|
.map { it[response].toString() }
|
||||||
|
} else {
|
||||||
|
listOf(YES_VALUE, NO_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Query.mapToBet() = this.map { it.toBet() }
|
||||||
|
|
||||||
|
override fun getAllBets(): List<Bet> =
|
||||||
|
database.from(BetsEntity).select().mapToBet()
|
||||||
|
|
||||||
|
override fun getBetById(id: String): Bet? =
|
||||||
|
database.from(BetsEntity).select().where {
|
||||||
|
BetsEntity.id eq UUID.fromString(id)
|
||||||
|
}.mapToBet().firstOrNull()
|
||||||
|
|
||||||
|
override fun getBetsNotFinished(): List<Bet> {
|
||||||
|
val currentTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"))
|
||||||
|
return database.from(BetsEntity)
|
||||||
|
.select()
|
||||||
|
.where { BetsEntity.endBet greaterEq currentTime.toInstant() }
|
||||||
|
.mapToBet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addBet(bet: Bet) {
|
||||||
|
database.insert(BetsEntity) {
|
||||||
|
set(it.id, UUID.fromString(bet.id))
|
||||||
|
set(it.endBet, bet.endBet.toInstant())
|
||||||
|
set(it.endRegistration, bet.endRegistration.toInstant())
|
||||||
|
set(it.sentenceBet, bet.sentenceBet)
|
||||||
|
set(it.theme, bet.theme)
|
||||||
|
set(it.isPrivate, bet.isPrivate)
|
||||||
|
set(it.createdBy, bet.createdBy)
|
||||||
|
set(it.status, bet.status)
|
||||||
|
set(it.type, bet.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bet.type == BetType.CUSTOM) {
|
||||||
|
bet.response.forEach { selected ->
|
||||||
|
database.insert(ResponsesEntity) {
|
||||||
|
set(it.id, UUID.fromString(bet.id))
|
||||||
|
set(it.response, selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeBet(id: String): Boolean {
|
||||||
|
return database.delete(BetsEntity) { it.id eq UUID.fromString(id) } > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateBet(data: UpdatedBetData): Boolean {
|
||||||
|
return database.update(BetsEntity) {
|
||||||
|
set(BetsEntity.isPrivate, data.isPrivate)
|
||||||
|
where { BetsEntity.id eq UUID.fromString(data.id) }
|
||||||
|
} > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateBetStatuses(date: ZonedDateTime) {
|
||||||
|
database.update(BetsEntity) {
|
||||||
|
set(BetsEntity.status, BetStatus.WAITING)
|
||||||
|
where {
|
||||||
|
(date.toInstant() greaterEq BetsEntity.endRegistration) and
|
||||||
|
(date.toInstant() less BetsEntity.endBet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
database.update(BetsEntity) {
|
||||||
|
set(BetsEntity.status, BetStatus.CLOSING)
|
||||||
|
where {
|
||||||
|
(date.toInstant() greaterEq BetsEntity.endRegistration) and
|
||||||
|
(date.toInstant() greaterEq BetsEntity.endBet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package allin.data.postgres
|
||||||
|
|
||||||
|
import allin.data.AllInDataSource
|
||||||
|
import allin.data.BetDataSource
|
||||||
|
import allin.data.ParticipationDataSource
|
||||||
|
import allin.data.UserDataSource
|
||||||
|
import allin.utils.Execute
|
||||||
|
import org.ktorm.database.Database
|
||||||
|
|
||||||
|
class PostgresDataSource : AllInDataSource() {
|
||||||
|
|
||||||
|
private val database: Database
|
||||||
|
|
||||||
|
init {
|
||||||
|
val dbDatabase = System.getenv()["POSTGRES_DB"]
|
||||||
|
val dbUser = System.getenv()["POSTGRES_USER"]
|
||||||
|
val dbPassword = System.getenv()["POSTGRES_PASSWORD"]
|
||||||
|
val dbHost = System.getenv()["POSTGRES_HOST"]
|
||||||
|
|
||||||
|
database = Database.connect(
|
||||||
|
url = "jdbc:postgresql://$dbHost/$dbDatabase",
|
||||||
|
user = dbUser,
|
||||||
|
password = dbPassword
|
||||||
|
)
|
||||||
|
|
||||||
|
database.Execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF not exists utilisateur (
|
||||||
|
id uuid PRIMARY KEY,
|
||||||
|
username VARCHAR(255),
|
||||||
|
password VARCHAR(255),
|
||||||
|
coins double precision,
|
||||||
|
email VARCHAR(255)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
database.Execute(
|
||||||
|
"""
|
||||||
|
CREATE TYPE betstatus AS ENUM
|
||||||
|
('InProgress', 'Waiting', 'Closing', 'Finished', 'Cancelled');
|
||||||
|
|
||||||
|
CREATE TYPE bettype AS ENUM
|
||||||
|
('Match', 'Binary', 'Custom');
|
||||||
|
|
||||||
|
CREATE TABLE IF not exists bet (
|
||||||
|
id uuid PRIMARY KEY,
|
||||||
|
theme VARCHAR(255),
|
||||||
|
endregistration timestamp,
|
||||||
|
endbet timestamp,
|
||||||
|
sentencebet varchar(500),
|
||||||
|
isprivate boolean,
|
||||||
|
createdby varchar(250),
|
||||||
|
status varchar(20),
|
||||||
|
type varchar(20)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
database.Execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS participation (
|
||||||
|
id uuid PRIMARY KEY,
|
||||||
|
bet uuid,
|
||||||
|
username varchar(250),
|
||||||
|
answer varchar(250),
|
||||||
|
stake int
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
database.Execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS response (
|
||||||
|
id UUID,
|
||||||
|
response VARCHAR(250),
|
||||||
|
CONSTRAINT pk_response_id PRIMARY KEY (id,response)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val userDataSource: UserDataSource = PostgresUserDataSource(database)
|
||||||
|
override val betDataSource: BetDataSource = PostgresBetDataSource(database)
|
||||||
|
override val participationDataSource: ParticipationDataSource = PostgresParticipationDataSource(database)
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package allin.data.postgres
|
||||||
|
|
||||||
|
import allin.data.ParticipationDataSource
|
||||||
|
import allin.entities.ParticipationsEntity
|
||||||
|
import allin.model.Participation
|
||||||
|
import org.ktorm.database.Database
|
||||||
|
import org.ktorm.dsl.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class PostgresParticipationDataSource(private val database: Database) : ParticipationDataSource {
|
||||||
|
|
||||||
|
private fun QueryRowSet.toParticipation() =
|
||||||
|
Participation(
|
||||||
|
id = this[ParticipationsEntity.id].toString(),
|
||||||
|
betId = this[ParticipationsEntity.betId].toString(),
|
||||||
|
username = this[ParticipationsEntity.username].toString(),
|
||||||
|
answer = this[ParticipationsEntity.answer].toString(),
|
||||||
|
stake = this[ParticipationsEntity.stake] ?: 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Query.mapToParticipation() = this.map { it.toParticipation() }
|
||||||
|
|
||||||
|
override fun addParticipation(participation: Participation) {
|
||||||
|
database.insert(ParticipationsEntity) {
|
||||||
|
set(it.id, UUID.fromString(participation.id))
|
||||||
|
set(it.betId, UUID.fromString(participation.betId))
|
||||||
|
set(it.username, participation.username)
|
||||||
|
set(it.answer, participation.answer)
|
||||||
|
set(it.stake, participation.stake)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParticipationFromBetId(betid: String): List<Participation> {
|
||||||
|
return database.from(ParticipationsEntity)
|
||||||
|
.select()
|
||||||
|
.where { ParticipationsEntity.betId eq UUID.fromString(betid) }
|
||||||
|
.mapToParticipation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParticipationFromUserId(username: String, betid: String): List<Participation> {
|
||||||
|
return database.from(ParticipationsEntity)
|
||||||
|
.select()
|
||||||
|
.where { (ParticipationsEntity.betId eq UUID.fromString(betid)) and (ParticipationsEntity.username eq username) }
|
||||||
|
.mapToParticipation()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getParticipationEntity(): List<Participation> {
|
||||||
|
return database.from(ParticipationsEntity).select().mapToParticipation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteParticipation(id: String): Boolean {
|
||||||
|
return database.delete(ParticipationsEntity) {
|
||||||
|
it.id eq UUID.fromString(id)
|
||||||
|
} > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package allin.data.postgres
|
||||||
|
|
||||||
|
import allin.data.UserDataSource
|
||||||
|
import allin.dto.UserDTO
|
||||||
|
import allin.entities.UsersEntity
|
||||||
|
import allin.model.User
|
||||||
|
import org.ktorm.database.Database
|
||||||
|
import org.ktorm.dsl.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class PostgresUserDataSource(private val database: Database) : UserDataSource {
|
||||||
|
override fun getUserByUsername(username: String): Pair<UserDTO?, String?> =
|
||||||
|
database.from(UsersEntity)
|
||||||
|
.select()
|
||||||
|
.where { UsersEntity.username eq username }
|
||||||
|
.map { row ->
|
||||||
|
Pair(
|
||||||
|
UserDTO(
|
||||||
|
row[UsersEntity.id].toString(),
|
||||||
|
row[UsersEntity.username].toString(),
|
||||||
|
row[UsersEntity.email].toString(),
|
||||||
|
row[UsersEntity.nbCoins] ?: 0,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
row[UsersEntity.password].toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.firstOrNull() ?: Pair(null, null)
|
||||||
|
|
||||||
|
override fun addUser(user: User) {
|
||||||
|
database.insert(UsersEntity) {
|
||||||
|
set(it.id, UUID.fromString(user.id))
|
||||||
|
set(it.nbCoins, user.nbCoins)
|
||||||
|
set(it.username, user.username)
|
||||||
|
set(it.password, user.password)
|
||||||
|
set(it.email, user.email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteUser(username: String): Boolean {
|
||||||
|
val deletedCount = database.delete(UsersEntity) {
|
||||||
|
it.username eq username
|
||||||
|
}
|
||||||
|
return deletedCount > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun userExists(username: String, email: String): Boolean {
|
||||||
|
return database.from(UsersEntity).select(UsersEntity.username, UsersEntity.email).where {
|
||||||
|
(UsersEntity.username eq username) and (UsersEntity.email eq email)
|
||||||
|
}.totalRecords > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun modifyUserCoins(username: String, amount: Int) {
|
||||||
|
database.update(UsersEntity) {
|
||||||
|
set(UsersEntity.nbCoins, UsersEntity.nbCoins - amount)
|
||||||
|
where { UsersEntity.username eq username }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package allin.model
|
||||||
|
|
||||||
|
enum class BetStatus {
|
||||||
|
IN_PROGRESS,
|
||||||
|
WAITING,
|
||||||
|
CLOSING,
|
||||||
|
FINISHED,
|
||||||
|
CANCELLED
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package allin.model
|
||||||
|
|
||||||
|
enum class BetType {
|
||||||
|
MATCH,
|
||||||
|
BINARY,
|
||||||
|
CUSTOM
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package allin.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class, ExperimentalTime::class)
|
||||||
|
fun kronJob(duration: Duration, action: () -> Unit) =
|
||||||
|
GlobalScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
while (true) {
|
||||||
|
runCatching { action() }
|
||||||
|
delay(duration.toLongMilliseconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue