Skip to content

Commit

Permalink
fix(spring-boot-starter): 修复 #531
Browse files Browse the repository at this point in the history
close #531
  • Loading branch information
ForteScarlet committed Dec 5, 2022
1 parent 19abd02 commit 972f9bd
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 88 deletions.
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ include(
// project test
include(
projectTest("boot"),
projectTest("spring-boot-starter"),
projectTest("jmh-duration"),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import love.forte.simbot.ExperimentalSimbotApi
import love.forte.simbot.application.Application
import love.forte.simbot.application.EventProvider
import love.forte.simbot.bot.*
import love.forte.simbot.utils.runInNoScopeBlocking
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
Expand All @@ -47,21 +48,21 @@ public open class SimbotSpringBootBotAutoRegisterBuildConfigure : BeanFactoryPos
logger.warn("No such bean (Application) definition, skip bot register.", nsbEx)
return
}

val customDecoderFactories = beanFactory.getBeansOfType<BotVerifyInfoDecoderFactory<*, *>>()

config(application, customDecoderFactories.values.toList())

}

@OptIn(ExperimentalSerializationApi::class, ExperimentalSimbotApi::class)
private fun config(application: Application, customDecoderFactories: List<BotVerifyInfoDecoderFactory<*, *>>) {
val resolver = PathMatchingResourcePatternResolver()

val decoderList = customDecoderFactories + StandardBotVerifyInfoDecoderFactory.supportDecoderFactories()

val configuration = application.configuration as? BootApplicationConfiguration

val botConfigResources = (configuration?.botConfigurationResources ?: emptyList())
.asSequence()
.flatMap {
Expand All @@ -80,40 +81,48 @@ public open class SimbotSpringBootBotAutoRegisterBuildConfigure : BeanFactoryPos
if (it.filename == null) {
logger.warn("Resource [{}]'s filename is null, skip.", it)
}

it.filename != null
}
.distinct()
.mapNotNull {
logger.debug("Resolved bot register resource: {}", it)
val decoderFactory = decoderList.findLast { decoder -> decoder.match(it.filename!!) }
// ?: null // err? warn?

if (decoderFactory == null) {
// 没有任何解码器能匹配此资源。
logger.warn("No decoders match bot resource [{}] in {}.", it, decoderList)
return@mapNotNull null
}

var botVerifyInfo: BotVerifyInfo? = null

if (it.isFile) {
kotlin.runCatching {
botVerifyInfo =
it.file.takeIf { f -> f.exists() }?.toPath()?.toBotVerifyInfo(decoderFactory)
?: return@runCatching
}.getOrNull()
}

botVerifyInfo ?: it.url.toBotVerifyInfo(decoderFactory)
}.toList()

if (botConfigResources.isNotEmpty()) {
application.botManagers

botConfigResources.forEach { res ->
register(application.providers, res).also { bot ->
if (bot == null) {
if (bot != null) {
val isAutoStart = (application.configuration as? BootApplicationConfiguration)?.isAutoStartBots != false
if (isAutoStart) {
val startResult = runInNoScopeBlocking(application.coroutineContext) { bot.start() }
logger.info("Bot info [{}] successfully registered as Bot(component={}, id={}) and the result of auto-start is {}", res, bot.component, bot.id, startResult)
} else {
logger.info("Bot info [{}] successfully registered as Bot(component={}, id={}]) but it does not start automatically", res, bot.component, bot.id)
}
} else {
logger.warn(
"Bot verify info [{}] not registered by any registrars, skip. The botRegistrar: {}",
res,
Expand All @@ -123,16 +132,16 @@ public open class SimbotSpringBootBotAutoRegisterBuildConfigure : BeanFactoryPos
}
}
}

}

private fun register(providers: List<EventProvider>, botVerifyInfo: BotVerifyInfo): Bot? {
logger.info("Registering bot with verify info [{}]", botVerifyInfo)
for (manager in providers) {
if (manager !is BotRegistrar) {
continue
}

try {
return manager.register(botVerifyInfo).also { bot ->
logger.debug(
Expand All @@ -147,11 +156,11 @@ public open class SimbotSpringBootBotAutoRegisterBuildConfigure : BeanFactoryPos
// ignore this.
}
}

logger.warn("Bot verify info [{}] is not matched by any manager, skip it.", botVerifyInfo)
return null
}

public companion object {
private val logger = LoggerFactory.getLogger(SimbotSpringBootBotAutoRegisterBuildConfigure::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import love.forte.simbot.event.EventListenerRegistrationDescription
import love.forte.simbot.event.EventListenerRegistrationDescriptionBuilder
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.factory.getBean
Expand All @@ -45,59 +44,59 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter
@Suppress("SpringJavaAutowiredMembersInspection")
@AutoConfigureAfter(SimbotSpringBootApplicationConfiguration::class)
public open class SimbotSpringBootListenerAutoRegisterBuildConfigure : BeanFactoryPostProcessor {
@Autowired(required = false)
private var listeners: List<EventListener>? = null

@Autowired(required = false)
private var listenerRegistrationDescriptions: List<EventListenerRegistrationDescription>? = null

@Autowired(required = false)
private var listenerBuilders: List<EventListenerBuilder>? = null

override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) {
logger.debug("Start listener auto register")
try {
val application = beanFactory.getBean<Application>()
config(application)
config(application, beanFactory)
} catch (nsbEx: NoSuchBeanDefinitionException) {
// ignore?
logger.warn("No such bean (Application) definition, skip listener register.", nsbEx)
}
}

@OptIn(ExperimentalSimbotApi::class)
private fun config(application: Application) {
logger.debug("The size of resolved listeners is {}", listeners?.size ?: -1)
logger.debug("The size of resolved listener builders is {}", listenerBuilders?.size ?: -1)

private fun config(application: Application, beanFactory: ConfigurableListableBeanFactory) {
val listeners = beanFactory.getBeansOfType(EventListener::class.java)
val listenerRegistrationDescriptions =
beanFactory.getBeansOfType(EventListenerRegistrationDescription::class.java)
val listenerBuilders = beanFactory.getBeansOfType(EventListenerBuilder::class.java)
logger.debug("The size of resolved listeners is {}", listeners.size)
logger.debug(
"The size of resolved listenerRegistrationDescriptions is {}",
listenerRegistrationDescriptions.size
)
logger.debug("The size of resolved listener builders is {}", listenerBuilders.size)

// listeners {
listeners?.forEach {
application.eventListenerManager.register(it)
logger.debug("Registered listener {}", it)
listeners.forEach { (name, listener) ->
application.eventListenerManager.register(listener)
logger.debug("Registered listener [{}] named {}", listener, name)
}
listenerRegistrationDescriptions?.forEach {
application.eventListenerManager.register(it)
logger.debug("Registered listener description {}", it)
listenerRegistrationDescriptions.forEach { (name, listener) ->
application.eventListenerManager.register(listener)
logger.debug("Registered listener description [{}] named {}", listener, name)
}
listenerBuilders?.forEach { builder ->
listenerBuilders.forEach { (name, builder) ->
if (builder is EventListenerRegistrationDescriptionBuilder) {
val description = builder.buildDescription()
application.eventListenerManager.register(description)
logger.debug(
"Registered listener registration description [{}] by builder [{}]",
"Registered listener registration description [{}] by builder [{}] named {}",
description,
builder
builder,
name
)

} else {
val listener = builder.build()
application.eventListenerManager.register(listener)
logger.debug("Registered listener [{}] by builder [{}]", listener, builder)
logger.debug("Registered listener [{}] by builder [{}] named {}", listener, builder, name)
}
}
// }
}

private companion object {
private val logger = LoggerFactory.getLogger(SimbotSpringBootListenerAutoRegisterBuildConfigure::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ package love.forte.simbot.core.application

import kotlinx.coroutines.Job
import love.forte.simbot.application.Application
import love.forte.simbot.application.BotManagers
import love.forte.simbot.bot.Bot
import love.forte.simbot.bot.BotManager
import love.forte.simbot.bot.BotVerifyInfo
import love.forte.simbot.bot.ComponentMismatchException
import love.forte.simbot.logger.LoggerFactory
import org.slf4j.Logger
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.cancellation.CancellationException
Expand All @@ -30,8 +36,12 @@ import kotlin.coroutines.cancellation.CancellationException
public abstract class BaseApplication : Application {
abstract override val coroutineContext: CoroutineContext
protected abstract val logger: Logger

override val botManagers: BotManagers by lazy { BotManagersImpl(providers.filterIsInstance<BotManager<*>>()) }


private val job: Job? get() = coroutineContext[Job]

override suspend fun join() {
job?.join()
}
Expand All @@ -50,4 +60,38 @@ public abstract class BaseApplication : Application {
}
}
}
}
}


private class BotManagersImpl(private val botManagers: List<BotManager<*>>) : BotManagers,
List<BotManager<*>> by botManagers {

override fun register(botVerifyInfo: BotVerifyInfo): Bot? {
logger.info("Registering bot with verify info [{}]", botVerifyInfo)
for (manager in this) {
try {
return manager.register(botVerifyInfo).also { bot ->
logger.debug(
"Bot verify info [{}] is registered as [{}] via manager [{}]",
botVerifyInfo,
bot,
manager
)
}
} catch (ignore: ComponentMismatchException) {
logger.debug("Bot verify info [{}] is not matched by manager {}, try next.", botVerifyInfo, manager)

}
}

return null
}

override fun toString(): String {
return "BotManagersImpl(managers=$botManagers)"
}

companion object {
private val logger = LoggerFactory.getLogger(BotManagersImpl::class)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import love.forte.simbot.ExperimentalSimbotApi
import love.forte.simbot.application.*
import love.forte.simbot.bot.Bot
import love.forte.simbot.bot.BotManager
import love.forte.simbot.bot.BotVerifyInfo
import love.forte.simbot.bot.ComponentMismatchException
import love.forte.simbot.core.event.SimpleEventListenerManager
import love.forte.simbot.logger.LoggerFactory
import love.forte.simbot.logger.logger
Expand Down Expand Up @@ -129,8 +125,6 @@ private class SimpleApplicationImpl(
) : SimpleApplication, BaseApplication() {
override val providers: List<EventProvider> = providerList.view()

override val botManagers: BotManagers = BotManagersImpl(providerList.filterIsInstance<BotManager<*>>())

override val coroutineContext = environment.coroutineContext
override val logger = environment.logger
}
Expand Down Expand Up @@ -189,36 +183,4 @@ private class SimpleApplicationBuilderImpl : SimpleApplicationBuilder,
}
}

private class BotManagersImpl(private val botManagers: List<BotManager<*>>) : BotManagers,
List<BotManager<*>> by botManagers {

override fun register(botVerifyInfo: BotVerifyInfo): Bot? {
logger.info("Registering bot with verify info [{}]", botVerifyInfo)
for (manager in this) {
try {
return manager.register(botVerifyInfo).also { bot ->
logger.debug(
"Bot verify info [{}] is registered as [{}] via manager [{}]",
botVerifyInfo,
bot,
manager
)
}
} catch (ignore: ComponentMismatchException) {
logger.debug("Bot verify info [{}] is not matched by manager {}, try next.", botVerifyInfo, manager)

}
}

return null
}

override fun toString(): String {
return "BotManagersImpl(managers=$botManagers)"
}

companion object {
private val logger = LoggerFactory.getLogger(BotManagersImpl::class)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
java
kotlin("jvm") // version "1.7.21"
id("org.springframework.boot") version "2.7.5"
id("io.spring.dependency-management") version "1.1.0"
}

repositories {
mavenCentral()
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")

implementation(project(":simbot-boots:simboot-core-spring-boot-starter"))
implementation("love.forte.simbot.component:simbot-component-mirai-core:3.0.0.0-beta.5")
}

tasks.withType<Test> {
useJUnitPlatform()
}
Loading

0 comments on commit 972f9bd

Please sign in to comment.