Compare commits

..

59 Commits

Author SHA1 Message Date
08b797bbc2 start integration FSM oriented plagubot version 2022-08-13 18:30:33 +06:00
fa00d11a39 update gradle wrapper 2022-08-13 18:09:38 +06:00
1ba3953dfa update dependencies 2022-08-13 18:09:19 +06:00
af86a64a48 start 2.1.0 2022-08-13 18:08:00 +06:00
60fe1b5df9 Update CHANGELOG.md 2022-08-06 01:10:41 +06:00
c50b35c66b Merge pull request #39 from InsanusMokrassar/2.0.0
2.0.0
2022-08-06 01:10:14 +06:00
b309d6c946 Update libs.versions.toml 2022-08-06 00:42:58 +06:00
4f2b0aa40c Update libs.versions.toml 2022-08-05 22:52:59 +06:00
2d38292b55 Update CHANGELOG.md 2022-08-05 22:11:37 +06:00
e177f3e47a Update libs.versions.toml 2022-08-05 22:08:01 +06:00
2872395045 start 2.0.0 2022-08-05 22:06:39 +06:00
e49302b750 Merge pull request #38 from InsanusMokrassar/1.4.1
1.4.1
2022-08-03 09:20:34 +06:00
60dac2067a Update CHANGELOG.md 2022-08-03 09:20:10 +06:00
fc1888923f Update libs.versions.toml 2022-08-01 09:33:27 +06:00
703d3b1d64 Update gradle.properties 2022-08-01 09:32:21 +06:00
34383c1f82 Merge pull request #37 from InsanusMokrassar/1.4.0
1.4.0
2022-07-30 20:32:21 +06:00
9ec5303aed Update CHANGELOG.md 2022-07-30 18:29:45 +06:00
351f6e59e1 Update libs.versions.toml 2022-07-30 18:29:26 +06:00
d4bc89eb2f start 1.4.0 and update kslog 2022-07-30 15:27:28 +06:00
00b8197b71 Merge pull request #36 from InsanusMokrassar/1.3.1
1.3.1
2022-07-22 21:11:52 +06:00
a090b4f13f Update CHANGELOG.md 2022-07-22 21:10:05 +06:00
b377b5ed4f Update dependencies 2022-07-22 20:03:24 +06:00
dde3317323 start 1.3.1 2022-07-22 20:02:33 +06:00
40de085f26 Merge pull request #35 from InsanusMokrassar/1.3.0
1.3.0
2022-07-11 12:32:34 +06:00
ce5b98d6c8 update kotlin 2022-07-11 12:27:55 +06:00
058c239690 start 1.3.0 2022-07-11 12:17:08 +06:00
43d49ac3cd Update CHANGELOG.md 2022-07-10 00:21:27 +06:00
b0fbcfd54f Merge pull request #34 from InsanusMokrassar/1.2.3
1.2.3
2022-07-10 00:20:53 +06:00
8f726cee82 start 1.2.3 and update tgbotapi 2022-07-09 23:11:29 +06:00
998968a9c1 Update github_release.gradle 2022-07-09 09:47:34 +06:00
d8d1860c5a Merge pull request #33 from InsanusMokrassar/1.2.2
1.2.2
2022-07-09 09:44:56 +06:00
7ffd5a1433 update dependencies 2022-07-09 00:12:24 +06:00
05e2ec1c0d start 1.2.2 2022-07-09 00:07:07 +06:00
819ed7720a Merge pull request #32 from InsanusMokrassar/1.2.1
1.2.1
2022-06-26 15:15:38 +06:00
c99e4ee188 Update CHANGELOG.md 2022-06-26 14:46:09 +06:00
a408cc5099 Update CHANGELOG.md 2022-06-26 14:45:55 +06:00
f1d3f48a6b Update libs.versions.toml 2022-06-26 14:44:13 +06:00
2777a260ae Update gradle.properties 2022-06-26 14:42:44 +06:00
155b9865a8 Merge pull request #31 from InsanusMokrassar/1.2.0
1.2.0
2022-06-22 09:05:33 +06:00
ecc17e50b9 update dependencies 2022-06-21 23:54:25 +06:00
ffafee3f43 start 1.2.0 2022-06-21 23:53:38 +06:00
b99bb9ee64 Merge pull request #30 from InsanusMokrassar/1.1.2
1.1.2
2022-06-20 20:59:53 +06:00
0dff596926 update dependencies and optimize imports 2022-06-20 20:58:38 +06:00
e0a19bb5e5 start 1.1.2 + add opportunity to load object plugins 2022-06-20 20:52:42 +06:00
5ec1c8c55f Merge pull request #29 from InsanusMokrassar/1.1.1
1.1.1
2022-06-11 19:20:33 +06:00
37fd9f39d3 fixes in logging 2022-06-11 19:19:19 +06:00
f9f56f6afb update dependencies and add logging 2022-06-11 19:15:09 +06:00
343c26a7f1 start 1.1.1 2022-06-08 17:14:50 +06:00
1b5361eb28 change version in properties 2022-06-08 17:13:46 +06:00
511ec904e9 start 1.1.0 and update tgbotapi 2022-06-08 17:13:46 +06:00
a3f59087e0 updates in dependencies and update bot setup logic 2022-06-08 17:13:46 +06:00
492c04e25f start 1.0.1 2022-06-08 17:13:46 +06:00
6b017c129f remove redundant config test and update build workflow 2022-06-08 17:13:46 +06:00
93829d3e0d add logging inside of plagubot 2022-06-08 17:13:46 +06:00
a5e7ac180d fill changelog 2022-06-08 17:13:46 +06:00
77ba1d686c complete 1.0.0 2022-06-08 17:13:46 +06:00
dec27b1c34 temporal progress 2022-06-08 17:13:46 +06:00
11c5a38b72 start migration 2022-06-08 17:13:46 +06:00
9521217765 start 1.0.0 2022-06-08 17:13:46 +06:00
24 changed files with 599 additions and 50 deletions

2
.gitignore vendored
View File

@@ -10,5 +10,7 @@ build/
out/ out/
local.properties local.properties
local.*
local.*/
config.json config.json
secret.gradle secret.gradle

View File

@@ -1,9 +1,91 @@
# Changelog # Changelog
## 1.0.1 ## 2.1.0
* `Versions`:
* `tgbotapi`: `3.1.0`
* `ktor`: `2.1.0`
* `microutils`: `0.12.1`
## 2.0.0
* `Versions`:
* `kotlin`: `1.7.10`
* `serialization`: `1.4.0-RC`
* `tgbotapi`: `3.0.2`
* `kslog`: `0.5.0`
* `uuid`: `0.5.0`
* `exposed`: `0.39.2`
## 1.4.1
* `Versions`:
* `tgbotapi`: `2.2.2`
* `kslog`: `0.4.2`
## 1.4.0
* `Versions`:
* `kslog`: `0.4.1`
## 1.3.1
* `Versions`:
* `tgbotapi`: `2.2.1`
* `microutils`: `0.11.13`
## 1.3.0
* `Versions` * `Versions`
* `tgbotapi`: `1.1.3` * `tgbotapi`: `2.2.0`
## 1.2.3
* `Versions`
* `tgbotapi`: `2.1.3`
## 1.2.2
* `Versions`
* `tgbotapi`: `2.1.2`
* `microutils`: `0.11.12`
* `coroutines`: `1.6.3`
* `ktor`: `2.0.3`
## 1.2.1
* `Versions`
* `tgbotapi`: `2.1.1`
* `microutils`: `0.11.6`
* `kslog`: `0.3.2`
## 1.2.0
* `Versions`
* `tgbotapi`: `2.1.0`
## 1.1.2
* `Versions`
* `tgbotapi`: `2.0.3`
* `microutils`: `0.11.3`
* `kslog`: `0.3.1`
* `Plugin`:
* Now it is possible to use `object`s of plugins instead of classes
## 1.1.1
* `Versions`
* `coroutines`: `1.6.2`
* `tgbotapi`: `2.0.2`
* `microutils`: `0.11.0`
* `ktor`: `2.0.2`
* `uuid`: `0.4.1`
## 1.1.0
* `Versions`
* `tgbotapi`: `2.0.0`
* `microutils`: `0.10.5` * `microutils`: `0.10.5`
* `Plugin`: * `Plugin`:
* All plugins will be loaded in parallel * All plugins will be loaded in parallel

View File

@@ -17,6 +17,7 @@ dependencies {
api libs.tgbotapi api libs.tgbotapi
api libs.microutils.repos.exposed api libs.microutils.repos.exposed
api libs.kslog
api libs.sqlite api libs.sqlite

View File

@@ -1,7 +1,9 @@
package dev.inmo.plagubot package dev.inmo.plagubot
import dev.inmo.plagubot.config.* import dev.inmo.kslog.common.KSLog
import kotlinx.coroutines.* import dev.inmo.kslog.common.i
import dev.inmo.plagubot.config.Config
import dev.inmo.plagubot.config.defaultJsonFormat
import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import java.io.File import java.io.File
@@ -11,10 +13,13 @@ import java.io.File
*/ */
@InternalSerializationApi @InternalSerializationApi
suspend fun main(args: Array<String>) { suspend fun main(args: Array<String>) {
KSLog.default = KSLog("PlaguBot")
val (configPath) = args val (configPath) = args
val file = File(configPath) val file = File(configPath)
KSLog.i("Start read config from ${file.absolutePath}")
val json = defaultJsonFormat.parseToJsonElement(file.readText()).jsonObject val json = defaultJsonFormat.parseToJsonElement(file.readText()).jsonObject
val config = defaultJsonFormat.decodeFromJsonElement(Config.serializer(), json) val config = defaultJsonFormat.decodeFromJsonElement(Config.serializer(), json)
KSLog.i("Config has been read")
PlaguBot(json, config).start().join() PlaguBot(json, config).start().join()
} }

View File

@@ -1,23 +1,21 @@
package dev.inmo.plagubot package dev.inmo.plagubot
import dev.inmo.kslog.common.*
import dev.inmo.tgbotapi.extensions.api.bot.getMe import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.send.reply import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import kotlinx.serialization.* import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin import org.koin.core.Koin
import org.koin.core.KoinApplication
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import org.koin.core.module.Module import org.koin.core.module.Module
import org.koin.dsl.module
@Serializable @Serializable
@SerialName("Hello") @SerialName("Hello")
class HelloPlugin : Plugin { object HelloPlugin : Plugin {
@Serializable @Serializable
data class HelloPluginConfig( data class HelloPluginConfig(
val print: String val print: String
@@ -30,8 +28,8 @@ class HelloPlugin : Plugin {
} }
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) { override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
println(koin.get<HelloPluginConfig>().print) logger.d { koin.get<HelloPluginConfig>().print }
println(getMe()) logger.dS { getMe().toString() }
onCommand("hello_world") { onCommand("hello_world") {
reply(it, "Hello :)") reply(it, "Hello :)")
} }

View File

@@ -1,10 +1,14 @@
package dev.inmo.plagubot package dev.inmo.plagubot
import dev.inmo.kslog.common.*
import dev.inmo.micro_utils.common.Warning
import dev.inmo.micro_utils.coroutines.runCatchingSafely import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.plagubot.config.* import dev.inmo.plagubot.config.Config
import dev.inmo.plagubot.config.defaultJsonFormat
import dev.inmo.tgbotapi.bot.ktor.telegramBot import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.webhook.deleteWebhook import dev.inmo.tgbotapi.extensions.api.webhook.deleteWebhook
import dev.inmo.tgbotapi.extensions.behaviour_builder.* import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviour
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -17,19 +21,19 @@ import org.koin.core.context.GlobalContext
import org.koin.core.module.Module import org.koin.core.module.Module
import org.koin.core.scope.Scope import org.koin.core.scope.Scope
import org.koin.dsl.module import org.koin.dsl.module
import java.util.logging.Level
import java.util.logging.Logger
val Scope.plagubot: PlaguBot val Scope.plagubot: PlaguBot
get() = get() get() = get()
val Koin.plagubot: PlaguBot
get() = get()
@OptIn(Warning::class)
@Serializable @Serializable
data class PlaguBot( data class PlaguBot(
private val json: JsonObject, private val json: JsonObject,
private val config: Config private val config: Config
) : Plugin { ) : Plugin {
@Transient
private val logger = Logger.getLogger("PlaguBot")
@Transient @Transient
private val bot = telegramBot(config.botToken) private val bot = telegramBot(config.botToken)
@@ -50,24 +54,24 @@ data class PlaguBot(
} }
} }
}.onFailure { e -> }.onFailure { e ->
logger.log(Level.WARNING, "Unable to load DI part of $it", e) logger.w("Unable to load DI part of $it", e)
}.getOrNull() }.getOrNull()
} }
) )
} }
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) { override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
config.plugins.map { config.plugins.map { plugin ->
launch { launch {
runCatchingSafely { runCatchingSafely {
logger.info("Start loading of $it") logger.i("Start loading of $plugin")
with(it) { with(plugin) {
setupBotPlugin(koin) setupBotPlugin(koin)
} }
}.onFailure { e -> }.onFailure { e ->
logger.log(Level.WARNING, "Unable to load bot part of $it", e) logger.w("Unable to load bot part of $plugin", e)
}.onSuccess { }.onSuccess {
logger.info("Complete loading of $it") logger.i("Complete loading of $plugin")
} }
} }
}.joinAll() }.joinAll()
@@ -79,26 +83,26 @@ data class PlaguBot(
suspend fun start( suspend fun start(
scope: CoroutineScope = CoroutineScope(Dispatchers.IO) scope: CoroutineScope = CoroutineScope(Dispatchers.IO)
): Job { ): Job {
logger.info("Start initialization") logger.i("Start initialization")
val koinApp = KoinApplication.init() val koinApp = KoinApplication.init()
koinApp.modules( koinApp.modules(
module { module {
setupDI(config.databaseConfig.database, json) setupDI(config.databaseConfig.database, json)
} }
) )
logger.info("Modules loaded") logger.i("Modules loaded")
GlobalContext.startKoin(koinApp) GlobalContext.startKoin(koinApp)
logger.info("Koin started") logger.i("Koin started")
lateinit var behaviourContext: BehaviourContext lateinit var behaviourContext: BehaviourContext
bot.buildBehaviour(scope = scope) { bot.buildBehaviour(scope = scope) {
logger.info("Start setup of bot part") logger.i("Start setup of bot part")
behaviourContext = this behaviourContext = this
setupBotPlugin(koinApp.koin) setupBotPlugin(koinApp.koin)
deleteWebhook() deleteWebhook()
} }
logger.info("Behaviour builder has been setup") logger.i("Behaviour builder has been setup")
return bot.startGettingOfUpdatesByLongPolling(scope = behaviourContext, updatesFilter = behaviourContext).also { return bot.startGettingOfUpdatesByLongPolling(scope = behaviourContext, updatesFilter = behaviourContext).also {
logger.info("Long polling has been started") logger.i("Long polling has been started")
} }
} }
} }

View File

@@ -1,9 +1,11 @@
package dev.inmo.plagubot.config package dev.inmo.plagubot.config
import dev.inmo.micro_utils.common.Warning
import dev.inmo.plagubot.Plugin import dev.inmo.plagubot.Plugin
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Warning("This API is internal and can be changed without notifications of mentions of changes")
@Serializable @Serializable
data class Config( data class Config(
val botToken: String, val botToken: String,

38
fsm/bot/build.gradle Normal file
View File

@@ -0,0 +1,38 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
id "org.jetbrains.kotlin.plugin.serialization"
id 'application'
}
project.group="$group"
project.version="$version"
apply from: "publish.gradle"
dependencies {
implementation libs.kt.stdlib
api libs.kt.coroutines
api libs.kt.serialization
api libs.jb.exposed.jdbc
api libs.tgbotapi
api libs.microutils.repos.exposed
api libs.kslog
api libs.sqlite
testImplementation libs.kt.test.junit
api project(":plagubot.bot")
api project(":plagubot.fsm.plugin")
}
application {
mainClassName = 'dev.inmo.plagubot.AppKt'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

81
fsm/bot/publish.gradle Normal file
View File

@@ -0,0 +1,81 @@
apply plugin: 'maven-publish'
task javadocJar(type: Jar) {
from javadoc
classifier = 'javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact javadocJar
artifact sourcesJar
pom {
resolveStrategy = Closure.DELEGATE_FIRST
description = "Base PlaguBot project"
name = "PlaguBot Bot"
url = "https://github.com/InsanusMokrassar/PlaguBot"
scm {
developerConnection = "scm:git:[fetch=]ssh://git@github.com/InsanusMokrassar/PlaguBot.git[push=]ssh://git@github.com/InsanusMokrassar/PlaguBot.git"
url = "ssh://git@github.com/InsanusMokrassar/PlaguBot.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Aleksei Ovsiannikov"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/PlaguBot/LICENSE"
}
}
}
repositories {
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
}
}
}
}
}
if (project.hasProperty("signing.gnupg.keyName")) {
apply plugin: 'signing'
signing {
useGpgCmd()
sign publishing.publications
}
task signAll {
tasks.withType(Sign).forEach {
dependsOn(it)
}
}
}

1
fsm/bot/publish.kpsb Normal file
View File

@@ -0,0 +1 @@
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/PlaguBot/LICENSE"}],"mavenConfig":{"name":"PlaguBot Bot","description":"Base PlaguBot project","url":"https://github.com/InsanusMokrassar/PlaguBot","vcsUrl":"ssh://git@github.com/InsanusMokrassar/PlaguBot.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"}],"repositories":[{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}

View File

@@ -0,0 +1,25 @@
package dev.inmo.plagubot
import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.i
import dev.inmo.plagubot.config.Config
import dev.inmo.plagubot.config.defaultJsonFormat
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.json.jsonObject
import java.io.File
/**
* This method by default expects one argument in [args] field: path to config
*/
@InternalSerializationApi
suspend fun main(args: Array<String>) {
KSLog.default = KSLog("PlaguBot")
val (configPath) = args
val file = File(configPath)
KSLog.i("Start read config from ${file.absolutePath}")
val json = defaultJsonFormat.parseToJsonElement(file.readText()).jsonObject
val config = defaultJsonFormat.decodeFromJsonElement(Config.serializer(), json)
KSLog.i("Config has been read")
FSMPlaguBot(json, config).start().join()
}

View File

@@ -0,0 +1,112 @@
package dev.inmo.plagubot
import dev.inmo.kslog.common.*
import dev.inmo.micro_utils.common.Warning
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.plagubot.config.Config
import dev.inmo.plagubot.config.defaultJsonFormat
import dev.inmo.plagubot.fsm.FSMPlugin
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.webhook.deleteWebhook
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.startGettingOfUpdatesByLongPolling
import kotlinx.coroutines.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonObject
import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin
import org.koin.core.KoinApplication
import org.koin.core.context.GlobalContext
import org.koin.core.module.Module
import org.koin.core.scope.Scope
import org.koin.dsl.module
val Scope.fsmPlagubot: FSMPlaguBot
get() = get()
val Koin.fsmPlagubot: FSMPlaguBot
get() = get()
@OptIn(Warning::class)
@Serializable
data class FSMPlaguBot(
private val json: JsonObject,
private val config: Config
) : FSMPlugin {
@Transient
private val bot = telegramBot(config.botToken)
override fun Module.setupDI(database: Database, params: JsonObject) {
single { config }
single { config.plugins }
single { config.databaseConfig }
single { config.databaseConfig.database }
single { defaultJsonFormat }
single { this@FSMPlaguBot }
includes(
config.plugins.mapNotNull {
runCatching {
module {
with(it) {
setupDI(database, params)
}
}
}.onFailure { e ->
logger.w("Unable to load DI part of $it", e)
}.getOrNull()
}
)
}
override suspend fun BehaviourContextWithFSM<*>.setupBotPlugin(koin: Koin) {
config.plugins.map { plugin ->
launch {
runCatchingSafely {
logger.i("Start loading of $plugin")
with(plugin) {
if (this is FSMPlugin) {
setupBotPlugin(koin) // use setupBotPlugin with BehaviourContextWithFSM as receiver
} else {
setupBotPlugin(koin) // use setupBotPlugin with BehaviourContext as receiver
}
}
}.onFailure { e ->
logger.w("Unable to load bot part of $plugin", e)
}.onSuccess {
logger.i("Complete loading of $plugin")
}
}
}.joinAll()
}
/**
* This method will create an [Job] which will be the main [Job] of ran instance
*/
suspend fun start(
scope: CoroutineScope = CoroutineScope(Dispatchers.IO)
): Job {
logger.i("Start initialization")
val koinApp = KoinApplication.init()
koinApp.modules(
module {
setupDI(config.databaseConfig.database, json)
}
)
logger.i("Modules loaded")
GlobalContext.startKoin(koinApp)
logger.i("Koin started")
lateinit var behaviourContext: BehaviourContext
bot.buildBehaviourWithFSM (scope = scope) {
logger.i("Start setup of bot part")
behaviourContext = this
setupBotPlugin(koinApp.koin)
deleteWebhook()
}
logger.i("Behaviour builder has been setup")
return bot.startGettingOfUpdatesByLongPolling(scope = behaviourContext, updatesFilter = behaviourContext).also {
logger.i("Long polling has been started")
}
}
}

View File

@@ -0,0 +1,37 @@
package dev.inmo.plagubot
import dev.inmo.kslog.common.*
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin
import org.koin.core.module.Module
@Serializable
@SerialName("Hello")
object HelloFSMPlugin : Plugin {
@Serializable
data class HelloPluginConfig(
val print: String
)
override fun Module.setupDI(database: Database, params: JsonObject) {
single {
get<Json>().decodeFromJsonElement(HelloPluginConfig.serializer(), params["helloPlugin"] ?: return@single null)
}
}
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
logger.d { koin.get<HelloPluginConfig>().print }
logger.dS { getMe().toString() }
onCommand("hello_world") {
reply(it, "Hello :)")
}
}
}

21
fsm/plugin/build.gradle Normal file
View File

@@ -0,0 +1,21 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
id "org.jetbrains.kotlin.plugin.serialization"
}
project.group="$group"
project.version="$version"
apply from: "publish.gradle"
dependencies {
implementation libs.kt.stdlib
api libs.tgbotapi.behaviourBuilder.fsm
api project(":plagubot.plugin")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

81
fsm/plugin/publish.gradle Normal file
View File

@@ -0,0 +1,81 @@
apply plugin: 'maven-publish'
task javadocJar(type: Jar) {
from javadoc
classifier = 'javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact javadocJar
artifact sourcesJar
pom {
resolveStrategy = Closure.DELEGATE_FIRST
description = "Base dependency for whole PlaguBot project"
name = "PlaguBot Plugin"
url = "https://github.com/InsanusMokrassar/PlaguBot"
scm {
developerConnection = "scm:git:[fetch=]ssh://git@github.com/InsanusMokrassar/PlaguBot.git[push=]ssh://git@github.com/InsanusMokrassar/PlaguBot.git"
url = "ssh://git@github.com/InsanusMokrassar/PlaguBot.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Aleksei Ovsiannikov"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/PlaguBot/LICENSE"
}
}
}
repositories {
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
}
}
}
}
}
if (project.hasProperty("signing.gnupg.keyName")) {
apply plugin: 'signing'
signing {
useGpgCmd()
sign publishing.publications
}
task signAll {
tasks.withType(Sign).forEach {
dependsOn(it)
}
}
}

1
fsm/plugin/publish.kpsb Normal file
View File

@@ -0,0 +1 @@
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/PlaguBot/LICENSE"}],"mavenConfig":{"name":"PlaguBot Plugin","description":"Base dependency for whole PlaguBot project","url":"https://github.com/InsanusMokrassar/PlaguBot","vcsUrl":"ssh://git@github.com/InsanusMokrassar/PlaguBot.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"}],"repositories":[{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}

View File

@@ -0,0 +1,24 @@
package dev.inmo.plagubot.fsm
import dev.inmo.plagubot.Plugin
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextWithFSM
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject
import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin
import org.koin.core.module.Module
/**
* **ANY REALIZATION OF [FSMPlugin] MUST HAVE CONSTRUCTOR WITH ABSENCE OF INCOMING PARAMETERS**
*
* Use this interface for your bot. It is possible to use [kotlinx.serialization.SerialName] annotations on your plugins
* to set up short name for your plugin. Besides, simple name of your class will be used as key for deserialization
* too.
*/
@Serializable(FSMPluginSerializer::class)
interface FSMPlugin : Plugin {
suspend fun BehaviourContextWithFSM<*>.setupBotPlugin(koin: Koin) {
(this as BehaviourContext).setupBotPlugin(koin)
}
}

View File

@@ -0,0 +1,25 @@
package dev.inmo.plagubot.fsm
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializer(FSMPlugin::class)
class FSMPluginSerializer : KSerializer<FSMPlugin> {
override val descriptor: SerialDescriptor
get() = String.serializer().descriptor
override fun deserialize(decoder: Decoder): FSMPlugin {
val kclass = Class.forName(decoder.decodeString()).kotlin
return (kclass.objectInstance ?: kclass.constructors.first { it.parameters.isEmpty() }.call()) as FSMPlugin
}
override fun serialize(encoder: Encoder, value: FSMPlugin) {
encoder.encodeString(
value::class.java.canonicalName
)
}
}

View File

@@ -23,7 +23,7 @@ if (new File(projectDir, "secret.gradle").exists()) {
owner "InsanusMokrassar" owner "InsanusMokrassar"
repo "PlaguBot" repo "PlaguBot"
tagName "${project.version}" tagName "v${project.version}"
releaseName "${project.version}" releaseName "${project.version}"
targetCommitish "${project.version}" targetCommitish "${project.version}"

View File

@@ -5,4 +5,4 @@ kotlin.js.generate.externals=true
kotlin.incremental=true kotlin.incremental=true
group=dev.inmo group=dev.inmo
version=1.0.1 version=2.1.0

View File

@@ -1,25 +1,26 @@
[versions] [versions]
kt = "1.6.21" kt = "1.7.10"
kt-serialization = "1.3.3" kt-serialization = "1.4.0-RC"
kt-coroutines = "1.6.1" kt-coroutines = "1.6.4"
microutils = "0.10.5" microutils = "0.12.1"
tgbotapi = "1.1.3" tgbotapi = "3.1.0"
kslog = "0.5.0"
jb-exposed = "0.38.2" jb-exposed = "0.39.2"
jb-dokka = "1.6.21" jb-dokka = "1.7.10"
sqlite = "3.36.0.3" sqlite = "3.36.0.3"
klock = "2.7.0" klock = "3.0.0"
uuid = "0.4.0" uuid = "0.5.0"
ktor = "2.0.1" ktor = "2.1.0"
gh-release = "2.3.7" gh-release = "2.4.1"
android-gradle = "7.0.4" android-gradle = "7.2.2"
dexcount = "3.1.0" dexcount = "3.1.0"
koin = "3.2.0" koin = "3.2.0"
@@ -31,7 +32,9 @@ kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", vers
kt-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kt-serialization" } kt-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kt-serialization" }
tgbotapi = { module = "dev.inmo:tgbotapi", version.ref = "tgbotapi" } tgbotapi = { module = "dev.inmo:tgbotapi", version.ref = "tgbotapi" }
tgbotapi-behaviourBuilder-fsm = { module = "dev.inmo:tgbotapi.behaviour_builder.fsm", version.ref = "tgbotapi" }
microutils-repos-exposed = { module = "dev.inmo:micro_utils.repos.exposed", version.ref = "microutils" } microutils-repos-exposed = { module = "dev.inmo:micro_utils.repos.exposed", version.ref = "microutils" }
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
koin = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -13,7 +13,8 @@ class PluginSerializer : KSerializer<Plugin> {
get() = String.serializer().descriptor get() = String.serializer().descriptor
override fun deserialize(decoder: Decoder): Plugin { override fun deserialize(decoder: Decoder): Plugin {
return Class.forName(decoder.decodeString()).getDeclaredConstructor().newInstance() as Plugin val kclass = Class.forName(decoder.decodeString()).kotlin
return (kclass.objectInstance ?: kclass.constructors.first { it.parameters.isEmpty() }.call()) as Plugin
} }
override fun serialize(encoder: Encoder, value: Plugin) { override fun serialize(encoder: Encoder, value: Plugin) {

View File

@@ -1,8 +1,13 @@
String[] toInclude = [":bot", ":plugin"] String[] toInclude = [":bot", ":plugin", ":fsm:bot", ":fsm:plugin"]
rootProject.name = 'plagubot' rootProject.name = 'plagubot'
toInclude.each { toInclude.each { originalName ->
include (it) String projectDirectory = "${rootProject.projectDir.getAbsolutePath()}${originalName.replace(":", File.separator)}"
project(it).name = "${rootProject.name}${it.replace(":", ".")}" String projectName = "${rootProject.name}${originalName.replace(":", ".")}"
String projectIdentifier = ":${projectName}"
include projectIdentifier
ProjectDescriptor project = project(projectIdentifier)
project.name = projectName
project.projectDir = new File(projectDirectory)
} }