mirror of
https://github.com/InsanusMokrassar/TelegramBotApiLibraries.git
synced 2024-12-22 16:47:16 +00:00
first version of adminbot
This commit is contained in:
parent
3fe45e4aec
commit
e638aff72a
@ -6,3 +6,12 @@ plugins {
|
||||
|
||||
apply from: "$mppProjectWithSerializationPresetPath"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api "dev.inmo:tgbotapi:$tgbotapi_version"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package dev.inmo.tgbotapi.libraries.cache.admins
|
||||
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
|
||||
|
||||
interface AdminsCacheAPI {
|
||||
suspend fun getChatAdmins(chatId: ChatId): List<AdministratorChatMember>?
|
||||
suspend fun isAdmin(userId: UserId, chatId: ChatId): Boolean
|
||||
|
||||
suspend fun settings(): AdminsCacheSettingsAPI
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package dev.inmo.tgbotapi.libraries.cache.admins
|
||||
|
||||
import com.soywiz.klock.minutes
|
||||
import dev.inmo.tgbotapi.types.ChatId
|
||||
import dev.inmo.tgbotapi.types.Seconds
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AdminsCacheSettings(
|
||||
val refreshSeconds: Seconds = 10.minutes.seconds.toInt(),
|
||||
/**
|
||||
* In case this setting set up to true, will request admins list just from time to time instead of refreshing on
|
||||
* requests
|
||||
*/
|
||||
val disableRequestsRefreshMode: Boolean = false
|
||||
) {
|
||||
val refreshOnRequests: Boolean
|
||||
get() = !disableRequestsRefreshMode
|
||||
}
|
||||
|
||||
interface AdminsCacheSettingsAPI {
|
||||
suspend fun getChatSettings(chatId: ChatId): AdminsCacheSettings?
|
||||
}
|
||||
|
||||
interface MutableAdminsCacheSettingsAPI : AdminsCacheSettingsAPI {
|
||||
val chatSettingsUpdatedFlow: SharedFlow<Pair<ChatId, AdminsCacheSettings>>
|
||||
|
||||
suspend fun setChatSettings(chatId: ChatId, settings: AdminsCacheSettings)
|
||||
}
|
||||
|
||||
fun AdminsCacheSettingsAPI.asMutable(): MutableAdminsCacheSettingsAPI? = this as? MutableAdminsCacheSettingsAPI
|
||||
|
||||
@Serializable
|
||||
class StaticAdminsCacheSettingsAPI(
|
||||
private val settings: Map<ChatId, AdminsCacheSettings>
|
||||
) : AdminsCacheSettingsAPI {
|
||||
override suspend fun getChatSettings(chatId: ChatId): AdminsCacheSettings? = settings[chatId]
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,48 @@
|
||||
package dev.inmo.tgbotapi.libraries.cache.admins
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.extensions.api.chat.get.getChatAdministrators
|
||||
import dev.inmo.tgbotapi.types.ChatId
|
||||
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
|
||||
import dev.inmo.tgbotapi.types.UserId
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
interface DefaultAdminsCacheAPIRepo {
|
||||
suspend fun getChatAdmins(chatId: ChatId): List<AdministratorChatMember>?
|
||||
suspend fun setChatAdmins(chatId: ChatId, chatMembers: List<AdministratorChatMember>)
|
||||
suspend fun lastUpdate(chatId: ChatId): DateTime?
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class DefaultAdminsCacheAPI(
|
||||
private val bot: TelegramBot,
|
||||
private val repo: DefaultAdminsCacheAPIRepo,
|
||||
private val settingsAPI: AdminsCacheSettingsAPI
|
||||
) : AdminsCacheAPI {
|
||||
private suspend fun triggerUpdate(chatId: ChatId): List<AdministratorChatMember> {
|
||||
val admins = bot.getChatAdministrators(chatId)
|
||||
repo.setChatAdmins(chatId, admins)
|
||||
return admins
|
||||
}
|
||||
|
||||
override suspend fun getChatAdmins(chatId: ChatId): List<AdministratorChatMember>? {
|
||||
val settings = settingsAPI.getChatSettings(chatId)
|
||||
val lastUpdate = repo.lastUpdate(chatId)
|
||||
return when {
|
||||
settings == null -> null
|
||||
settings.refreshOnRequests &&
|
||||
(lastUpdate == null || (DateTime.now() - lastUpdate).seconds > settings.refreshSeconds) -> {
|
||||
triggerUpdate(chatId)
|
||||
}
|
||||
else -> repo.getChatAdmins(chatId) ?: triggerUpdate(chatId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun isAdmin(userId: UserId, chatId: ChatId): Boolean = getChatAdmins(chatId) ?.any {
|
||||
it.user.id == userId
|
||||
} == true
|
||||
|
||||
override suspend fun settings(): AdminsCacheSettingsAPI = settingsAPI
|
||||
|
||||
}
|
25
cache/admins/micro_utils/build.gradle
vendored
Normal file
25
cache/admins/micro_utils/build.gradle
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
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.admins.common")
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
api "dev.inmo:micro_utils.repos.exposed:$micro_utils_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-cbor:$kotlin_serialisation_core_version"
|
||||
api "org.jetbrains.exposed:exposed-jdbc:$exposed_version"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package dev.inmo.tgbotapi.libraries.cache.admins.micro_utils
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import dev.inmo.micro_utils.coroutines.actor
|
||||
import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.tgbotapi.libraries.cache.admins.DefaultAdminsCacheAPIRepo
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlin.coroutines.*
|
||||
|
||||
private sealed class RepoActions<T> {
|
||||
abstract val toReturn: Continuation<T>
|
||||
}
|
||||
private class GetUpdateDateTimeRepoAction(
|
||||
val chatId: ChatId,
|
||||
override val toReturn: Continuation<DateTime?>
|
||||
) : RepoActions<DateTime?>()
|
||||
private class GetChatAdminsRepoAction(
|
||||
val chatId: ChatId,
|
||||
override val toReturn: Continuation<List<AdministratorChatMember>?>
|
||||
) : RepoActions<List<AdministratorChatMember>?>()
|
||||
private class SetChatAdminsRepoAction(
|
||||
val chatId: ChatId,
|
||||
val newValue: List<AdministratorChatMember>,
|
||||
override val toReturn: Continuation<Unit>
|
||||
) : RepoActions<Unit>()
|
||||
|
||||
class DefaultAdminsCacheAPIRepo(
|
||||
private val adminsRepo: KeyValuesRepo<ChatId, AdministratorChatMember>,
|
||||
private val updatesRepo: KeyValueRepo<ChatId, MilliSeconds>,
|
||||
private val scope: CoroutineScope
|
||||
) : DefaultAdminsCacheAPIRepo {
|
||||
private val actor = scope.actor<RepoActions<*>>(Channel.UNLIMITED) {
|
||||
safelyWithoutExceptions {
|
||||
when (it) {
|
||||
is GetUpdateDateTimeRepoAction -> it.toReturn.resume(
|
||||
updatesRepo.get(it.chatId) ?.let { DateTime(it.toDouble()) }
|
||||
)
|
||||
is GetChatAdminsRepoAction -> it.toReturn.resume(adminsRepo.getAll(it.chatId))
|
||||
is SetChatAdminsRepoAction -> {
|
||||
adminsRepo.clear(it.chatId)
|
||||
adminsRepo.set(it.chatId, it.newValue)
|
||||
updatesRepo.set(it.chatId, DateTime.now().unixMillisLong)
|
||||
it.toReturn.resume(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getChatAdmins(chatId: ChatId): List<AdministratorChatMember>? = suspendCoroutine {
|
||||
actor.offer(GetChatAdminsRepoAction(chatId, it))
|
||||
}
|
||||
override suspend fun setChatAdmins(chatId: ChatId, chatMembers: List<AdministratorChatMember>) = suspendCoroutine<Unit> {
|
||||
actor.offer(SetChatAdminsRepoAction(chatId, chatMembers, it))
|
||||
}
|
||||
override suspend fun lastUpdate(chatId: ChatId): DateTime? = suspendCoroutine {
|
||||
actor.offer(GetUpdateDateTimeRepoAction(chatId, it))
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package dev.inmo.tgbotapi.libraries.cache.admins.micro_utils
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import dev.inmo.tgbotapi.libraries.cache.admins.*
|
||||
import dev.inmo.tgbotapi.types.ChatId
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
class DynamicAdminsCacheSettingsAPI(
|
||||
private val repo: KeyValueRepo<ChatId, AdminsCacheSettings>,
|
||||
private val scope: CoroutineScope
|
||||
) : AdminsCacheSettingsAPI, MutableAdminsCacheSettingsAPI {
|
||||
override val chatSettingsUpdatedFlow: SharedFlow<Pair<ChatId, AdminsCacheSettings>>
|
||||
get() = repo.onNewValue.shareIn(scope, SharingStarted.Eagerly)
|
||||
|
||||
override suspend fun setChatSettings(chatId: ChatId, settings: AdminsCacheSettings) {
|
||||
repo.set(chatId, settings)
|
||||
}
|
||||
|
||||
override suspend fun getChatSettings(chatId: ChatId): AdminsCacheSettings {
|
||||
val settings = repo.get(chatId)
|
||||
return if (settings == null) {
|
||||
val newSettings = AdminsCacheSettings()
|
||||
setChatSettings(chatId, newSettings)
|
||||
newSettings
|
||||
} else {
|
||||
settings
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package dev.inmo.tgbotapi.libraries.cache.admins
|
||||
|
||||
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.exposed.onetomany.ExposedOneToManyKeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.mappers.withMapper
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.libraries.cache.admins.micro_utils.DefaultAdminsCacheAPIRepo
|
||||
import dev.inmo.tgbotapi.libraries.cache.admins.micro_utils.DynamicAdminsCacheSettingsAPI
|
||||
import dev.inmo.tgbotapi.types.toChatId
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.statements.api.ExposedBlob
|
||||
|
||||
private val serializationFormat = Cbor
|
||||
|
||||
fun AdminsCacheAPI(
|
||||
bot: TelegramBot,
|
||||
database: Database,
|
||||
scope: CoroutineScope,
|
||||
repo: dev.inmo.tgbotapi.libraries.cache.admins.DefaultAdminsCacheAPIRepo = DefaultAdminsCacheAPIRepo(
|
||||
ExposedOneToManyKeyValueRepo(
|
||||
database,
|
||||
{ long("chatId") },
|
||||
{ blob("member") },
|
||||
"AdminsTable"
|
||||
).withMapper(
|
||||
keyFromToTo = { chatId },
|
||||
valueFromToTo = { ExposedBlob(serializationFormat.encodeToByteArray(this)) },
|
||||
keyToToFrom = { toChatId() },
|
||||
valueToToFrom = { serializationFormat.decodeFromByteArray(bytes) }
|
||||
),
|
||||
ExposedKeyValueRepo(
|
||||
database,
|
||||
{ long("chatId") },
|
||||
{ long("datetime") },
|
||||
"AdminsUpdatesTimesTable"
|
||||
).withMapper(
|
||||
keyFromToTo = { chatId },
|
||||
keyToToFrom = { toChatId() }
|
||||
),
|
||||
scope
|
||||
),
|
||||
settingsAPI: AdminsCacheSettingsAPI = DynamicAdminsCacheSettingsAPI(
|
||||
ExposedKeyValueRepo(
|
||||
database,
|
||||
{ long("chatId") },
|
||||
{ blob("settings") },
|
||||
"DynamicAdminsCacheSettingsAPI"
|
||||
).withMapper(
|
||||
keyFromToTo = { chatId },
|
||||
valueFromToTo = { ExposedBlob(serializationFormat.encodeToByteArray(this)) },
|
||||
keyToToFrom = { toChatId() },
|
||||
valueToToFrom = { serializationFormat.decodeFromByteArray(bytes) }
|
||||
),
|
||||
scope
|
||||
)
|
||||
) : AdminsCacheAPI = DefaultAdminsCacheAPI(
|
||||
bot,
|
||||
repo,
|
||||
settingsAPI
|
||||
)
|
1
cache/admins/micro_utils/src/main/AndroidManifest.xml
vendored
Normal file
1
cache/admins/micro_utils/src/main/AndroidManifest.xml
vendored
Normal file
@ -0,0 +1 @@
|
||||
<manifest package="dev.inmo.tgbotapi.libraries.cache.admins.micro_utils"/>
|
@ -13,6 +13,7 @@ github_release_plugin_version=2.2.12
|
||||
|
||||
tgbotapi_version=0.32.8
|
||||
micro_utils_version=0.4.26
|
||||
exposed_version=0.29.1
|
||||
|
||||
# ANDROID
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
rootProject.name = 'tgbotapi.libraries'
|
||||
|
||||
String[] includes = [
|
||||
":cache:admins",
|
||||
":cache:admins:common",
|
||||
":cache:admins:micro_utils",
|
||||
":cache:media"
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user