From 6591c8ffa8578977c6d443efdfce026d10641817 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 22 Mar 2022 18:52:02 +0600 Subject: [PATCH 1/9] start 0.0.17 --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 72640f8..02f4c27 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,5 +33,5 @@ dokka_version=1.6.10 # Project data group=dev.inmo -version=0.0.16 -android_code_version=16 +version=0.0.17 +android_code_version=17 From f423d31423aee21ee425c2a2179e70cf251bfdfe Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 22 Mar 2022 18:52:23 +0600 Subject: [PATCH 2/9] implement content caching --- cache/{media => content/common}/build.gradle | 10 ++ .../common/DefaultMessageContentCache.kt | 119 ++++++++++++++++++ .../cache/media/common/MessageContentCache.kt | 12 ++ .../cache/media/common/MessagesFilesCache.kt | 49 ++++++++ .../media/common/InFilesMessagesFilesCache.kt | 75 +++++++++++ .../common/src/main/AndroidManifest.xml | 1 + cache/content/micro_utils/build.gradle | 19 +++ .../SimpleKeyValueMessageContentCache.kt | 84 +++++++++++++ .../micro_utils/src/main/AndroidManifest.xml | 1 + cache/media/src/main/AndroidManifest.xml | 1 - gradle.properties | 6 +- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 8 +- 13 files changed, 379 insertions(+), 8 deletions(-) rename cache/{media => content/common}/build.gradle (52%) create mode 100644 cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt create mode 100644 cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt create mode 100644 cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt create mode 100644 cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt create mode 100644 cache/content/common/src/main/AndroidManifest.xml create mode 100644 cache/content/micro_utils/build.gradle create mode 100644 cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt create mode 100644 cache/content/micro_utils/src/main/AndroidManifest.xml delete mode 100644 cache/media/src/main/AndroidManifest.xml diff --git a/cache/media/build.gradle b/cache/content/common/build.gradle similarity index 52% rename from cache/media/build.gradle rename to cache/content/common/build.gradle index 8a22926..1c05fde 100644 --- a/cache/media/build.gradle +++ b/cache/content/common/build.gradle @@ -6,3 +6,13 @@ plugins { apply from: "$mppProjectWithSerializationPresetPath" +kotlin { + sourceSets { + commonMain { + dependencies { + api "dev.inmo:tgbotapi.core:$tgbotapi_version" + } + } + } +} + diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt new file mode 100644 index 0000000..94ce7f2 --- /dev/null +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt @@ -0,0 +1,119 @@ +package dev.inmo.tgbotapi.libraries.cache.media.common + +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.requests.DownloadFileStream +import dev.inmo.tgbotapi.requests.abstracts.MultipartFile +import dev.inmo.tgbotapi.requests.get.GetFile +import dev.inmo.tgbotapi.requests.send.media.* +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.InputMedia.* +import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent +import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +import io.ktor.utils.io.cancel + +class DefaultMessageContentCache( + private val bot: TelegramBot, + private val simpleMessageContentCache: MessageContentCache, + private val messagesFilesCache: MessagesFilesCache, + private val filesRefreshingChatId: ChatId +) : MessageContentCache { + override suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean { + runCatching { + if (content is MediaContent) { + val extendedInfo = bot.execute( + GetFile(content.media.fileId) + ) + val allocator = bot.execute( + DownloadFileStream( + extendedInfo.filePath + ) + ) + messagesFilesCache.set(chatId, messageId, extendedInfo.fileName, allocator) + } + }.onFailure { + return false + } + + return simpleMessageContentCache.save( + chatId, messageId, content + ) + } + + override suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? { + val savedSimpleContent = simpleMessageContentCache.get(chatId, messageId) ?: return null + + if (savedSimpleContent is MediaContent) { + runCatching { + val streamAllocator = bot.execute( + DownloadFileStream( + bot.execute( + GetFile( + savedSimpleContent.media.fileId + ) + ).filePath + ) + ) + + streamAllocator().apply { + readByte() + cancel() + } + }.onFailure { + val savedFileContentAllocator = messagesFilesCache.get(chatId, messageId) ?: error("Unexpected absence of $chatId:$messageId file for content ($simpleMessageContentCache)") + val newContent = bot.execute( + when (savedSimpleContent.asInputMedia()) { + is InputMediaAnimation -> SendAnimation( + filesRefreshingChatId, + MultipartFile( + savedFileContentAllocator + ), + disableNotification = true + ) + is InputMediaAudio -> SendAudio( + filesRefreshingChatId, + MultipartFile( + savedFileContentAllocator + ), + disableNotification = true + ) + is InputMediaVideo -> SendVideo( + filesRefreshingChatId, + MultipartFile( + savedFileContentAllocator + ), + disableNotification = true + ) + is InputMediaDocument -> SendDocument( + filesRefreshingChatId, + MultipartFile( + savedFileContentAllocator + ), + disableNotification = true + ) + is InputMediaPhoto -> SendPhoto( + filesRefreshingChatId, + MultipartFile( + savedFileContentAllocator + ), + disableNotification = true + ) + } + ) + + simpleMessageContentCache.save(chatId, messageId, newContent.content) + return newContent.content + } + } + return savedSimpleContent + } + + override suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean { + return simpleMessageContentCache.contains(chatId, messageId) + } + + override suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) { + simpleMessageContentCache.remove(chatId, messageId) + messagesFilesCache.remove(chatId, messageId) + } +} diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt new file mode 100644 index 0000000..48fc69d --- /dev/null +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt @@ -0,0 +1,12 @@ +package dev.inmo.tgbotapi.libraries.cache.media.common + +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent + +interface MessageContentCache { + suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean + suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? + suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean + suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) +} diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt new file mode 100644 index 0000000..5308cfd --- /dev/null +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt @@ -0,0 +1,49 @@ +package dev.inmo.tgbotapi.libraries.cache.media.common + +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.utils.ByteReadChannelAllocator +import dev.inmo.tgbotapi.utils.StorageFile +import io.ktor.util.toByteArray +import io.ktor.utils.io.ByteReadChannel + +interface MessagesFilesCache { + suspend fun set(chatId: ChatId, messageIdentifier: MessageIdentifier, filename: String, byteReadChannelAllocator: ByteReadChannelAllocator) + suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? + suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) + suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean +} + +/** + * It is not recommended to use in production realization of [MessagesFilesCache] which has been created for fast + * start of application creation with usage of [MessageContentCache] with aim to replace this realization by some + * disks-oriented one + */ +class InMemoryMessagesFilesCache : MessagesFilesCache { + private val map = mutableMapOf, StorageFile>() + + override suspend fun set( + chatId: ChatId, + messageIdentifier: MessageIdentifier, + filename: String, + byteReadChannelAllocator: ByteReadChannelAllocator + ) { + map[chatId to messageIdentifier] = StorageFile( + filename, + byteReadChannelAllocator.invoke().toByteArray() + ) + } + + override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? { + return map[chatId to messageIdentifier] + } + + override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { + map.remove(chatId to messageIdentifier) + } + + override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { + return map.contains(chatId to messageIdentifier) + } + +} diff --git a/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt b/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt new file mode 100644 index 0000000..c893888 --- /dev/null +++ b/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt @@ -0,0 +1,75 @@ +package dev.inmo.tgbotapi.libraries.cache.media.common + +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.utils.* +import io.ktor.utils.io.core.copyTo +import io.ktor.utils.io.streams.asInput +import io.ktor.utils.io.streams.asOutput +import java.io.File + +class InFilesMessagesFilesCache( + private val folderFile: File +) : MessagesFilesCache { + private val Pair.storageFile: StorageFile? + get() { + val prefix = filePrefix(first, second) + val filename = folderFile.list() ?.firstOrNull { it.startsWith(prefix) } ?: return null + val file = File(folderFile, filename) + val storageFileFilename = file.name.removePrefix("$prefix ") + + return StorageFile( + StorageFileInfo(storageFileFilename) + ) { + file.inputStream().asInput() + } + } + + init { + require(!folderFile.isFile) { "Folder of messages files cache can't be file, but was $folderFile" } + folderFile.mkdirs() + } + + private fun filePrefix(chatId: ChatId, messageIdentifier: MessageIdentifier): String { + return "${chatId.chatId} $messageIdentifier" + } + + private fun fileName(chatId: ChatId, messageIdentifier: MessageIdentifier, filename: String): String { + return "${chatId.chatId} $messageIdentifier $filename" + } + + override suspend fun set( + chatId: ChatId, + messageIdentifier: MessageIdentifier, + filename: String, + byteReadChannelAllocator: ByteReadChannelAllocator + ) { + val fullFileName = fileName(chatId, messageIdentifier, filename) + val file = File(folderFile, fullFileName).apply { + delete() + } + byteReadChannelAllocator.invoke().asInput().use { input -> + file.outputStream().asOutput().use { output -> + input.copyTo(output) + } + } + } + + override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? { + return (chatId to messageIdentifier).storageFile + } + + override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { + val prefix = filePrefix(chatId, messageIdentifier) + folderFile.listFiles() ?.forEach { + if (it.name.startsWith(prefix)) { + it.delete() + } + } + } + + override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { + val prefix = filePrefix(chatId, messageIdentifier) + return folderFile.list() ?.any { it.startsWith(prefix) } == true + } +} diff --git a/cache/content/common/src/main/AndroidManifest.xml b/cache/content/common/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e663aab --- /dev/null +++ b/cache/content/common/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/cache/content/micro_utils/build.gradle b/cache/content/micro_utils/build.gradle new file mode 100644 index 0000000..0dcdc86 --- /dev/null +++ b/cache/content/micro_utils/build.gradle @@ -0,0 +1,19 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" + id "com.android.library" +} + +apply from: "$mppProjectWithSerializationPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + api "dev.inmo:micro_utils.repos.common:$micro_utils_version" + api project(":tgbotapi.libraries.cache.content.common") + } + } + } +} + diff --git a/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt b/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt new file mode 100644 index 0000000..86f6f6d --- /dev/null +++ b/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt @@ -0,0 +1,84 @@ +package dev.inmo.tgbotapi.libraries.cache.media.micro_utils + +import dev.inmo.micro_utils.repos.* +import dev.inmo.micro_utils.repos.mappers.withMapper +import dev.inmo.tgbotapi.libraries.cache.media.common.MessageContentCache +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +import kotlinx.serialization.* +import kotlinx.serialization.builtins.PairSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule +import kotlin.js.JsName +import kotlin.jvm.JvmName + +class SimpleKeyValueMessageContentCache( + private val keyValueRepo: KeyValueRepo, MessageContent> +) : MessageContentCache { + override suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean { + return keyValueRepo.runCatching { + set(chatId to messageId, content) + }.isSuccess + } + + override suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? { + return keyValueRepo.get(chatId to messageId) + } + + override suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean { + return keyValueRepo.contains(chatId to messageId) + } + + override suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) { + keyValueRepo.unset(chatId to messageId) + } +} + +val chatIdToMessageIdentifierSerializer = PairSerializer( + ChatId.serializer(), + MessageIdentifier.serializer() +) + +val messageContentSerializer = PolymorphicSerializer(MessageContent::class) + +inline fun KeyValueRepo.asMessageContentCache( + serialFormatCreator: (SerializersModule) -> StringFormat = { Json { serializersModule = it } } +): StandardKeyValueRepo, MessageContent> { + val serialFormat = serialFormatCreator(MessageContent.serializationModule()) + return withMapper, MessageContent, String, String>( + { serialFormat.encodeToString(chatIdToMessageIdentifierSerializer, this) }, + { serialFormat.encodeToString(messageContentSerializer, this) }, + { serialFormat.decodeFromString(chatIdToMessageIdentifierSerializer, this) }, + { serialFormat.decodeFromString(messageContentSerializer, this) }, + ) +} + +@JvmName("stringsKeyValueAsHexMessageContentCache") +@JsName("stringsKeyValueAsHexMessageContentCache") +inline fun KeyValueRepo.asMessageContentCache( + serialFormatCreator: (SerializersModule) -> BinaryFormat +): StandardKeyValueRepo, MessageContent> { + val serialFormat = serialFormatCreator(MessageContent.serializationModule()) + return withMapper, MessageContent, String, String>( + { serialFormat.encodeToHexString(chatIdToMessageIdentifierSerializer, this) }, + { serialFormat.encodeToHexString(messageContentSerializer, this) }, + { serialFormat.decodeFromHexString(chatIdToMessageIdentifierSerializer, this) }, + { serialFormat.decodeFromHexString(messageContentSerializer, this) }, + ) +} + +@JvmName("bytesKeyValueAsMessageContentCache") +@JsName("bytesKeyValueAsMessageContentCache") +inline fun KeyValueRepo.asMessageContentCache( + serialFormatCreator: (SerializersModule) -> BinaryFormat +): StandardKeyValueRepo, MessageContent> { + val serialFormat = serialFormatCreator(MessageContent.serializationModule()) + return withMapper, MessageContent, ByteArray, ByteArray>( + { serialFormat.encodeToByteArray(chatIdToMessageIdentifierSerializer, this) }, + { serialFormat.encodeToByteArray(messageContentSerializer, this) }, + { serialFormat.decodeFromByteArray(chatIdToMessageIdentifierSerializer, this) }, + { serialFormat.decodeFromByteArray(messageContentSerializer, this) }, + ) +} diff --git a/cache/content/micro_utils/src/main/AndroidManifest.xml b/cache/content/micro_utils/src/main/AndroidManifest.xml new file mode 100644 index 0000000..77c705e --- /dev/null +++ b/cache/content/micro_utils/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/cache/media/src/main/AndroidManifest.xml b/cache/media/src/main/AndroidManifest.xml deleted file mode 100644 index 24d7792..0000000 --- a/cache/media/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/gradle.properties b/gradle.properties index 02f4c27..833bdda 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,9 +11,9 @@ kotlin_serialisation_core_version=1.3.2 github_release_plugin_version=2.2.12 -tgbotapi_version=0.38.4 -micro_utils_version=0.9.5 -exposed_version=0.37.2 +tgbotapi_version=0.38.9 +micro_utils_version=0.9.16 +exposed_version=0.37.3 plagubot_version=0.5.1 # ANDROID diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102..00e33ed 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index 40732cb..ccfc849 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,13 +4,15 @@ String[] includes = [ ":cache:admins:common", ":cache:admins:micro_utils", ":cache:admins:plagubot", - ":cache:media" + + ":cache:content:common", + ":cache:content:micro_utils", ] includes.each { originalName -> - String projectDirectory = "${rootProject.projectDir.getAbsolutePath()}${originalName.replaceAll(":", File.separator)}" - String projectName = "${rootProject.name}${originalName.replaceAll(":", ".")}" + String projectDirectory = "${rootProject.projectDir.getAbsolutePath()}${originalName.replace(":", File.separator)}" + String projectName = "${rootProject.name}${originalName.replace(":", ".")}" String projectIdentifier = ":${projectName}" include projectIdentifier ProjectDescriptor project = project(projectIdentifier) From 5305438686b2fb7de81841521493c2f9bbcd4363 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 30 Mar 2022 07:56:25 +0600 Subject: [PATCH 3/9] Update gradle.properties --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 833bdda..7d42585 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,8 +11,8 @@ kotlin_serialisation_core_version=1.3.2 github_release_plugin_version=2.2.12 -tgbotapi_version=0.38.9 -micro_utils_version=0.9.16 +tgbotapi_version=0.38.11 +micro_utils_version=0.9.17 exposed_version=0.37.3 plagubot_version=0.5.1 From 7e37a439042cf4892b903cd17b8363e4de7d155d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 4 Apr 2022 17:40:00 +0600 Subject: [PATCH 4/9] small potential fix --- .../tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt index 5308cfd..2459366 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt @@ -30,7 +30,7 @@ class InMemoryMessagesFilesCache : MessagesFilesCache { ) { map[chatId to messageIdentifier] = StorageFile( filename, - byteReadChannelAllocator.invoke().toByteArray() + byteReadChannelAllocator.invoke() ) } From cde0a11c1b094f1a04e956c7a9afee465733a201 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 11 Apr 2022 21:28:53 +0600 Subject: [PATCH 5/9] simple fixes --- .../common/DefaultMessageContentCache.kt | 43 ++++++++++++----- .../cache/media/common/MessageContentCache.kt | 9 ++++ .../cache/media/common/MessagesFilesCache.kt | 15 +++--- .../cache/media/common/MessagesSimpleCache.kt | 48 +++++++++++++++++++ .../media/common/InFilesMessagesFilesCache.kt | 5 +- .../SimpleKeyValueMessageContentCache.kt | 22 ++++----- 6 files changed, 111 insertions(+), 31 deletions(-) create mode 100644 cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt index 94ce7f2..5a4e01c 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt @@ -10,17 +10,20 @@ import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +import dev.inmo.tgbotapi.utils.StorageFile +import dev.inmo.tgbotapi.utils.asInput import io.ktor.utils.io.cancel +import io.ktor.utils.io.core.Input -class DefaultMessageContentCache( +class DefaultMessageContentCache( private val bot: TelegramBot, - private val simpleMessageContentCache: MessageContentCache, - private val messagesFilesCache: MessagesFilesCache, - private val filesRefreshingChatId: ChatId + private val filesRefreshingChatId: ChatId, + private val simpleMessageContentCache: MessagesSimpleCache = InMemoryMessagesSimpleCache(), + private val messagesFilesCache: MessagesFilesCache = InMemoryMessagesFilesCache() ) : MessageContentCache { override suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean { - runCatching { - if (content is MediaContent) { + return when (content) { + is MediaContent -> { val extendedInfo = bot.execute( GetFile(content.media.fileId) ) @@ -29,15 +32,33 @@ class DefaultMessageContentCache( extendedInfo.filePath ) ) - messagesFilesCache.set(chatId, messageId, extendedInfo.fileName, allocator) + + save(chatId, messageId, content, extendedInfo.fileName) { + allocator.invoke().asInput() + } } + else -> simpleMessageContentCache.runCatching { + set(chatId, messageId, content) + }.isSuccess + } + } + + override suspend fun save( + chatId: ChatId, + messageId: MessageIdentifier, + content: MediaContent, + filename: String, + inputAllocator: suspend () -> Input + ): Boolean { + runCatching { + messagesFilesCache.set(chatId, messageId, filename, inputAllocator) }.onFailure { return false } - return simpleMessageContentCache.save( - chatId, messageId, content - ) + return simpleMessageContentCache.runCatching { + set(chatId, messageId, content) + }.isSuccess } override suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? { @@ -101,7 +122,7 @@ class DefaultMessageContentCache( } ) - simpleMessageContentCache.save(chatId, messageId, newContent.content) + simpleMessageContentCache.set(chatId, messageId, newContent.content) return newContent.content } } diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt index 48fc69d..2718920 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt @@ -2,10 +2,19 @@ package dev.inmo.tgbotapi.libraries.cache.media.common import dev.inmo.tgbotapi.types.ChatId import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +import io.ktor.utils.io.core.Input interface MessageContentCache { suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean + suspend fun save( + chatId: ChatId, + messageId: MessageIdentifier, + content: MediaContent, + filename: String, + inputAllocator: suspend () -> Input + ): Boolean suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt index 2459366..a23fa5d 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt @@ -2,13 +2,16 @@ package dev.inmo.tgbotapi.libraries.cache.media.common import dev.inmo.tgbotapi.types.ChatId import dev.inmo.tgbotapi.types.MessageIdentifier -import dev.inmo.tgbotapi.utils.ByteReadChannelAllocator import dev.inmo.tgbotapi.utils.StorageFile -import io.ktor.util.toByteArray -import io.ktor.utils.io.ByteReadChannel +import io.ktor.utils.io.core.* interface MessagesFilesCache { - suspend fun set(chatId: ChatId, messageIdentifier: MessageIdentifier, filename: String, byteReadChannelAllocator: ByteReadChannelAllocator) + suspend fun set( + chatId: ChatId, + messageIdentifier: MessageIdentifier, + filename: String, + inputAllocator: suspend () -> Input + ) suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean @@ -26,11 +29,11 @@ class InMemoryMessagesFilesCache : MessagesFilesCache { chatId: ChatId, messageIdentifier: MessageIdentifier, filename: String, - byteReadChannelAllocator: ByteReadChannelAllocator + inputAllocator: suspend () -> Input ) { map[chatId to messageIdentifier] = StorageFile( filename, - byteReadChannelAllocator.invoke() + inputAllocator().readBytes() ) } diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt new file mode 100644 index 0000000..a325fe2 --- /dev/null +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt @@ -0,0 +1,48 @@ +package dev.inmo.tgbotapi.libraries.cache.media.common + +import dev.inmo.tgbotapi.types.ChatId +import dev.inmo.tgbotapi.types.MessageIdentifier +import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent +import dev.inmo.tgbotapi.utils.StorageFile +import io.ktor.utils.io.core.* + +interface MessagesSimpleCache { + suspend fun set( + chatId: ChatId, + messageIdentifier: MessageIdentifier, + content: MessageContent + ) + suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): MessageContent? + suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) + suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean +} + +/** + * It is not recommended to use in production realization of [MessagesFilesCache] which has been created for fast + * start of application creation with usage of [MessageContentCache] with aim to replace this realization by some + * disks-oriented one + */ +class InMemoryMessagesSimpleCache : MessagesSimpleCache { + private val map = mutableMapOf, MessageContent>() + + override suspend fun set( + chatId: ChatId, + messageIdentifier: MessageIdentifier, + content: MessageContent + ) { + map[chatId to messageIdentifier] = content + } + + override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): MessageContent? { + return map[chatId to messageIdentifier] + } + + override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { + map.remove(chatId to messageIdentifier) + } + + override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { + return map.contains(chatId to messageIdentifier) + } + +} diff --git a/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt b/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt index c893888..9244e6c 100644 --- a/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt +++ b/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt @@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.libraries.cache.media.common import dev.inmo.tgbotapi.types.ChatId import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.utils.* +import io.ktor.utils.io.core.Input import io.ktor.utils.io.core.copyTo import io.ktor.utils.io.streams.asInput import io.ktor.utils.io.streams.asOutput @@ -42,13 +43,13 @@ class InFilesMessagesFilesCache( chatId: ChatId, messageIdentifier: MessageIdentifier, filename: String, - byteReadChannelAllocator: ByteReadChannelAllocator + inputAllocator: suspend () -> Input ) { val fullFileName = fileName(chatId, messageIdentifier, filename) val file = File(folderFile, fullFileName).apply { delete() } - byteReadChannelAllocator.invoke().asInput().use { input -> + inputAllocator().use { input -> file.outputStream().asOutput().use { output -> input.copyTo(output) } diff --git a/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt b/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt index 86f6f6d..0cf0ce0 100644 --- a/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt +++ b/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt @@ -2,7 +2,7 @@ package dev.inmo.tgbotapi.libraries.cache.media.micro_utils import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.mappers.withMapper -import dev.inmo.tgbotapi.libraries.cache.media.common.MessageContentCache +import dev.inmo.tgbotapi.libraries.cache.media.common.MessagesSimpleCache import dev.inmo.tgbotapi.types.ChatId import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent @@ -16,23 +16,21 @@ import kotlin.jvm.JvmName class SimpleKeyValueMessageContentCache( private val keyValueRepo: KeyValueRepo, MessageContent> -) : MessageContentCache { - override suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean { - return keyValueRepo.runCatching { - set(chatId to messageId, content) - }.isSuccess +) : MessagesSimpleCache { + override suspend fun set(chatId: ChatId, messageIdentifier: MessageIdentifier, content: MessageContent) { + keyValueRepo.set(chatId to messageIdentifier, content) } - override suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? { - return keyValueRepo.get(chatId to messageId) + override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): MessageContent? { + return keyValueRepo.get(chatId to messageIdentifier) } - override suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean { - return keyValueRepo.contains(chatId to messageId) + override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { + return keyValueRepo.contains(chatId to messageIdentifier) } - override suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) { - keyValueRepo.unset(chatId to messageId) + override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { + keyValueRepo.unset(chatId to messageIdentifier) } } From 043948401dffc87828198ae17413ae0914753d02 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 11 Apr 2022 21:42:12 +0600 Subject: [PATCH 6/9] fixes in getting of content file cache --- .../media/common/DefaultMessageContentCache.kt | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt index 5a4e01c..71c6de5 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt @@ -10,7 +10,6 @@ import dev.inmo.tgbotapi.types.InputMedia.* import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent -import dev.inmo.tgbotapi.utils.StorageFile import dev.inmo.tgbotapi.utils.asInput import io.ktor.utils.io.cancel import io.ktor.utils.io.core.Input @@ -66,20 +65,7 @@ class DefaultMessageContentCache( if (savedSimpleContent is MediaContent) { runCatching { - val streamAllocator = bot.execute( - DownloadFileStream( - bot.execute( - GetFile( - savedSimpleContent.media.fileId - ) - ).filePath - ) - ) - - streamAllocator().apply { - readByte() - cancel() - } + bot.execute(GetFile(savedSimpleContent.media.fileId)) }.onFailure { val savedFileContentAllocator = messagesFilesCache.get(chatId, messageId) ?: error("Unexpected absence of $chatId:$messageId file for content ($simpleMessageContentCache)") val newContent = bot.execute( From be1b13debba99ff3ae3304b47157d19d3e506257 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 11 Apr 2022 22:07:47 +0600 Subject: [PATCH 7/9] update dependencies --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 7d42585..1f24ec5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,8 +11,8 @@ kotlin_serialisation_core_version=1.3.2 github_release_plugin_version=2.2.12 -tgbotapi_version=0.38.11 -micro_utils_version=0.9.17 +tgbotapi_version=0.38.12 +micro_utils_version=0.9.19 exposed_version=0.37.3 plagubot_version=0.5.1 From 0f05779e0d7a829205ccbada24bc0a75f15f19d5 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 11 Apr 2022 23:32:06 +0600 Subject: [PATCH 8/9] add opportunity to use custom keys --- .../common/DefaultMessageContentCache.kt | 58 ++++++++-------- .../cache/media/common/MessageContentCache.kt | 16 ++--- .../cache/media/common/MessagesFilesCache.kt | 41 +++++------- .../cache/media/common/MessagesSimpleCache.kt | 67 ++++++++++++------- .../media/common/InFilesMessagesFilesCache.kt | 50 +++++++------- .../SimpleKeyValueMessageContentCache.kt | 44 +++++++++--- 6 files changed, 149 insertions(+), 127 deletions(-) diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt index 71c6de5..755e430 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/DefaultMessageContentCache.kt @@ -7,20 +7,18 @@ import dev.inmo.tgbotapi.requests.get.GetFile import dev.inmo.tgbotapi.requests.send.media.* import dev.inmo.tgbotapi.types.ChatId import dev.inmo.tgbotapi.types.InputMedia.* -import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import dev.inmo.tgbotapi.utils.asInput -import io.ktor.utils.io.cancel import io.ktor.utils.io.core.Input -class DefaultMessageContentCache( +class DefaultMessageContentCache( private val bot: TelegramBot, private val filesRefreshingChatId: ChatId, - private val simpleMessageContentCache: MessagesSimpleCache = InMemoryMessagesSimpleCache(), - private val messagesFilesCache: MessagesFilesCache = InMemoryMessagesFilesCache() -) : MessageContentCache { - override suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean { + private val simpleMessageContentCache: MessagesSimpleCache, + private val messagesFilesCache: MessagesFilesCache = InMemoryMessagesFilesCache() +) : MessageContentCache { + override suspend fun save(content: MessageContent): K { return when (content) { is MediaContent -> { val extendedInfo = bot.execute( @@ -32,42 +30,37 @@ class DefaultMessageContentCache( ) ) - save(chatId, messageId, content, extendedInfo.fileName) { + save(content, extendedInfo.fileName) { allocator.invoke().asInput() } } - else -> simpleMessageContentCache.runCatching { - set(chatId, messageId, content) - }.isSuccess + else -> simpleMessageContentCache.add(content) } } override suspend fun save( - chatId: ChatId, - messageId: MessageIdentifier, content: MediaContent, filename: String, inputAllocator: suspend () -> Input - ): Boolean { + ): K { + val key = simpleMessageContentCache.add(content) runCatching { - messagesFilesCache.set(chatId, messageId, filename, inputAllocator) + messagesFilesCache.set(key, filename, inputAllocator) }.onFailure { - return false + simpleMessageContentCache.remove(key) } - return simpleMessageContentCache.runCatching { - set(chatId, messageId, content) - }.isSuccess + return key } - override suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? { - val savedSimpleContent = simpleMessageContentCache.get(chatId, messageId) ?: return null + override suspend fun get(k: K): MessageContent? { + val savedSimpleContent = simpleMessageContentCache.get(k) ?: return null if (savedSimpleContent is MediaContent) { runCatching { bot.execute(GetFile(savedSimpleContent.media.fileId)) }.onFailure { - val savedFileContentAllocator = messagesFilesCache.get(chatId, messageId) ?: error("Unexpected absence of $chatId:$messageId file for content ($simpleMessageContentCache)") + val savedFileContentAllocator = messagesFilesCache.get(k) ?: error("Unexpected absence of $k file for content ($simpleMessageContentCache)") val newContent = bot.execute( when (savedSimpleContent.asInputMedia()) { is InputMediaAnimation -> SendAnimation( @@ -108,19 +101,28 @@ class DefaultMessageContentCache( } ) - simpleMessageContentCache.set(chatId, messageId, newContent.content) + simpleMessageContentCache.update(k, newContent.content) return newContent.content } } return savedSimpleContent } - override suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean { - return simpleMessageContentCache.contains(chatId, messageId) + override suspend fun contains(k: K): Boolean { + return simpleMessageContentCache.contains(k) } - override suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) { - simpleMessageContentCache.remove(chatId, messageId) - messagesFilesCache.remove(chatId, messageId) + override suspend fun remove(k: K) { + simpleMessageContentCache.remove(k) + messagesFilesCache.remove(k) + } + + companion object { + operator fun invoke( + bot: TelegramBot, + filesRefreshingChatId: ChatId, + simpleMessageContentCache: MessagesSimpleCache = InMemoryMessagesSimpleCache(), + messagesFilesCache: MessagesFilesCache = InMemoryMessagesFilesCache() + ) = DefaultMessageContentCache(bot, filesRefreshingChatId, simpleMessageContentCache, messagesFilesCache) } } diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt index 2718920..baec180 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessageContentCache.kt @@ -1,21 +1,17 @@ package dev.inmo.tgbotapi.libraries.cache.media.common -import dev.inmo.tgbotapi.types.ChatId -import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent import io.ktor.utils.io.core.Input -interface MessageContentCache { - suspend fun save(chatId: ChatId, messageId: MessageIdentifier, content: MessageContent): Boolean +interface MessageContentCache { + suspend fun save(content: MessageContent): K suspend fun save( - chatId: ChatId, - messageId: MessageIdentifier, content: MediaContent, filename: String, inputAllocator: suspend () -> Input - ): Boolean - suspend fun get(chatId: ChatId, messageId: MessageIdentifier): MessageContent? - suspend fun contains(chatId: ChatId, messageId: MessageIdentifier): Boolean - suspend fun remove(chatId: ChatId, messageId: MessageIdentifier) + ): K + suspend fun get(k: K): MessageContent? + suspend fun contains(k: K): Boolean + suspend fun remove(k: K) } diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt index a23fa5d..796fca9 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesFilesCache.kt @@ -5,16 +5,11 @@ import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.utils.StorageFile import io.ktor.utils.io.core.* -interface MessagesFilesCache { - suspend fun set( - chatId: ChatId, - messageIdentifier: MessageIdentifier, - filename: String, - inputAllocator: suspend () -> Input - ) - suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? - suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) - suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean +interface MessagesFilesCache { + suspend fun set(k: K, filename: String, inputAllocator: suspend () -> Input) + suspend fun get(k: K): StorageFile? + suspend fun remove(k: K) + suspend fun contains(k: K): Boolean } /** @@ -22,31 +17,25 @@ interface MessagesFilesCache { * start of application creation with usage of [MessageContentCache] with aim to replace this realization by some * disks-oriented one */ -class InMemoryMessagesFilesCache : MessagesFilesCache { - private val map = mutableMapOf, StorageFile>() +class InMemoryMessagesFilesCache : MessagesFilesCache { + private val map = mutableMapOf() - override suspend fun set( - chatId: ChatId, - messageIdentifier: MessageIdentifier, - filename: String, - inputAllocator: suspend () -> Input - ) { - map[chatId to messageIdentifier] = StorageFile( + override suspend fun set(k: K, filename: String, inputAllocator: suspend () -> Input) { + map[k] = StorageFile( filename, inputAllocator().readBytes() ) } - override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? { - return map[chatId to messageIdentifier] + override suspend fun get(k: K): StorageFile? { + return map[k] } - override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { - map.remove(chatId to messageIdentifier) + override suspend fun remove(k: K) { + map.remove(k) } - override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { - return map.contains(chatId to messageIdentifier) + override suspend fun contains(k: K): Boolean { + return map.contains(k) } - } diff --git a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt index a325fe2..ffc08b1 100644 --- a/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt +++ b/cache/content/common/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/MessagesSimpleCache.kt @@ -1,20 +1,14 @@ package dev.inmo.tgbotapi.libraries.cache.media.common -import dev.inmo.tgbotapi.types.ChatId -import dev.inmo.tgbotapi.types.MessageIdentifier +import com.benasher44.uuid.uuid4 import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent -import dev.inmo.tgbotapi.utils.StorageFile -import io.ktor.utils.io.core.* -interface MessagesSimpleCache { - suspend fun set( - chatId: ChatId, - messageIdentifier: MessageIdentifier, - content: MessageContent - ) - suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): MessageContent? - suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) - suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean +interface MessagesSimpleCache { + suspend fun add(content: MessageContent): K + suspend fun update(k: K, content: MessageContent): Boolean + suspend fun get(k: K): MessageContent? + suspend fun remove(k: K) + suspend fun contains(k: K): Boolean } /** @@ -22,27 +16,48 @@ interface MessagesSimpleCache { * start of application creation with usage of [MessageContentCache] with aim to replace this realization by some * disks-oriented one */ -class InMemoryMessagesSimpleCache : MessagesSimpleCache { - private val map = mutableMapOf, MessageContent>() +class InMemoryMessagesSimpleCache( + private val keyGenerator: () -> K +) : MessagesSimpleCache { + private val map = mutableMapOf() - override suspend fun set( - chatId: ChatId, - messageIdentifier: MessageIdentifier, + override suspend fun add( content: MessageContent - ) { - map[chatId to messageIdentifier] = content + ): K { + val key = keyGenerator() + map[key] = content + return key } - override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): MessageContent? { - return map[chatId to messageIdentifier] + override suspend fun update( + k: K, + content: MessageContent + ): Boolean { + return map.runCatching { + if (contains(k)) { + put(k, content) + true + } else { + false + } + }.getOrDefault(false) } - override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { - map.remove(chatId to messageIdentifier) + override suspend fun get(k: K): MessageContent? { + return map[k] } - override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { - return map.contains(chatId to messageIdentifier) + override suspend fun remove(k: K) { + map.remove(k) } + override suspend fun contains(k: K): Boolean { + return map.contains(k) + } + + companion object { + operator fun invoke() = InMemoryMessagesSimpleCache { + uuid4().toString() + } + } } diff --git a/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt b/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt index 9244e6c..53aed1c 100644 --- a/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt +++ b/cache/content/common/src/jvmMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/common/InFilesMessagesFilesCache.kt @@ -1,7 +1,5 @@ package dev.inmo.tgbotapi.libraries.cache.media.common -import dev.inmo.tgbotapi.types.ChatId -import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.utils.* import io.ktor.utils.io.core.Input import io.ktor.utils.io.core.copyTo @@ -9,12 +7,13 @@ import io.ktor.utils.io.streams.asInput import io.ktor.utils.io.streams.asOutput import java.io.File -class InFilesMessagesFilesCache( - private val folderFile: File -) : MessagesFilesCache { - private val Pair.storageFile: StorageFile? +class InFilesMessagesFilesCache( + private val folderFile: File, + private val filePrefixBuilder: (K) -> String +) : MessagesFilesCache { + private val K.storageFile: StorageFile? get() { - val prefix = filePrefix(first, second) + val prefix = filePrefix(this) val filename = folderFile.list() ?.firstOrNull { it.startsWith(prefix) } ?: return null val file = File(folderFile, filename) val storageFileFilename = file.name.removePrefix("$prefix ") @@ -31,21 +30,14 @@ class InFilesMessagesFilesCache( folderFile.mkdirs() } - private fun filePrefix(chatId: ChatId, messageIdentifier: MessageIdentifier): String { - return "${chatId.chatId} $messageIdentifier" + private fun filePrefix(k: K): String = filePrefixBuilder(k) + + private fun fileName(k: K, filename: String): String { + return "${filePrefix(k)} $filename" } - private fun fileName(chatId: ChatId, messageIdentifier: MessageIdentifier, filename: String): String { - return "${chatId.chatId} $messageIdentifier $filename" - } - - override suspend fun set( - chatId: ChatId, - messageIdentifier: MessageIdentifier, - filename: String, - inputAllocator: suspend () -> Input - ) { - val fullFileName = fileName(chatId, messageIdentifier, filename) + override suspend fun set(k: K, filename: String, inputAllocator: suspend () -> Input) { + val fullFileName = fileName(k, filename) val file = File(folderFile, fullFileName).apply { delete() } @@ -56,12 +48,12 @@ class InFilesMessagesFilesCache( } } - override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): StorageFile? { - return (chatId to messageIdentifier).storageFile + override suspend fun get(k: K): StorageFile? { + return k.storageFile } - override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { - val prefix = filePrefix(chatId, messageIdentifier) + override suspend fun remove(k: K) { + val prefix = filePrefix(k) folderFile.listFiles() ?.forEach { if (it.name.startsWith(prefix)) { it.delete() @@ -69,8 +61,14 @@ class InFilesMessagesFilesCache( } } - override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { - val prefix = filePrefix(chatId, messageIdentifier) + override suspend fun contains(k: K): Boolean { + val prefix = filePrefix(k) return folderFile.list() ?.any { it.startsWith(prefix) } == true } + + companion object { + operator fun invoke(folderFile: File) = InFilesMessagesFilesCache( + folderFile + ) { it } + } } diff --git a/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt b/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt index 0cf0ce0..e77a7db 100644 --- a/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt +++ b/cache/content/micro_utils/src/commonMain/kotlin/dev/inmo/tgbotapi/libraries/cache/media/micro_utils/SimpleKeyValueMessageContentCache.kt @@ -1,5 +1,6 @@ package dev.inmo.tgbotapi.libraries.cache.media.micro_utils +import com.benasher44.uuid.uuid4 import dev.inmo.micro_utils.repos.* import dev.inmo.micro_utils.repos.mappers.withMapper import dev.inmo.tgbotapi.libraries.cache.media.common.MessagesSimpleCache @@ -14,23 +15,44 @@ import kotlinx.serialization.modules.SerializersModule import kotlin.js.JsName import kotlin.jvm.JvmName -class SimpleKeyValueMessageContentCache( - private val keyValueRepo: KeyValueRepo, MessageContent> -) : MessagesSimpleCache { - override suspend fun set(chatId: ChatId, messageIdentifier: MessageIdentifier, content: MessageContent) { - keyValueRepo.set(chatId to messageIdentifier, content) +class SimpleKeyValueMessageContentCache( + private val keyValueRepo: KeyValueRepo, + private val keyGenerator: () -> K +) : MessagesSimpleCache { + override suspend fun add(content: MessageContent): K { + val key = keyGenerator() + keyValueRepo.set(key, content) + + return key } - override suspend fun get(chatId: ChatId, messageIdentifier: MessageIdentifier): MessageContent? { - return keyValueRepo.get(chatId to messageIdentifier) + override suspend fun update(k: K, content: MessageContent): Boolean { + return keyValueRepo.runCatching { + if (contains(k)) { + keyValueRepo.set(k, content) + true + } else { + false + } + }.getOrDefault(false) } - override suspend fun contains(chatId: ChatId, messageIdentifier: MessageIdentifier): Boolean { - return keyValueRepo.contains(chatId to messageIdentifier) + override suspend fun get(k: K): MessageContent? { + return keyValueRepo.get(k) } - override suspend fun remove(chatId: ChatId, messageIdentifier: MessageIdentifier) { - keyValueRepo.unset(chatId to messageIdentifier) + override suspend fun contains(k: K): Boolean { + return keyValueRepo.contains(k) + } + + override suspend fun remove(k: K) { + keyValueRepo.unset(k) + } + + companion object { + operator fun invoke( + keyValueRepo: KeyValueRepo + ) = SimpleKeyValueMessageContentCache(keyValueRepo) { uuid4().toString() } } } From 6327366720dc205178831cc0370a53e83778775d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 16 Apr 2022 09:12:10 +0600 Subject: [PATCH 9/9] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1f24ec5..260a53d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ kotlin_serialisation_core_version=1.3.2 github_release_plugin_version=2.2.12 tgbotapi_version=0.38.12 -micro_utils_version=0.9.19 +micro_utils_version=0.9.20 exposed_version=0.37.3 plagubot_version=0.5.1