Compare commits

...

4 Commits

3 changed files with 114 additions and 52 deletions

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.libraries.cache.media.common package dev.inmo.tgbotapi.libraries.cache.media.common
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.DeleteMessage
import dev.inmo.tgbotapi.requests.DownloadFileStream import dev.inmo.tgbotapi.requests.DownloadFileStream
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.get.GetFile import dev.inmo.tgbotapi.requests.get.GetFile
@ -16,6 +17,9 @@ class DefaultMessageContentCache<K>(
private val bot: TelegramBot, private val bot: TelegramBot,
private val filesRefreshingChatId: ChatId, private val filesRefreshingChatId: ChatId,
private val simpleMessageContentCache: MessagesSimpleCache<K>, private val simpleMessageContentCache: MessagesSimpleCache<K>,
private val mediaFileActualityChecker: MediaFileActualityChecker = MediaFileActualityChecker.WithDelay(
MediaFileActualityChecker.Default(filesRefreshingChatId)
),
private val messagesFilesCache: MessagesFilesCache<K> = InMemoryMessagesFilesCache() private val messagesFilesCache: MessagesFilesCache<K> = InMemoryMessagesFilesCache()
) : MessageContentCache<K> { ) : MessageContentCache<K> {
override suspend fun save(content: MessageContent): K { override suspend fun save(content: MessageContent): K {
@ -48,6 +52,10 @@ class DefaultMessageContentCache<K>(
messagesFilesCache.set(key, filename, inputAllocator) messagesFilesCache.set(key, filename, inputAllocator)
}.onFailure { }.onFailure {
simpleMessageContentCache.remove(key) simpleMessageContentCache.remove(key)
}.onSuccess {
with(mediaFileActualityChecker) {
bot.saved(content)
}
} }
return key return key
@ -56,54 +64,50 @@ class DefaultMessageContentCache<K>(
override suspend fun get(k: K): MessageContent? { override suspend fun get(k: K): MessageContent? {
val savedSimpleContent = simpleMessageContentCache.get(k) ?: return null val savedSimpleContent = simpleMessageContentCache.get(k) ?: return null
if (savedSimpleContent is MediaContent) { if (savedSimpleContent is MediaContent && !with(mediaFileActualityChecker) { bot.isActual(savedSimpleContent) }) {
runCatching { val savedFileContentAllocator = messagesFilesCache.get(k) ?: error("Unexpected absence of $k file for content ($simpleMessageContentCache)")
bot.execute(GetFile(savedSimpleContent.media.fileId)) val newContent = bot.execute(
}.onFailure { when (savedSimpleContent.asInputMedia()) {
val savedFileContentAllocator = messagesFilesCache.get(k) ?: error("Unexpected absence of $k file for content ($simpleMessageContentCache)") is InputMediaAnimation -> SendAnimation(
val newContent = bot.execute( filesRefreshingChatId,
when (savedSimpleContent.asInputMedia()) { MultipartFile(
is InputMediaAnimation -> SendAnimation( savedFileContentAllocator
filesRefreshingChatId, ),
MultipartFile( disableNotification = true
savedFileContentAllocator )
), is InputMediaAudio -> SendAudio(
disableNotification = true filesRefreshingChatId,
) MultipartFile(
is InputMediaAudio -> SendAudio( savedFileContentAllocator
filesRefreshingChatId, ),
MultipartFile( disableNotification = true
savedFileContentAllocator )
), is InputMediaVideo -> SendVideo(
disableNotification = true filesRefreshingChatId,
) MultipartFile(
is InputMediaVideo -> SendVideo( savedFileContentAllocator
filesRefreshingChatId, ),
MultipartFile( disableNotification = true
savedFileContentAllocator )
), is InputMediaDocument -> SendDocument(
disableNotification = true filesRefreshingChatId,
) MultipartFile(
is InputMediaDocument -> SendDocument( savedFileContentAllocator
filesRefreshingChatId, ),
MultipartFile( disableNotification = true
savedFileContentAllocator )
), is InputMediaPhoto -> SendPhoto(
disableNotification = true filesRefreshingChatId,
) MultipartFile(
is InputMediaPhoto -> SendPhoto( savedFileContentAllocator
filesRefreshingChatId, ),
MultipartFile( disableNotification = true
savedFileContentAllocator )
), }
disableNotification = true )
)
}
)
simpleMessageContentCache.update(k, newContent.content) simpleMessageContentCache.update(k, newContent.content)
return newContent.content return newContent.content
}
} }
return savedSimpleContent return savedSimpleContent
} }
@ -122,7 +126,10 @@ class DefaultMessageContentCache<K>(
bot: TelegramBot, bot: TelegramBot,
filesRefreshingChatId: ChatId, filesRefreshingChatId: ChatId,
simpleMessageContentCache: MessagesSimpleCache<String> = InMemoryMessagesSimpleCache(), simpleMessageContentCache: MessagesSimpleCache<String> = InMemoryMessagesSimpleCache(),
mediaFileActualityChecker: MediaFileActualityChecker = MediaFileActualityChecker.WithDelay(
MediaFileActualityChecker.Default(filesRefreshingChatId)
),
messagesFilesCache: MessagesFilesCache<String> = InMemoryMessagesFilesCache() messagesFilesCache: MessagesFilesCache<String> = InMemoryMessagesFilesCache()
) = DefaultMessageContentCache(bot, filesRefreshingChatId, simpleMessageContentCache, messagesFilesCache) ) = DefaultMessageContentCache(bot, filesRefreshingChatId, simpleMessageContentCache, mediaFileActualityChecker, messagesFilesCache)
} }
} }

View File

@ -0,0 +1,55 @@
package dev.inmo.tgbotapi.libraries.cache.media.common
import com.soywiz.klock.DateTime
import com.soywiz.klock.milliseconds
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.DeleteMessage
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.MilliSeconds
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
fun interface MediaFileActualityChecker {
suspend fun TelegramBot.isActual(mediaContent: MediaContent): Boolean
suspend fun TelegramBot.saved(mediaContent: MediaContent) {}
class Default(
private val checkingChatId: ChatId
) : MediaFileActualityChecker {
override suspend fun TelegramBot.isActual(mediaContent: MediaContent): Boolean {
return runCatching {
execute(mediaContent.createResend(checkingChatId)).also { sentMessage ->
execute(DeleteMessage(sentMessage.chat.id, sentMessage.messageId))
}
}.isSuccess
}
}
class WithDelay(
private val underhoodChecker: MediaFileActualityChecker,
private val checkingDelay: MilliSeconds = 24 * 60 * 60 * 1000L // one day
) : MediaFileActualityChecker {
private val fileIdChecksMap = mutableMapOf<FileId, DateTime>()
private val checkingDelayTimeSpan = checkingDelay.milliseconds
override suspend fun TelegramBot.isActual(mediaContent: MediaContent): Boolean {
val now = DateTime.now()
val lastCheck = fileIdChecksMap[mediaContent.media.fileId]
return if (lastCheck == null || now - lastCheck > checkingDelayTimeSpan) {
with(underhoodChecker) {
isActual(mediaContent)
}.also {
if (it) {
fileIdChecksMap[mediaContent.media.fileId] = now
}
}
} else {
true
}
}
override suspend fun TelegramBot.saved(mediaContent: MediaContent) {
fileIdChecksMap[mediaContent.media.fileId] = DateTime.now()
}
}
}

View File

@ -11,8 +11,8 @@ kotlin_serialisation_core_version=1.3.2
github_release_plugin_version=2.2.12 github_release_plugin_version=2.2.12
tgbotapi_version=0.38.12 tgbotapi_version=0.38.13
micro_utils_version=0.9.20 micro_utils_version=0.9.22
exposed_version=0.37.3 exposed_version=0.37.3
plagubot_version=0.5.1 plagubot_version=0.5.1
@ -33,5 +33,5 @@ dokka_version=1.6.10
# Project data # Project data
group=dev.inmo group=dev.inmo
version=0.0.17 version=0.0.18
android_code_version=17 android_code_version=18