add target and telegram target

This commit is contained in:
2022-01-07 21:35:11 +06:00
parent 6171eb3c40
commit 3661c1ca73
20 changed files with 232 additions and 3 deletions
features
content
binary
common
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
features
content
binary
common
src
commonMain
kotlin
dev
inmo
postssystem
features
content
server
src
jvmMain
publication
client
common
server
build.gradle
src
jvmMain
kotlin
dev
inmo
gradle.properties
server
build.gradle
src
main
java
dev
inmo
postssystem
server
settings.gradle
targets/telegram/publication/server
build.gradle
src
jvmMain
kotlin
dev
inmo
postssystem
targets
telegram

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

@ -1,9 +1,14 @@
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 kotlinx.serialization.Serializable
@Serializable
data class BinaryContent(
val bytes: ByteArray
) : Content
val filename: FileName,
val mimeType: MimeType,
val bytesAllocator: ByteArrayAllocator
) : Content

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

@ -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>

@ -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>

@ -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>

@ -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")
}
}
}
}

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

@ -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")
}
}
}
}

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

@ -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")
}
}
}
}

@ -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()
}
}

@ -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>
)

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

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

@ -21,6 +21,10 @@ dependencies {
api project(":postssystem.features.content.server")
api project(":postssystem.features.content.text.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-websockets:$ktor_version"
api "org.jetbrains.exposed:exposed-jdbc:$kotlin_exposed_version"

@ -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.OtherContentSerializerModuleConfigurator
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.log
import io.ktor.routing.Route
@ -129,6 +132,11 @@ fun getDIModule(
}
singleWithBinds<RolesStorage<Role>> { RolesAggregator(getAll()) }
// Publication targets
singleWithRandomQualifier<PublicationTarget> { PublicationTargetTelegram(get(), get()) }
single { PublicationManager(getAll(), get(), get(), get()) }
// Roles checkers
single<RolesChecker<Role>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker }

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

@ -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"
}
}
}
}

@ -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)
}
}
}