add target and telegram target

This commit is contained in:
InsanusMokrassar 2022-01-07 21:35:11 +06:00
parent 6171eb3c40
commit 3661c1ca73
20 changed files with 232 additions and 3 deletions

View File

@ -12,6 +12,7 @@ kotlin {
dependencies { dependencies {
api project(":postssystem.features.common.common") api project(":postssystem.features.common.common")
api project(":postssystem.features.content.common") api project(":postssystem.features.content.common")
api "dev.inmo:micro_utils.mime_types:$microutils_version"
} }
} }
} }

View File

@ -1,9 +1,14 @@
package dev.inmo.postssystem.features.content.binary.common package dev.inmo.postssystem.features.content.binary.common
import dev.inmo.micro_utils.common.ByteArrayAllocator
import dev.inmo.micro_utils.common.FileName
import dev.inmo.micro_utils.mime_types.MimeType
import dev.inmo.postssystem.features.content.common.Content import dev.inmo.postssystem.features.content.common.Content
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class BinaryContent( data class BinaryContent(
val bytes: ByteArray val filename: FileName,
) : Content val mimeType: MimeType,
val bytesAllocator: ByteArrayAllocator
) : Content

View File

@ -2,7 +2,8 @@ package dev.inmo.postssystem.features.content.common
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
typealias ContentId = String @Serializable
value class ContentId(val string: String)
/** /**
* Content which is planned to be registered in database * Content which is planned to be registered in database

View File

@ -0,0 +1,6 @@
package dev.inmo.postssystem.features.content.server
import dev.inmo.micro_utils.repos.CRUDRepo
import dev.inmo.postssystem.features.content.common.*
interface ServerContentStorage : ServerReadContentStorage, ServerWriteContentStorage, CRUDRepo<RegisteredContent, ContentId, Content>

View File

@ -0,0 +1,7 @@
package dev.inmo.postssystem.features.content.server
import dev.inmo.micro_utils.repos.ReadCRUDRepo
import dev.inmo.postssystem.features.content.common.ContentId
import dev.inmo.postssystem.features.content.common.RegisteredContent
interface ServerReadContentStorage : ReadCRUDRepo<RegisteredContent, ContentId>

View File

@ -0,0 +1,6 @@
package dev.inmo.postssystem.features.content.server
import dev.inmo.micro_utils.repos.WriteCRUDRepo
import dev.inmo.postssystem.features.content.common.*
interface ServerWriteContentStorage : WriteCRUDRepo<RegisteredContent, ContentId, Content>

View File

@ -0,0 +1,18 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api project(":postssystem.features.publication.common")
api project(":postssystem.features.common.client")
}
}
}
}

View File

@ -0,0 +1 @@
<manifest package="dev.inmo.postssystem.features.publication.client"/>

View File

@ -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 project(":postssystem.features.common.common")
api project(":postssystem.features.content.common")
api project(":postssystem.features.posts.common")
}
}
}
}

View File

@ -0,0 +1 @@
<manifest package="dev.inmo.postssystem.features.publication.common"/>

View File

@ -0,0 +1,19 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppJavaProjectPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api project(":postssystem.features.publication.common")
api project(":postssystem.features.common.server")
api project(":postssystem.features.content.server")
api project(":postssystem.features.posts.server")
}
}
}
}

View File

@ -0,0 +1,33 @@
package dev.inmo.postssystem.features.publication.server
import dev.inmo.micro_utils.coroutines.asyncSafelyWithoutExceptions
import dev.inmo.postssystem.features.content.server.ServerReadContentStorage
import dev.inmo.postssystem.features.posts.common.PostId
import dev.inmo.postssystem.features.posts.server.ServerReadPostsStorage
import kotlinx.coroutines.*
class PublicationManager (
private val targets: List<PublicationTarget>,
private val postsRepo: ServerReadPostsStorage,
private val contentRepo: ServerReadContentStorage,
private val scope: CoroutineScope
) {
suspend fun publish(
postId: PostId
) {
val post = postsRepo.getById(postId) ?: return
val content = post.content.map {
scope.async {
contentRepo.getById(it)
}
}.awaitAll().filterNotNull()
val publicationPost = PublicationPost(post, content)
targets.map {
scope.asyncSafelyWithoutExceptions {
it.publish(publicationPost)
}
}.awaitAll()
}
}

View File

@ -0,0 +1,11 @@
package dev.inmo.postssystem.features.publication.server
import dev.inmo.postssystem.features.content.common.RegisteredContent
import dev.inmo.postssystem.features.posts.common.RegisteredPost
import kotlinx.serialization.Serializable
@Serializable
data class PublicationPost(
val post: RegisteredPost,
val content: List<RegisteredContent>
)

View File

@ -0,0 +1,5 @@
package dev.inmo.postssystem.features.publication.server
fun interface PublicationTarget {
suspend fun publish(post: PublicationPost)
}

View File

@ -19,6 +19,8 @@ logback_version=1.2.10
uuid_version=0.3.1 uuid_version=0.3.1
klock_version=2.4.10 klock_version=2.4.10
tgbotapi_version=0.38.1
# Server # Server
kotlin_exposed_version=0.37.2 kotlin_exposed_version=0.37.2

View File

@ -21,6 +21,10 @@ dependencies {
api project(":postssystem.features.content.server") api project(":postssystem.features.content.server")
api project(":postssystem.features.content.text.server") api project(":postssystem.features.content.text.server")
api project(":postssystem.features.content.binary.server") api project(":postssystem.features.content.binary.server")
api project(":postssystem.features.publication.server")
api project(":postssystem.targets.telegram.publication.server")
api "io.ktor:ktor-server-netty:$ktor_version" api "io.ktor:ktor-server-netty:$ktor_version"
api "io.ktor:ktor-websockets:$ktor_version" api "io.ktor:ktor-websockets:$ktor_version"
api "org.jetbrains.exposed:exposed-jdbc:$kotlin_exposed_version" api "org.jetbrains.exposed:exposed-jdbc:$kotlin_exposed_version"

View File

@ -29,6 +29,9 @@ import dev.inmo.postssystem.features.content.binary.common.BinaryContentSerializ
import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator
import dev.inmo.postssystem.features.content.common.OtherContentSerializerModuleConfigurator import dev.inmo.postssystem.features.content.common.OtherContentSerializerModuleConfigurator
import dev.inmo.postssystem.features.content.text.common.TextContentSerializerModuleConfigurator import dev.inmo.postssystem.features.content.text.common.TextContentSerializerModuleConfigurator
import dev.inmo.postssystem.features.publication.server.PublicationManager
import dev.inmo.postssystem.features.publication.server.PublicationTarget
import dev.inmo.postssystem.targets.telegram.publication.server.PublicationTargetTelegram
import io.ktor.application.featureOrNull import io.ktor.application.featureOrNull
import io.ktor.application.log import io.ktor.application.log
import io.ktor.routing.Route import io.ktor.routing.Route
@ -129,6 +132,11 @@ fun getDIModule(
} }
singleWithBinds<RolesStorage<Role>> { RolesAggregator(getAll()) } singleWithBinds<RolesStorage<Role>> { RolesAggregator(getAll()) }
// Publication targets
singleWithRandomQualifier<PublicationTarget> { PublicationTargetTelegram(get(), get()) }
single { PublicationManager(getAll(), get(), get(), get()) }
// Roles checkers // Roles checkers
single<RolesChecker<Role>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker } single<RolesChecker<Role>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker }

View File

@ -45,6 +45,12 @@ String[] includes = [
":features:posts:client", ":features:posts:client",
":features:posts:server", ":features:posts:server",
":features:publication:common",
":features:publication:client",
":features:publication:server",
":targets:telegram:publication:server",
":server", ":server",
":client", ":client",
] ]

View File

@ -0,0 +1,22 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppJavaProjectPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api project(":postssystem.features.common.server")
api project(":postssystem.features.publication.server")
api project(":postssystem.features.content.binary.server")
api project(":postssystem.features.content.text.server")
api "dev.inmo:tgbotapi:$tgbotapi_version"
}
}
}
}

View File

@ -0,0 +1,54 @@
package dev.inmo.postssystem.targets.telegram.publication.server
import dev.inmo.micro_utils.mime_types.KnownMimeTypes
import dev.inmo.postssystem.features.content.binary.common.BinaryContent
import dev.inmo.postssystem.features.content.text.common.TextContent
import dev.inmo.postssystem.features.publication.server.PublicationPost
import dev.inmo.postssystem.features.publication.server.PublicationTarget
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.utils.shortcuts.executeUnsafe
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.requests.send.SendTextMessage
import dev.inmo.tgbotapi.requests.send.media.*
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.utils.StorageFile
import kotlinx.coroutines.delay
class PublicationTargetTelegram(
private val bot: TelegramBot,
private val targetChatId: ChatId
) : PublicationTarget {
override suspend fun publish(post: PublicationPost) {
post.content.mapNotNull {
val content = it.content
when (content) {
is BinaryContent -> {
val storageFile by lazy {
StorageFile(content.filename.name, content.bytesAllocator()).asMultipartFile()
}
when (content.mimeType) {
is KnownMimeTypes.Image.Jpeg,
is KnownMimeTypes.Image.Png -> {
SendPhoto(targetChatId, storageFile)
}
is KnownMimeTypes.Video.Mp4 -> {
SendVideo(targetChatId, storageFile)
}
is KnownMimeTypes.Audio.Mpeg -> {
SendAudio(targetChatId, storageFile)
}
else -> null
}
}
is TextContent -> {
SendTextMessage(targetChatId, content.text)
}
else -> null
}
}.forEach { request ->
bot.executeUnsafe(request, 3, 1000L)
delay(100L)
}
}
}