mirror of
https://github.com/InsanusMokrassar/PlaguPoster.git
synced 2024-12-22 14:07:14 +00:00
commit
b05844737b
21
.github/workflows/docker-publish.yml
vendored
Normal file
21
.github/workflows/docker-publish.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Docker
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
publishing:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Log into registry
|
||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_LOGIN }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Deploy
|
||||
run: ./gradlew build && cd ./runner && ./nonsudo_deploy.sh
|
@ -1,5 +1,7 @@
|
||||
# PlaguPoster
|
||||
|
||||
## 0.0.10
|
||||
|
||||
## 0.0.9
|
||||
|
||||
* Update depedencies
|
||||
|
@ -11,7 +11,9 @@ kotlin {
|
||||
dependencies {
|
||||
api libs.tgbotapi
|
||||
api libs.microutils.repos.common
|
||||
api libs.microutils.repos.cache
|
||||
api libs.kslog
|
||||
api libs.microutils.koin
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
|
16
common/src/commonMain/kotlin/UseCache.kt
Normal file
16
common/src/commonMain/kotlin/UseCache.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package dev.inmo.plaguposter.common
|
||||
|
||||
import org.koin.core.Koin
|
||||
import org.koin.core.module.Module
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
val Scope.useCache: Boolean
|
||||
get() = getOrNull(named("useCache")) ?: false
|
||||
|
||||
val Koin.useCache: Boolean
|
||||
get() = getOrNull(named("useCache")) ?: false
|
||||
|
||||
fun Module.useCache(useCache: Boolean) {
|
||||
single(named("useCache")) { useCache }
|
||||
}
|
@ -10,6 +10,8 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.booleanOrNull
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.koin.core.Koin
|
||||
import org.koin.core.module.Module
|
||||
@ -18,6 +20,8 @@ object CommonPlugin : Plugin {
|
||||
private val Log = logger
|
||||
override fun Module.setupDI(database: Database, params: JsonObject) {
|
||||
single { CoroutineScope(Dispatchers.Default + SupervisorJob()) }
|
||||
val useCache = (params["useCache"] as? JsonPrimitive) ?.booleanOrNull ?: true
|
||||
useCache(useCache)
|
||||
}
|
||||
|
||||
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||
|
@ -10,4 +10,4 @@ android.enableJetifier=true
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.0.9
|
||||
version=0.0.10
|
||||
|
@ -3,13 +3,13 @@
|
||||
kotlin = "1.7.22"
|
||||
kotlin-serialization = "1.4.1"
|
||||
|
||||
plagubot = "3.3.0"
|
||||
tgbotapi = "5.0.0"
|
||||
microutils = "0.16.4"
|
||||
plagubot = "3.5.0"
|
||||
tgbotapi = "5.2.1"
|
||||
microutils = "0.16.11"
|
||||
kslog = "0.5.4"
|
||||
krontab = "0.8.5"
|
||||
tgbotapi-libraries = "0.7.0"
|
||||
plagubot-plugins = "0.7.0"
|
||||
tgbotapi-libraries = "0.8.2"
|
||||
plagubot-plugins = "0.8.1"
|
||||
|
||||
dokka = "1.7.20"
|
||||
|
||||
|
@ -4,6 +4,9 @@ import com.benasher44.uuid.uuid4
|
||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.koin.getAllDistinct
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.cached
|
||||
import dev.inmo.micro_utils.repos.cache.full.cached
|
||||
import dev.inmo.micro_utils.repos.deleteById
|
||||
import dev.inmo.micro_utils.repos.id
|
||||
import dev.inmo.micro_utils.repos.set
|
||||
@ -12,6 +15,7 @@ import dev.inmo.micro_utils.repos.value
|
||||
import dev.inmo.plagubot.Plugin
|
||||
import dev.inmo.plaguposter.common.ChatConfig
|
||||
import dev.inmo.plaguposter.common.UnsuccessfulSymbol
|
||||
import dev.inmo.plaguposter.common.useCache
|
||||
import dev.inmo.plaguposter.posts.models.PostId
|
||||
import dev.inmo.plaguposter.posts.panel.repos.PostsMessages
|
||||
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||
@ -93,7 +97,12 @@ object Plugin : Plugin {
|
||||
val chatsConfig = koin.get<ChatConfig>()
|
||||
val config = koin.getOrNull<Config>() ?: Config()
|
||||
val api = koin.get<PanelButtonsAPI>()
|
||||
val postsMessages = PostsMessages(koin.get(), koin.get())
|
||||
val basePostsMessages = PostsMessages(koin.get(), koin.get())
|
||||
val postsMessages = if (koin.useCache) {
|
||||
basePostsMessages.cached(FullKVCache(), koin.get())
|
||||
} else {
|
||||
basePostsMessages
|
||||
}
|
||||
|
||||
postsRepo.newObjectsFlow.subscribeSafelyWithoutExceptions(this) {
|
||||
val firstContent = it.content.first()
|
||||
|
@ -4,6 +4,7 @@ import dev.inmo.kslog.common.logger
|
||||
import dev.inmo.kslog.common.w
|
||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.koin.singleWithBinds
|
||||
import dev.inmo.micro_utils.repos.deleteById
|
||||
import dev.inmo.plagubot.Plugin
|
||||
import dev.inmo.plaguposter.common.SuccessfulSymbol
|
||||
@ -13,6 +14,8 @@ import dev.inmo.plaguposter.common.ChatConfig
|
||||
import dev.inmo.plagubot.plugins.inline.queries.models.Format
|
||||
import dev.inmo.plagubot.plugins.inline.queries.models.OfferTemplate
|
||||
import dev.inmo.plagubot.plugins.inline.queries.repos.InlineTemplatesRepo
|
||||
import dev.inmo.plaguposter.common.useCache
|
||||
import dev.inmo.plaguposter.posts.cached.CachedPostsRepo
|
||||
import dev.inmo.plaguposter.posts.repo.*
|
||||
import dev.inmo.plaguposter.posts.sending.PostPublisher
|
||||
import dev.inmo.tgbotapi.extensions.api.delete
|
||||
@ -44,11 +47,16 @@ object Plugin : Plugin {
|
||||
}
|
||||
single { get<Json>().decodeFromJsonElement(Config.serializer(), configJson) }
|
||||
single { get<Config>().chats }
|
||||
single { ExposedPostsRepo(database) } binds arrayOf(
|
||||
PostsRepo::class,
|
||||
ReadPostsRepo::class,
|
||||
WritePostsRepo::class,
|
||||
)
|
||||
single { ExposedPostsRepo(database) }
|
||||
singleWithBinds<PostsRepo> {
|
||||
val base = get<ExposedPostsRepo>()
|
||||
|
||||
if (useCache) {
|
||||
CachedPostsRepo(base, get())
|
||||
} else {
|
||||
base
|
||||
}
|
||||
}
|
||||
single {
|
||||
val config = get<Config>()
|
||||
PostPublisher(get(), get(), config.chats.cacheChatId, config.chats.targetChatId, config.deleteAfterPublishing)
|
||||
|
49
posts/src/jvmMain/kotlin/cached/CachedPostsRepo.kt
Normal file
49
posts/src/jvmMain/kotlin/cached/CachedPostsRepo.kt
Normal file
@ -0,0 +1,49 @@
|
||||
package dev.inmo.plaguposter.posts.cached
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||
import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination
|
||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||
import dev.inmo.micro_utils.repos.CRUDRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.full.FullCRUDCacheRepo
|
||||
import dev.inmo.plaguposter.posts.models.NewPost
|
||||
import dev.inmo.plaguposter.posts.models.PostContentInfo
|
||||
import dev.inmo.plaguposter.posts.models.PostId
|
||||
import dev.inmo.plaguposter.posts.models.RegisteredPost
|
||||
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class CachedPostsRepo(
|
||||
private val parentRepo: PostsRepo,
|
||||
private val scope: CoroutineScope,
|
||||
private val kvCache: FullKVCache<PostId, RegisteredPost> = FullKVCache()
|
||||
) : PostsRepo, CRUDRepo<RegisteredPost, PostId, NewPost> by FullCRUDCacheRepo(
|
||||
parentRepo,
|
||||
kvCache,
|
||||
scope,
|
||||
{ it.id }
|
||||
) {
|
||||
override val removedPostsFlow: Flow<RegisteredPost> by parentRepo::removedPostsFlow
|
||||
|
||||
override suspend fun getIdByChatAndMessage(chatId: IdChatIdentifier, messageId: MessageIdentifier): PostId? {
|
||||
doForAllWithNextPaging(firstPageWithOneElementPagination) {
|
||||
kvCache.values(it).also {
|
||||
it.results.forEach {
|
||||
return it.takeIf {
|
||||
it.content.any { it.chatId == chatId && it.messageId == messageId }
|
||||
} ?.id ?: return@forEach
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun getPostCreationTime(postId: PostId): DateTime? = getById(postId) ?.created
|
||||
|
||||
override suspend fun getFirstMessageInfo(postId: PostId): PostContentInfo? = getById(postId) ?.content ?.firstOrNull()
|
||||
}
|
@ -65,7 +65,7 @@ object Plugin : Plugin {
|
||||
val newMessagesInfo = firstOf {
|
||||
add {
|
||||
listOf(
|
||||
waitContentMessage().filter {
|
||||
waitAnyContentMessage().filter {
|
||||
it.chat.id == state.context && it.content.textContentOrNull() ?.text != "/finish_post"
|
||||
}.take(1).first()
|
||||
)
|
||||
|
@ -1,6 +1,9 @@
|
||||
package dev.inmo.plaguposter.ratings.source.buttons
|
||||
|
||||
import com.soywiz.klock.DateFormat
|
||||
import dev.inmo.kslog.common.TagLogger
|
||||
import dev.inmo.kslog.common.d
|
||||
import dev.inmo.kslog.common.i
|
||||
import dev.inmo.micro_utils.coroutines.runCatchingSafely
|
||||
import dev.inmo.micro_utils.pagination.FirstPagePagination
|
||||
import dev.inmo.micro_utils.pagination.Pagination
|
||||
@ -63,6 +66,7 @@ suspend fun RatingsRepo.buildRatingButtons(
|
||||
postCreationTimeFormat: DateFormat = defaultPostCreationTimeFormat
|
||||
): InlineKeyboardMarkup {
|
||||
val postsByRatings = getPosts(rating .. rating, true).keys.paginate(pagination)
|
||||
TagLogger("RatingsButtonsBuilder").i { postsByRatings.results }
|
||||
return inlineKeyboard {
|
||||
if (postsByRatings.pagesNumber > 1) {
|
||||
row {
|
||||
@ -75,7 +79,7 @@ suspend fun RatingsRepo.buildRatingButtons(
|
||||
}
|
||||
}
|
||||
}
|
||||
postsByRatings.results.chunked(rowSize).map {
|
||||
postsByRatings.results.chunked(rowSize).forEach {
|
||||
row {
|
||||
it.forEach { postId ->
|
||||
val firstMessageInfo = postsRepo.getFirstMessageInfo(postId) ?: return@forEach
|
||||
|
@ -0,0 +1,15 @@
|
||||
package dev.inmo.plaguposter.ratings.source.repos
|
||||
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.cache.KeyValueCacheRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.full.cached
|
||||
import dev.inmo.plaguposter.common.ShortMessageInfo
|
||||
import dev.inmo.tgbotapi.types.PollIdentifier
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
class CachedPollsToMessagesInfoRepo(
|
||||
private val repo: PollsToMessagesInfoRepo,
|
||||
private val scope: CoroutineScope,
|
||||
private val kvCache: FullKVCache<PollIdentifier, ShortMessageInfo> = FullKVCache()
|
||||
) : PollsToMessagesInfoRepo, KeyValueRepo<PollIdentifier, ShortMessageInfo> by repo.cached(kvCache, scope)
|
@ -0,0 +1,15 @@
|
||||
package dev.inmo.plaguposter.ratings.source.repos
|
||||
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.full.cached
|
||||
import dev.inmo.plaguposter.common.ShortMessageInfo
|
||||
import dev.inmo.plaguposter.posts.models.PostId
|
||||
import dev.inmo.tgbotapi.types.PollIdentifier
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
class CachedPollsToPostsIdsRepo(
|
||||
private val repo: PollsToPostsIdsRepo,
|
||||
private val scope: CoroutineScope,
|
||||
private val kvCache: FullKVCache<PollIdentifier, PostId> = FullKVCache()
|
||||
) : PollsToPostsIdsRepo, KeyValueRepo<PollIdentifier, PostId> by repo.cached(kvCache, scope)
|
@ -67,8 +67,29 @@ object Plugin : Plugin {
|
||||
get<Json>().decodeFromJsonElement(Config.serializer(), params["ratingsPolls"] ?: error("Unable to load config for rating polls in $params"))
|
||||
}
|
||||
single<RatingsVariants>(ratingVariantsQualifier) { get<Config>().variants }
|
||||
single<PollsToPostsIdsRepo> { ExposedPollsToPostsIdsRepo(database) }
|
||||
single<PollsToMessagesInfoRepo> { ExposedPollsToMessagesInfoRepo(database) }
|
||||
|
||||
single { ExposedPollsToPostsIdsRepo(database) }
|
||||
single<PollsToPostsIdsRepo> {
|
||||
val base = get<ExposedPollsToPostsIdsRepo>()
|
||||
|
||||
if (useCache) {
|
||||
CachedPollsToPostsIdsRepo(base, get())
|
||||
} else {
|
||||
base
|
||||
}
|
||||
}
|
||||
|
||||
single { ExposedPollsToMessagesInfoRepo(database) }
|
||||
single<PollsToMessagesInfoRepo> {
|
||||
val base = get<ExposedPollsToMessagesInfoRepo>()
|
||||
|
||||
if (useCache) {
|
||||
CachedPollsToMessagesInfoRepo(base, get())
|
||||
} else {
|
||||
base
|
||||
}
|
||||
}
|
||||
|
||||
single<VariantTransformer> {
|
||||
val ratingsSettings = get<RatingsVariants>(ratingVariantsQualifier)
|
||||
VariantTransformer {
|
||||
|
61
ratings/src/commonMain/kotlin/repo/CachedRatingsRepo.kt
Normal file
61
ratings/src/commonMain/kotlin/repo/CachedRatingsRepo.kt
Normal file
@ -0,0 +1,61 @@
|
||||
package dev.inmo.plaguposter.ratings.repo
|
||||
|
||||
import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.cache.cache.FullKVCache
|
||||
import dev.inmo.micro_utils.repos.cache.full.FullKeyValueCacheRepo
|
||||
import dev.inmo.plaguposter.posts.models.PostId
|
||||
import dev.inmo.plaguposter.ratings.models.Rating
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
class CachedRatingsRepo(
|
||||
private val base: RatingsRepo,
|
||||
private val scope: CoroutineScope,
|
||||
private val kvCache: FullKVCache<PostId, Rating> = FullKVCache()
|
||||
) : RatingsRepo, KeyValueRepo<PostId, Rating> by FullKeyValueCacheRepo(base, kvCache, scope) {
|
||||
override suspend fun getPosts(
|
||||
range: ClosedRange<Rating>,
|
||||
reversed: Boolean,
|
||||
count: Int?,
|
||||
exclude: List<PostId>
|
||||
): Map<PostId, Rating> {
|
||||
val result = mutableMapOf<PostId, Rating>()
|
||||
|
||||
doForAllWithNextPaging {
|
||||
kvCache.keys(it).also {
|
||||
it.results.forEach {
|
||||
val rating = get(it) ?: return@forEach
|
||||
if (it !in exclude && rating in range) {
|
||||
result[it] = rating
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toMap()
|
||||
}
|
||||
|
||||
override suspend fun getPostsWithRatingGreaterEq(
|
||||
then: Rating,
|
||||
reversed: Boolean,
|
||||
count: Int?,
|
||||
exclude: List<PostId>
|
||||
): Map<PostId, Rating> = getPosts(
|
||||
then .. Rating(Double.MAX_VALUE),
|
||||
reversed,
|
||||
count,
|
||||
exclude
|
||||
)
|
||||
|
||||
override suspend fun getPostsWithRatingLessEq(
|
||||
then: Rating,
|
||||
reversed: Boolean,
|
||||
count: Int?,
|
||||
exclude: List<PostId>
|
||||
): Map<PostId, Rating> = getPosts(
|
||||
Rating(Double.MIN_VALUE) .. then,
|
||||
reversed,
|
||||
count,
|
||||
exclude
|
||||
)
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package dev.inmo.plaguposter.ratings
|
||||
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.micro_utils.koin.singleWithBinds
|
||||
import dev.inmo.micro_utils.repos.unset
|
||||
import dev.inmo.plagubot.Plugin
|
||||
import dev.inmo.plaguposter.common.useCache
|
||||
import dev.inmo.plaguposter.posts.exposed.ExposedPostsRepo
|
||||
import dev.inmo.plaguposter.posts.repo.PostsRepo
|
||||
import dev.inmo.plaguposter.ratings.exposed.ExposedRatingsRepo
|
||||
@ -16,11 +18,16 @@ import org.koin.dsl.binds
|
||||
|
||||
object Plugin : Plugin {
|
||||
override fun Module.setupDI(database: Database, params: JsonObject) {
|
||||
single { ExposedRatingsRepo(database) } binds arrayOf(
|
||||
RatingsRepo::class,
|
||||
ReadRatingsRepo::class,
|
||||
WriteRatingsRepo::class,
|
||||
)
|
||||
single { ExposedRatingsRepo(database) }
|
||||
singleWithBinds<RatingsRepo> {
|
||||
val base = get<ExposedRatingsRepo>()
|
||||
|
||||
if (useCache) {
|
||||
CachedRatingsRepo(base, get())
|
||||
} else {
|
||||
base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
|
||||
|
25
runner/nonsudo_deploy.sh
Executable file
25
runner/nonsudo_deploy.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
function send_notification() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
function assert_success() {
|
||||
"${@}"
|
||||
local status=${?}
|
||||
if [ ${status} -ne 0 ]; then
|
||||
send_notification "### Error ${status} at: ${BASH_LINENO[*]} ###"
|
||||
exit ${status}
|
||||
fi
|
||||
}
|
||||
|
||||
app=plaguposter
|
||||
version="`grep ../gradle.properties -e "^version=" | grep -e "[0-9.]*" -o`"
|
||||
server=insanusmokrassar
|
||||
|
||||
assert_success ../gradlew build
|
||||
assert_success docker build -t $app:"$version" .
|
||||
assert_success docker tag $app:"$version" $server/$app:$version
|
||||
assert_success docker tag $app:"$version" $server/$app:latest
|
||||
assert_success docker push $server/$app:$version
|
||||
assert_success docker push $server/$app:latest
|
Loading…
Reference in New Issue
Block a user