Skip to content

Commit 3bdf980

Browse files
committed
refactor: clarify package declarations; decouple logics
1 parent 1fce1b2 commit 3bdf980

46 files changed

Lines changed: 661 additions & 676 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

detekt.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ buildUponDefaultConfig: true
33
style:
44
WildcardImport:
55
active: false
6+
MagicNumber:
7+
active: false

saltify-core/src/commonMain/kotlin/org/ntqqrev/saltify/core/SaltifyApplication.kt renamed to saltify-core/src/commonMain/kotlin/org/ntqqrev/saltify/SaltifyApplication.kt

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,68 @@
1-
package org.ntqqrev.saltify.core
2-
3-
import io.ktor.client.*
4-
import io.ktor.client.call.*
5-
import io.ktor.client.plugins.*
6-
import io.ktor.client.plugins.contentnegotiation.*
7-
import io.ktor.client.plugins.sse.*
8-
import io.ktor.client.plugins.websocket.*
9-
import io.ktor.client.request.*
10-
import io.ktor.http.*
11-
import io.ktor.serialization.kotlinx.*
12-
import io.ktor.serialization.kotlinx.json.*
13-
import io.ktor.util.logging.*
14-
import kotlinx.coroutines.*
15-
import kotlinx.coroutines.flow.*
1+
package org.ntqqrev.saltify
2+
3+
import io.ktor.client.HttpClient
4+
import io.ktor.client.call.body
5+
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
6+
import io.ktor.client.plugins.defaultRequest
7+
import io.ktor.client.plugins.sse.SSE
8+
import io.ktor.client.plugins.timeout
9+
import io.ktor.client.plugins.websocket.WebSockets
10+
import io.ktor.client.request.header
11+
import io.ktor.client.request.post
12+
import io.ktor.client.request.setBody
13+
import io.ktor.http.ContentType
14+
import io.ktor.http.HttpHeaders
15+
import io.ktor.http.contentType
16+
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
17+
import io.ktor.serialization.kotlinx.json.json
18+
import io.ktor.util.logging.KtorSimpleLogger
19+
import kotlinx.coroutines.CoroutineScope
20+
import kotlinx.coroutines.SupervisorJob
21+
import kotlinx.coroutines.cancel
22+
import kotlinx.coroutines.flow.MutableSharedFlow
23+
import kotlinx.coroutines.flow.MutableStateFlow
24+
import kotlinx.coroutines.flow.SharedFlow
25+
import kotlinx.coroutines.flow.StateFlow
26+
import kotlinx.coroutines.flow.asSharedFlow
27+
import kotlinx.coroutines.flow.asStateFlow
28+
import kotlinx.coroutines.job
29+
import kotlinx.coroutines.joinAll
30+
import kotlinx.coroutines.launch
1631
import kotlinx.serialization.json.decodeFromJsonElement
17-
import org.ntqqrev.milky.*
32+
import org.ntqqrev.milky.ApiEmptyStruct
33+
import org.ntqqrev.milky.ApiEndpoint
34+
import org.ntqqrev.milky.ApiGeneralResponse
35+
import org.ntqqrev.milky.Event
36+
import org.ntqqrev.milky.milkyJsonModule
1837
import org.ntqqrev.saltify.annotation.WithApiExtension
19-
import org.ntqqrev.saltify.dsl.SaltifyPluginContext
20-
import org.ntqqrev.saltify.dsl.config.SaltifyApplicationConfig
21-
import org.ntqqrev.saltify.entity.InstalledPlugin
22-
import org.ntqqrev.saltify.entity.RegisteredCommandInfo
38+
import org.ntqqrev.saltify.dsl.PluginBuilder
39+
import org.ntqqrev.saltify.dsl.config.ApplicationConfig
40+
import org.ntqqrev.saltify.internal.util.InstalledPlugin
41+
import org.ntqqrev.saltify.runtime.SaltifyComponent
42+
import org.ntqqrev.saltify.internal.util.ExceptionHandlerProvider
43+
import org.ntqqrev.saltify.runtime.command.RegisteredCommand
2344
import org.ntqqrev.saltify.exception.ApiCallException
24-
import org.ntqqrev.saltify.model.EventConnectionState
25-
import org.ntqqrev.saltify.model.EventConnectionType
45+
import org.ntqqrev.saltify.internal.app.SaltifyApplicationSSE
46+
import org.ntqqrev.saltify.internal.app.SaltifyApplicationWebSocket
2647
import org.ntqqrev.saltify.model.SaltifyComponentType
27-
import org.ntqqrev.saltify.util.coroutine.SaltifyComponent
28-
import org.ntqqrev.saltify.util.coroutine.SaltifyExceptionHandlerProvider
48+
import org.ntqqrev.saltify.model.event.EventConnectionState
49+
import org.ntqqrev.saltify.model.event.EventConnectionType
2950
import kotlin.coroutines.CoroutineContext
3051
import kotlin.time.Clock
3152

3253
/**
3354
* 一个 Saltify 应用实例
3455
*/
3556
@WithApiExtension
36-
public sealed class SaltifyApplication(@PublishedApi internal val config: SaltifyApplicationConfig) : AutoCloseable {
57+
public abstract class SaltifyApplication internal constructor(
58+
@PublishedApi internal val config: ApplicationConfig
59+
) : AutoCloseable {
3760
public companion object {
3861
/**
3962
* 创建一个 Saltify 应用实例。
4063
*/
41-
public operator fun invoke(block: SaltifyApplicationConfig.() -> Unit): SaltifyApplication {
42-
val config = SaltifyApplicationConfig().apply(block)
64+
public operator fun invoke(block: ApplicationConfig.() -> Unit): SaltifyApplication {
65+
val config = ApplicationConfig().apply(block)
4366
return when (config.connection.event.type) {
4467
EventConnectionType.WebSocket -> SaltifyApplicationWebSocket(config)
4568
EventConnectionType.SSE -> SaltifyApplicationSSE(config)
@@ -50,12 +73,12 @@ public sealed class SaltifyApplication(@PublishedApi internal val config: Saltif
5073
internal val logger = KtorSimpleLogger("Saltify/main")
5174

5275
@PublishedApi
53-
internal val exceptionHandlerProvider: SaltifyExceptionHandlerProvider = SaltifyExceptionHandlerProvider()
76+
internal val exceptionHandlerProvider: ExceptionHandlerProvider = ExceptionHandlerProvider()
5477

5578
/**
5679
* 全局异常流。
5780
*
58-
* 可以通过 [SaltifyComponent] 判断异常抛出位置。
81+
* 可以通过 [org.ntqqrev.saltify.runtime.SaltifyComponent] 判断异常抛出位置。
5982
*
6083
* ```kotlin
6184
* client.exceptionFlow.collect { (context, exception) ->
@@ -77,7 +100,7 @@ public sealed class SaltifyApplication(@PublishedApi internal val config: Saltif
77100

78101
internal val applicationScope: CoroutineScope = CoroutineScope(
79102
SaltifyComponent(SaltifyComponentType.Application, "SaltifyApplication") +
80-
exceptionHandlerProvider.handler
103+
exceptionHandlerProvider.handler
81104
)
82105

83106
protected val events: MutableSharedFlow<Event> = MutableSharedFlow(extraBufferCapacity = 64)
@@ -92,15 +115,15 @@ public sealed class SaltifyApplication(@PublishedApi internal val config: Saltif
92115
@PublishedApi
93116
internal val extensionScope: CoroutineScope = CoroutineScope(
94117
applicationScope.coroutineContext +
95-
SupervisorJob(applicationScope.coroutineContext.job) +
96-
SaltifyComponent(SaltifyComponentType.Extension, "SaltifyExtension")
118+
SupervisorJob(applicationScope.coroutineContext.job) +
119+
SaltifyComponent(SaltifyComponentType.Extension, "SaltifyExtension")
97120
)
98121

99122
protected val addressBaseNormalized: String = config.connection.baseUrl.trimEnd('/')
100123

101-
private val loadedPlugins = mutableListOf<SaltifyPluginContext>()
124+
private val loadedPlugins = mutableListOf<PluginBuilder>()
102125

103-
internal val commandRegistry: MutableList<RegisteredCommandInfo> = mutableListOf()
126+
internal val commandRegistry: MutableList<RegisteredCommand> = mutableListOf()
104127

105128
@PublishedApi
106129
internal val accessToken: String? = config.connection.accessToken
@@ -138,11 +161,11 @@ public sealed class SaltifyApplication(@PublishedApi internal val config: Saltif
138161

139162
val pluginScope = CoroutineScope(
140163
applicationScope.coroutineContext +
141-
SupervisorJob(applicationScope.coroutineContext.job) +
142-
SaltifyComponent(SaltifyComponentType.Plugin, plugin.name)
164+
SupervisorJob(applicationScope.coroutineContext.job) +
165+
SaltifyComponent(SaltifyComponentType.Plugin, plugin.name)
143166
)
144167

145-
val context = SaltifyPluginContext(plugin.name, this, pluginScope)
168+
val context = PluginBuilder(this, pluginScope, plugin.name)
146169

147170
plugin.setup(context, configInstance)
148171
loadedPlugins.add(context)

saltify-core/src/commonMain/kotlin/org/ntqqrev/saltify/annotation/ContextParametersMigrationNeeded.kt

Lines changed: 0 additions & 7 deletions
This file was deleted.

saltify-core/src/commonMain/kotlin/org/ntqqrev/saltify/builtin/plugin/CommandHelp.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package org.ntqqrev.saltify.builtin.plugin
22

3-
import org.ntqqrev.saltify.core.forward
4-
import org.ntqqrev.saltify.core.node
5-
import org.ntqqrev.saltify.core.text
63
import org.ntqqrev.saltify.dsl.SaltifyPlugin
7-
import org.ntqqrev.saltify.entity.RegisteredCommandInfo
8-
import org.ntqqrev.saltify.entity.RegisteredSubCommandInfo
4+
import org.ntqqrev.saltify.runtime.command.RegisteredCommand
5+
import org.ntqqrev.saltify.runtime.command.RegisteredSubCommand
6+
import org.ntqqrev.saltify.extension.command
97
import org.ntqqrev.saltify.extension.respond
8+
import org.ntqqrev.saltify.forward
9+
import org.ntqqrev.saltify.node
10+
import org.ntqqrev.saltify.text
1011

1112
/**
1213
* Saltify 内置全局帮助指令插件。
@@ -49,7 +50,7 @@ public val commandHelp: SaltifyPlugin<Unit> = SaltifyPlugin("command-help") {
4950

5051
private fun buildCommandGroupText(
5152
pluginName: String?,
52-
commands: List<RegisteredCommandInfo>
53+
commands: List<RegisteredCommand>
5354
): String = buildString {
5455
if (pluginName != null) {
5556
appendLine("插件 $pluginName: ")
@@ -81,7 +82,7 @@ private fun buildCommandGroupText(
8182
}.trimEnd()
8283

8384
private fun StringBuilder.appendSubCommand(
84-
sub: RegisteredSubCommandInfo,
85+
sub: RegisteredSubCommand,
8586
parentPath: String,
8687
depth: Int
8788
) {

saltify-core/src/commonMain/kotlin/org/ntqqrev/saltify/builtin/plugin/DefaultLogging.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import kotlinx.coroutines.launch
55
import org.ntqqrev.milky.Event
66
import org.ntqqrev.milky.IncomingMessage
77
import org.ntqqrev.saltify.dsl.SaltifyPlugin
8+
import org.ntqqrev.saltify.extension.on
89
import org.ntqqrev.saltify.extension.plainText
9-
import org.ntqqrev.saltify.model.EventConnectionState
10+
import org.ntqqrev.saltify.model.event.EventConnectionState
1011
import org.ntqqrev.saltify.model.SaltifyComponentType
11-
import org.ntqqrev.saltify.util.coroutine.saltifyComponent
12+
import org.ntqqrev.saltify.runtime.saltifyComponent
1213

1314
/**
1415
* Saltify 内置日志插件。
@@ -54,7 +55,7 @@ public val defaultLogging: SaltifyPlugin<Unit> = SaltifyPlugin("default-logging"
5455
}
5556

5657
// 收到消息日志
57-
on<Event.MessageReceive> { event ->
58+
on<Event.MessageReceive> {
5859
when (val data = event.data) {
5960
is IncomingMessage.Group ->
6061
logger.debug(
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package org.ntqqrev.saltify.dsl
2+
3+
import org.ntqqrev.saltify.annotation.SaltifyDsl
4+
import org.ntqqrev.saltify.runtime.command.CommandRequirementMatch
5+
import org.ntqqrev.saltify.runtime.command.CommandParameter
6+
import org.ntqqrev.saltify.runtime.context.CommandExecutionContext
7+
import org.ntqqrev.saltify.model.command.CommandError
8+
import org.ntqqrev.saltify.model.command.CommandRequirement
9+
10+
@SaltifyDsl
11+
public class CommandBuilder internal constructor() {
12+
public val parameter: SaltifyParameterBuilder = SaltifyParameterBuilder(this)
13+
14+
@PublishedApi
15+
internal val parameters: MutableList<CommandParameter<*>> = mutableListOf()
16+
internal val subCommands = mutableListOf<Pair<String, CommandBuilder>>()
17+
internal var executionBlock: (suspend CommandExecutionContext.() -> Unit)? = null
18+
19+
/**
20+
* 指令的描述信息。
21+
*/
22+
public var description: String = ""
23+
24+
internal var groupExecutionBlock: (suspend CommandExecutionContext.() -> Unit)? = null
25+
internal var privateExecutionBlock: (suspend CommandExecutionContext.() -> Unit)? = null
26+
internal var failureBlock: (suspend CommandExecutionContext.(CommandError) -> Unit)? = null
27+
internal var requirementBlock: (CommandRequirementMatch.() -> CommandRequirement)? = null
28+
29+
/**
30+
* 注册一个子指令。
31+
*/
32+
public fun subCommand(name: String, block: CommandBuilder.() -> Unit) {
33+
subCommands.add(name to CommandBuilder().apply(block))
34+
}
35+
36+
/**
37+
* 定义指令执行要求。若不满足,静默返回。
38+
*/
39+
public fun require(block: CommandRequirementMatch.() -> CommandRequirement) {
40+
this.requirementBlock = block
41+
}
42+
43+
/**
44+
* 设置通用的指令执行逻辑。
45+
*/
46+
public fun onExecute(block: suspend CommandExecutionContext.() -> Unit) {
47+
executionBlock = block
48+
}
49+
50+
/**
51+
* 设置仅在群聊中触发的执行逻辑。优先级高于 [onExecute],定义后在群聊不会使用 [onExecute]。
52+
*/
53+
public fun onGroupExecute(block: suspend CommandExecutionContext.() -> Unit) {
54+
groupExecutionBlock = block
55+
}
56+
57+
/**
58+
* 设置仅在私聊中触发的执行逻辑。优先级高于 [onExecute],定义后在群聊不会使用 [onExecute]。
59+
*/
60+
public fun onPrivateExecute(block: suspend CommandExecutionContext.() -> Unit) {
61+
privateExecutionBlock = block
62+
}
63+
64+
/**
65+
* 当指令**解析**失败时执行的逻辑。
66+
*/
67+
public fun onFailure(block: suspend CommandExecutionContext.(CommandError) -> Unit) {
68+
failureBlock = block
69+
}
70+
}
71+
72+
public class SaltifyParameterBuilder(@PublishedApi internal val context: CommandBuilder) {
73+
/**
74+
* 定义一个指令参数。请搭配 [CommandExecutionContext.value] 使用。
75+
*
76+
* @param isGreedy 是否是贪婪参数,即是否包含后面的所有剩余文本。
77+
* @param transform 将原始文本转化为目标类型的函数。
78+
*/
79+
public inline fun <reified T : Any> from(
80+
name: String,
81+
description: String,
82+
isGreedy: Boolean = false,
83+
noinline transform: (String) -> T?
84+
): CommandParameter<T> = CommandParameter(transform, T::class, name, description, isGreedy).also {
85+
context.parameters.add(it)
86+
}
87+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.ntqqrev.saltify.dsl
2+
3+
import io.ktor.util.logging.*
4+
import kotlinx.coroutines.CoroutineScope
5+
import org.ntqqrev.saltify.annotation.SaltifyDsl
6+
import org.ntqqrev.saltify.SaltifyApplication
7+
import org.ntqqrev.saltify.runtime.context.ApplicationContext
8+
9+
@SaltifyDsl
10+
public class PluginBuilder internal constructor(
11+
public override val client: SaltifyApplication,
12+
@PublishedApi internal val pluginScope: CoroutineScope,
13+
pluginName: String
14+
) : CoroutineScope by pluginScope, ApplicationContext(client) {
15+
internal val onStartHooks = mutableListOf<suspend () -> Unit>()
16+
internal val onStopHooks = mutableListOf<() -> Unit>()
17+
18+
public val logger: Logger = KtorSimpleLogger("Saltify/plugin:$pluginName")
19+
20+
/**
21+
* 插件被加载,即 [SaltifyApplication.Companion.invoke] 后执行的逻辑。
22+
*/
23+
public fun onStart(block: suspend () -> Unit) {
24+
onStartHooks.add(block)
25+
}
26+
27+
/**
28+
* 插件被卸载,即 [SaltifyApplication.close] 前执行的逻辑。
29+
*/
30+
public fun onStop(block: () -> Unit) {
31+
onStopHooks.add(block)
32+
}
33+
}
34+
35+
/**
36+
* 一个插件
37+
*/
38+
public class SaltifyPlugin<T : Any>(
39+
public val name: String,
40+
@PublishedApi internal val createConfig: () -> T,
41+
internal val setup: PluginBuilder.(T) -> Unit
42+
) {
43+
public companion object {
44+
/**
45+
* 创建一个插件。
46+
*
47+
* @param name 插件名,不填随机。
48+
*/
49+
public operator fun <T : Any> invoke(
50+
name: String = generateAnonymousName(),
51+
config: () -> T,
52+
setup: PluginBuilder.(config: T) -> Unit
53+
): SaltifyPlugin<T> = SaltifyPlugin(name, config, setup)
54+
55+
/**
56+
* 创建一个插件。
57+
*
58+
* @param name 插件名,不填随机。
59+
*/
60+
public operator fun invoke(
61+
name: String = generateAnonymousName(),
62+
setup: PluginBuilder.(Unit) -> Unit
63+
): SaltifyPlugin<Unit> = SaltifyPlugin(name, {}, setup)
64+
}
65+
}
66+
67+
private fun generateAnonymousName(): String =
68+
"anonymous-${(1..4).map { ('A'..'Z').random() }.joinToString("")}"

0 commit comments

Comments
 (0)