mirror of
https://github.com/InsanusMokrassar/PlaguPoster.git
synced 2024-12-22 22:17:14 +00:00
add timers repo and timers handler
This commit is contained in:
parent
9403b133f9
commit
c632a2ba14
@ -4,8 +4,11 @@ import com.soywiz.klock.DateTime
|
|||||||
import com.soywiz.klock.DateTimeTz
|
import com.soywiz.klock.DateTimeTz
|
||||||
import com.soywiz.klock.Month
|
import com.soywiz.klock.Month
|
||||||
import com.soywiz.klock.Year
|
import com.soywiz.klock.Year
|
||||||
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
||||||
|
import dev.inmo.plaguposter.posts.models.Post
|
||||||
import dev.inmo.plaguposter.posts.models.PostId
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.answers.answer
|
||||||
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
|
||||||
@ -38,7 +41,9 @@ object ButtonsBuilder {
|
|||||||
dataButton(SuccessfulSymbol, "$changeDateDataPrefix $postId $unixMillis")
|
dataButton(SuccessfulSymbol, "$changeDateDataPrefix $postId $unixMillis")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun BehaviourContext.includeKeyboardHandling() {
|
suspend fun BehaviourContext.includeKeyboardHandling(
|
||||||
|
onSavePublishingTime: suspend (PostId, DateTime) -> Boolean
|
||||||
|
) {
|
||||||
fun buildKeyboard(
|
fun buildKeyboard(
|
||||||
prefix: String,
|
prefix: String,
|
||||||
postId: PostId,
|
postId: PostId,
|
||||||
@ -180,5 +185,21 @@ object ButtonsBuilder {
|
|||||||
oldDateTime.offset
|
oldDateTime.offset
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMessageDataCallbackQuery(Regex("$changeDateDataPrefix .*")) {
|
||||||
|
val (_, rawPostId, rawDateTimeMillis) = it.data.split(" ")
|
||||||
|
val currentMillis = rawDateTimeMillis.toLongOrNull() ?: return@onMessageDataCallbackQuery
|
||||||
|
val currentDateTime = DateTime(currentMillis)
|
||||||
|
val postId = PostId(rawPostId)
|
||||||
|
|
||||||
|
val success = runCatchingSafely {
|
||||||
|
onSavePublishingTime(postId, currentDateTime)
|
||||||
|
}.getOrElse { false }
|
||||||
|
|
||||||
|
answer(
|
||||||
|
it,
|
||||||
|
if (success) "Successfully set timer" else "Unable to set timer"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
triggers/timer/src/commonMain/kotlin/TimersHandler.kt
Normal file
57
triggers/timer/src/commonMain/kotlin/TimersHandler.kt
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.coroutines.plus
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.plaguposter.posts.sending.PostPublisher
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
|
||||||
|
class TimersHandler(
|
||||||
|
private val timersRepo: TimersRepo,
|
||||||
|
private val publisher: PostPublisher,
|
||||||
|
private val scope: CoroutineScope
|
||||||
|
) {
|
||||||
|
private var currentPostAndJob: Pair<PostId, Job>? = null
|
||||||
|
private val currentJobMutex = Mutex()
|
||||||
|
|
||||||
|
init {
|
||||||
|
(flowOf(Unit) + timersRepo.onNewValue + timersRepo.onValueRemoved).subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
refreshPublishingJob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun refreshPublishingJob() {
|
||||||
|
val minimal = timersRepo.getMinimalDateTimePost()
|
||||||
|
|
||||||
|
currentJobMutex.withLock {
|
||||||
|
if (minimal ?.first == currentPostAndJob ?.first) {
|
||||||
|
return@withLock
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPostAndJob ?.second ?.cancel()
|
||||||
|
|
||||||
|
currentPostAndJob = minimal ?.let { (postId, dateTime) ->
|
||||||
|
postId to scope.launchSafelyWithoutExceptions {
|
||||||
|
val now = DateTime.now()
|
||||||
|
val span = dateTime - now
|
||||||
|
|
||||||
|
delay(span.millisecondsLong)
|
||||||
|
|
||||||
|
publisher.publish(postId)
|
||||||
|
|
||||||
|
timersRepo.unset(postId)
|
||||||
|
|
||||||
|
refreshPublishingJob()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
triggers/timer/src/commonMain/kotlin/TimersRepo.kt
Normal file
9
triggers/timer/src/commonMain/kotlin/TimersRepo.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
|
||||||
|
interface TimersRepo : KeyValueRepo<PostId, DateTime> {
|
||||||
|
suspend fun getMinimalDateTimePost(): Pair<PostId, DateTime>?
|
||||||
|
}
|
@ -2,8 +2,10 @@ package dev.inmo.plaguposter.triggers.timer
|
|||||||
|
|
||||||
import com.soywiz.klock.DateTime
|
import com.soywiz.klock.DateTime
|
||||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||||
|
import dev.inmo.micro_utils.repos.set
|
||||||
import dev.inmo.plagubot.Plugin
|
import dev.inmo.plagubot.Plugin
|
||||||
import dev.inmo.plaguposter.posts.repo.ReadPostsRepo
|
import dev.inmo.plaguposter.posts.repo.ReadPostsRepo
|
||||||
|
import dev.inmo.plaguposter.triggers.timer.repo.ExposedTimersRepo
|
||||||
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
import dev.inmo.tgbotapi.extensions.api.edit.edit
|
||||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
|
||||||
@ -12,15 +14,22 @@ import kotlinx.serialization.json.*
|
|||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.koin.core.Koin
|
import org.koin.core.Koin
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
|
import org.koin.dsl.binds
|
||||||
|
|
||||||
object Plugin : Plugin {
|
object Plugin : Plugin {
|
||||||
override fun Module.setupDI(database: Database, params: JsonObject) {
|
override fun Module.setupDI(database: Database, params: JsonObject) {
|
||||||
|
single { ExposedTimersRepo(get(), get(), get()) } binds arrayOf(TimersRepo::class)
|
||||||
|
single(createdAtStart = true) { TimersHandler(get(), get(), get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||||
val postsRepo = koin.get<ReadPostsRepo>()
|
val postsRepo = koin.get<ReadPostsRepo>()
|
||||||
|
val timersRepo = koin.get<TimersRepo>()
|
||||||
with(ButtonsBuilder) {
|
with(ButtonsBuilder) {
|
||||||
includeKeyboardHandling()
|
includeKeyboardHandling { postId, dateTime ->
|
||||||
|
timersRepo.set(postId, dateTime)
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onCommand("test") {
|
onCommand("test") {
|
||||||
val reply = it.replyTo ?: return@onCommand
|
val reply = it.replyTo ?: return@onCommand
|
||||||
|
62
triggers/timer/src/jvmMain/kotlin/repo/ExposedTimersRepo.kt
Normal file
62
triggers/timer/src/jvmMain/kotlin/repo/ExposedTimersRepo.kt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package dev.inmo.plaguposter.triggers.timer.repo
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import dev.inmo.micro_utils.common.firstNotNull
|
||||||
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
|
import dev.inmo.micro_utils.pagination.paginate
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.initTable
|
||||||
|
import dev.inmo.micro_utils.repos.exposed.keyvalue.AbstractExposedKeyValueRepo
|
||||||
|
import dev.inmo.micro_utils.repos.unset
|
||||||
|
import dev.inmo.plaguposter.posts.models.PostId
|
||||||
|
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||||
|
import dev.inmo.plaguposter.triggers.timer.TimersRepo
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import org.jetbrains.exposed.sql.Column
|
||||||
|
import org.jetbrains.exposed.sql.Database
|
||||||
|
import org.jetbrains.exposed.sql.ISqlExpressionBuilder
|
||||||
|
import org.jetbrains.exposed.sql.Op
|
||||||
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||||
|
import org.jetbrains.exposed.sql.statements.UpdateBuilder
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|
||||||
|
class ExposedTimersRepo(
|
||||||
|
database: Database,
|
||||||
|
postsRepo: PostsRepo,
|
||||||
|
scope: CoroutineScope
|
||||||
|
) : TimersRepo, AbstractExposedKeyValueRepo<PostId, DateTime>(
|
||||||
|
database,
|
||||||
|
"timers"
|
||||||
|
) {
|
||||||
|
override val keyColumn = text("post_id")
|
||||||
|
private val dateTimeColumn = long("date_time")
|
||||||
|
override val selectById: ISqlExpressionBuilder.(PostId) -> Op<Boolean> = { keyColumn.eq(it.string) }
|
||||||
|
override val selectByValue: ISqlExpressionBuilder.(DateTime) -> Op<Boolean> = { dateTimeColumn.eq(it.unixMillisLong) }
|
||||||
|
override val ResultRow.asKey: PostId
|
||||||
|
get() = PostId(get(keyColumn))
|
||||||
|
override val ResultRow.asObject: DateTime
|
||||||
|
get() = DateTime(get(dateTimeColumn))
|
||||||
|
|
||||||
|
val postsRepoListeningJob = postsRepo.deletedObjectsIdsFlow.subscribeSafelyWithoutExceptions(scope) {
|
||||||
|
unset(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
initTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(k: PostId, v: DateTime, it: UpdateBuilder<Int>) {
|
||||||
|
it[dateTimeColumn] = v.unixMillisLong
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun insertKey(k: PostId, v: DateTime, it: InsertStatement<Number>) {
|
||||||
|
it[keyColumn] = k.string
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getMinimalDateTimePost(): Pair<PostId, DateTime>? = transaction(database) {
|
||||||
|
selectAll().orderBy(dateTimeColumn).limit(1).firstOrNull() ?.let {
|
||||||
|
PostId(it[keyColumn]) to DateTime(it[dateTimeColumn])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user