@@ -36,6 +36,7 @@ import kotlinx.serialization.json.long
3636import kotlinx.serialization.modules.overwriteWith
3737import love.forte.simbot.annotations.FragileSimbotAPI
3838import love.forte.simbot.bot.JobBasedBot
39+ import love.forte.simbot.common.atomic.atomic
3940import love.forte.simbot.common.collectable.Collectable
4041import love.forte.simbot.common.collectable.flowCollectable
4142import love.forte.simbot.common.coroutines.IOOrDefault
@@ -86,6 +87,8 @@ import love.forte.simbot.logger.isDebugEnabled
8687import kotlin.concurrent.Volatile
8788import kotlin.coroutines.CoroutineContext
8889import kotlin.math.max
90+ import kotlin.properties.Delegates
91+ import kotlin.time.Duration
8992import kotlin.time.Duration.Companion.milliseconds
9093import kotlin.time.Duration.Companion.seconds
9194import love.forte.simbot.component.onebot.v11.event.RawEvent as OBRawEvent
@@ -102,46 +105,107 @@ internal class OneBotBotImpl(
102105 override val configuration : OneBotBotConfiguration ,
103106 override val component : OneBot11Component ,
104107 private val eventProcessor : EventProcessor ,
105- baseDecoderJson : Json ,
108+ private val baseDecoderJson : Json ,
106109) : OneBotBot, JobBasedBot() {
107110 companion object {
108111 private const val BASE_LOGGER_NAME =
109112 " love.forte.simbot.component.onebot.v11.core.bot.OneBotBot"
110113 }
111114
112115 override val subContext = coroutineContext.minusKey(Job )
113- override val decoderJson: Json = Json (baseDecoderJson) {
114- configuration.serializersModule?.also { confMd ->
115- serializersModule = serializersModule overwriteWith confMd
116- }
117- }
118116
119117 internal val logger = LoggerFactory .getLogger(" $BASE_LOGGER_NAME .$uniqueId " )
120118
121- private val eventServerHost = configuration.eventServerHost
122- private val connectMaxRetryTimes = configuration.wsConnectMaxRetryTimes
123- private val connectRetryDelay = max(configuration.wsConnectRetryDelayMillis, 0L ).milliseconds
119+ override lateinit var decoderJson: Json
120+ private set
121+
122+ private var eventServerHost: Url ? = null
123+ private var connectMaxRetryTimes by Delegates .notNull<Int >()
124+ private var connectRetryDelay by Delegates .notNull<Duration >()
125+
126+ override lateinit var apiHost: Url
127+ override var apiAccessToken: String? = null
128+ override var eventAccessToken: String? = null
124129
125- override val apiClient: HttpClient
126- private val wsClient: HttpClient ?
130+
131+ override lateinit var apiClient: HttpClient
132+ private set
133+
134+ private var wsClient: HttpClient ? = null
127135
128136 @ExperimentalCustomEventResolverApi
129- internal val customEventResolvers = configuration. customEventResolvers.toList()
137+ internal lateinit var customEventResolvers: List < CustomEventResolver >
130138
131- init {
132- apiClient = resolveHttpClient()
133- wsClient = if (eventServerHost != null ) {
139+ private val initLock = Mutex ()
140+ private val initialized = atomic(false )
141+
142+ override suspend fun initConfiguration (): Boolean {
143+ if (initialized.value) {
144+ return false
145+ }
146+
147+ initLock.withLock {
148+ if (initialized.value) {
149+ return false
150+ }
151+
152+ initDecoderJson()
153+ initHostAndConnectAndToken()
154+ initClients()
155+ initJobCompletion()
156+ initCustomEventResolvers()
157+
158+ initialized.value = true
159+ }
160+
161+ return true
162+ }
163+
164+ override val isConfigurationInitialized: Boolean
165+ get() = initialized.value
166+
167+ override val isConfigurationInitializing: Boolean
168+ get() = ! isConfigurationInitialized && initLock.isLocked
169+
170+ private fun initDecoderJson () {
171+ decoderJson = Json (baseDecoderJson) {
172+ configuration.serializersModule?.also { confMd ->
173+ serializersModule = serializersModule overwriteWith confMd
174+ }
175+ }
176+ }
177+
178+ private fun initHostAndConnectAndToken () {
179+ this .eventServerHost = configuration.eventServerHost
180+ this .connectMaxRetryTimes = configuration.wsConnectMaxRetryTimes
181+ this .connectRetryDelay = max(configuration.wsConnectRetryDelayMillis, 0L ).milliseconds
182+ this .apiHost = configuration.apiServerHost
183+ this .apiAccessToken = configuration.apiAccessToken
184+ this .eventAccessToken = configuration.eventAccessToken
185+
186+ }
187+
188+ private fun initClients () {
189+ this .apiClient = resolveHttpClient()
190+ this .wsClient = if (eventServerHost != null ) {
134191 resolveWsClient()
135192 } else {
136193 null
137194 }
195+ }
138196
197+ private fun initJobCompletion () {
139198 job.invokeOnCompletion {
140199 apiClient.close()
141200 wsClient?.close()
142201 }
143202 }
144203
204+ @OptIn(ExperimentalCustomEventResolverApi ::class )
205+ private fun initCustomEventResolvers () {
206+ this .customEventResolvers = configuration.customEventResolvers.toList()
207+ }
208+
145209 private val wsEnabled: Boolean
146210 get() = wsClient != null
147211
@@ -214,10 +278,6 @@ internal class OneBotBotImpl(
214278 }
215279 }
216280
217- override val apiHost: Url = configuration.apiServerHost
218-
219- override val apiAccessToken: String? = configuration.apiAccessToken
220- override val eventAccessToken: String? = configuration.eventAccessToken
221281
222282 override val id: ID = uniqueId.ID
223283
@@ -260,6 +320,7 @@ internal class OneBotBotImpl(
260320
261321 override suspend fun start (): Unit = startLock.withLock {
262322 job.ensureActive()
323+ initConfiguration()
263324
264325 // 更新个人信息
265326 val info = queryLoginInfo()
0 commit comments