Skip to content

Commit 49dfaa9

Browse files
committed
feat(api): implement KookChannel updator and extend channel properties
1 parent b3f6fa1 commit 49dfaa9

File tree

8 files changed

+324
-29
lines changed

8 files changed

+324
-29
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,19 @@ simbot-common-suspend = { group = "love.forte.simbot.common", name = "simbot-com
3535
simbot-common-annotations = { group = "love.forte.simbot.common", name = "simbot-common-annotations", version.ref = "simbot" }
3636
simbot-common-loop = { group = "love.forte.simbot.common", name = "simbot-common-stage-loop", version.ref = "simbot" }
3737
simbot-gradle = { group = "love.forte.simbot.gradle", name = "simbot-gradle-suspendtransforms", version.ref = "simbot" }
38+
simbot-processor-classBuilder = { module = "love.forte.simbot.processor:simbot-processor-class-builder", version.ref = "simbot" }
3839

3940
# jetbrains-annotation
4041
jetbrains-annotations = "org.jetbrains:annotations:26.0.2"
4142

4243
# kotlinx-coroutines
4344
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
44-
kotlinx-coroutines-core-jvm = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core-jvm", version.ref = "kotlinx-coroutines" }
45-
kotlinx-coroutines-core-js = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core-js", version.ref = "kotlinx-coroutines" }
46-
kotlinx-coroutines-jdk8 = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-jdk8", version.ref = "kotlinx-coroutines" }
47-
kotlinx-coroutines-reactive = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactive", version.ref = "kotlinx-coroutines" }
48-
kotlinx-coroutines-reactor = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor", version.ref = "kotlinx-coroutines" }
49-
kotlinx-coroutines-rx2 = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-rx2", version.ref = "kotlinx-coroutines" }
50-
kotlinx-coroutines-rx3 = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-rx3", version.ref = "kotlinx-coroutines" }
51-
kotlinx-coroutines-guava = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-guava", version.ref = "kotlinx-coroutines" }
52-
kotlinx-coroutines-slf4j = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-slf4j", version.ref = "kotlinx-coroutines" }
53-
kotlinx-coroutines-play-services = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" }
5445
kotlinx-coroutines-debug = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-debug", version.ref = "kotlinx-coroutines" }
5546
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
5647

5748
# kotlinx-serialization
5849
kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinx-serialization" }
5950
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
60-
kotlinx-serialization-hocon = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-hocon", version.ref = "kotlinx-serialization" }
61-
kotlinx-serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf", version.ref = "kotlinx-serialization" }
62-
kotlinx-serialization-cbor = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-cbor", version.ref = "kotlinx-serialization" }
63-
kotlinx-serialization-properties = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-properties", version.ref = "kotlinx-serialization" }
6451

6552
# ktor
6653
## serialization

simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/api/channel/GetChannelListApi.kt

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,57 @@ public data class ChannelInfo @ApiResultType constructor(
123123
*/
124124
@SerialName("limit_amount")
125125
public val limitAmount: Int,
126+
127+
/**
128+
* @since 4.3.0
129+
*/
130+
@SerialName("guild_id")
131+
public val guildId: String = "",
132+
133+
/**
134+
* 主题
135+
* @since 4.3.0
136+
*/
137+
public val topic: String = "",
138+
139+
/**
140+
* 慢速模式。单位为秒。
141+
* @since 4.3.0
142+
*/
143+
@SerialName("slow_mode")
144+
public val slowMode: Int = 0,
145+
146+
/**
147+
* @since 4.3.0
148+
*/
149+
@SerialName("permission_overwrites")
150+
public val permissionOverwrites: List<PermissionOverwrite> = emptyList(),
151+
152+
/**
153+
* @since 4.3.0
154+
*/
155+
@SerialName("permission_sync")
156+
public val permissionSync: Int = 0,
157+
158+
/**
159+
* @since 4.3.0
160+
*/
161+
@SerialName("has_password")
162+
public val hasPassword: Boolean = false,
126163
)
127164

128165
/**
129166
* 将 [ChannelInfo] 转化为 [Channel] 类型,
130167
* 并可选的提供一些缺失字段的默认值。
131168
*/
132169
public fun ChannelInfo.toChannel(
133-
guildId: String,
134-
topic: String = "",
135-
slowMode: Int = 0,
136-
permissionOverwrites: List<PermissionOverwrite> = emptyList(),
170+
guildId: String = this.guildId,
171+
topic: String = this.topic,
172+
slowMode: Int = this.slowMode,
173+
permissionOverwrites: List<PermissionOverwrite> = this.permissionOverwrites,
137174
permissionUsers: List<PermissionUser> = emptyList(),
138-
permissionSync: Int = 0,
139-
hasPassword: Boolean = false,
175+
permissionSync: Int = this.permissionSync,
176+
hasPassword: Boolean = this.hasPassword,
140177
): Channel = ChannelInfoChannel(
141178
this,
142179
guildId = guildId,

simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/api/channel/GetChannelViewApi.kt

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ import io.ktor.http.*
2121
import kotlinx.serialization.DeserializationStrategy
2222
import kotlinx.serialization.SerialName
2323
import kotlinx.serialization.Serializable
24+
import love.forte.simbot.kook.InternalKookApi
2425
import love.forte.simbot.kook.api.ApiResultType
2526
import love.forte.simbot.kook.api.KookGetApi
27+
import love.forte.simbot.kook.objects.Channel
28+
import love.forte.simbot.kook.objects.PermissionOverwrite
29+
import love.forte.simbot.kook.objects.PermissionUser
30+
import love.forte.simbot.kook.util.BooleanToIntSerializer
2631
import love.forte.simbot.kook.util.parameters
2732
import kotlin.jvm.JvmOverloads
2833
import kotlin.jvm.JvmStatic
@@ -110,20 +115,18 @@ public data class ChannelView @ApiResultType constructor(
110115

111116
/** 是否为分组类型 */
112117
@SerialName("is_category")
113-
public val isCategory: Boolean = type == 0,
118+
@Serializable(BooleanToIntSerializer::class)
119+
public val isCategory: Boolean = false,
114120

115121
/** 语音服务器地址,HOST:PORT的格式 */
116122
@SerialName("server_url")
117123
val serverUrl: String,
118124

119-
// maybe miss
120-
121-
// /**
122-
// * 针对角色的频道权限覆盖
123-
// */
124-
// @SerialName("permission_overwrites")
125-
// public val permissionOverwrites: List<ChannelPermissionOverwrites> = emptyList(),
126-
// TODO permissionOverwrites
125+
/**
126+
* 针对角色的频道权限覆盖
127+
*/
128+
@SerialName("permission_overwrites")
129+
public val permissionOverwrites: List<PermissionOverwrite> = emptyList(),
127130

128131
/**
129132
* 针对用户的频道权限覆盖
@@ -145,3 +148,72 @@ public data class ChannelView @ApiResultType constructor(
145148
*/
146149
public val children: List<String>? = null
147150
)
151+
152+
/**
153+
* 将 [ChannelView] 转化为 [Channel] 类型,
154+
* 并可选的提供一些缺失字段的默认值。
155+
*
156+
* @since 4.3.0
157+
*/
158+
@InternalKookApi
159+
public fun ChannelView.toChannel(
160+
permissionUsers: List<PermissionUser> = emptyList(),
161+
): Channel = ChannelViewChannel(
162+
this,
163+
permissionUsers = permissionUsers,
164+
)
165+
166+
private class ChannelViewChannel(
167+
private val channelView: ChannelView,
168+
override val permissionUsers: List<PermissionUser>,
169+
) : Channel {
170+
override val id: String
171+
get() = channelView.id
172+
override val name: String
173+
get() = channelView.name
174+
override val userId: String
175+
get() = channelView.userId
176+
override val guildId: String
177+
get() = channelView.guildId
178+
override val topic: String
179+
get() = channelView.topic
180+
override val isCategory: Boolean
181+
get() = channelView.isCategory
182+
override val parentId: String
183+
get() = channelView.parentId
184+
override val level: Int
185+
get() = channelView.level
186+
override val slowMode: Int
187+
get() = channelView.slowMode
188+
override val type: Int
189+
get() = channelView.type
190+
override val permissionSync: Int
191+
get() = channelView.permissionSync
192+
override val hasPassword: Boolean
193+
get() = channelView.hasPassword
194+
override val permissionOverwrites: List<PermissionOverwrite>
195+
get() = channelView.permissionOverwrites
196+
197+
override fun toString(): String {
198+
return "ChannelViewChannel(channelView=$channelView, permissionOverwrites=$permissionOverwrites, permissionUsers=$permissionUsers)"
199+
}
200+
201+
override fun equals(other: Any?): Boolean {
202+
if (this === other) return true
203+
if (other !is ChannelViewChannel) return false
204+
205+
if (channelView != other.channelView) return false
206+
if (permissionOverwrites != other.permissionOverwrites) return false
207+
if (permissionUsers != other.permissionUsers) return false
208+
209+
return true
210+
}
211+
212+
override fun hashCode(): Int {
213+
var result = channelView.hashCode()
214+
result = 31 * result + permissionOverwrites.hashCode()
215+
result = 31 * result + permissionUsers.hashCode()
216+
return result
217+
}
218+
}
219+

simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/KookChannel.kt

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ import love.forte.simbot.common.id.ID
2424
import love.forte.simbot.common.id.StringID.Companion.ID
2525
import love.forte.simbot.component.kook.bot.KookBot
2626
import love.forte.simbot.definition.Channel
27+
import love.forte.simbot.kook.api.channel.UpdateChannelApi
2728
import love.forte.simbot.suspendrunner.ST
2829
import kotlin.coroutines.CoroutineContext
30+
import kotlin.time.Duration
31+
import kotlin.time.Duration.Companion.seconds
2932
import love.forte.simbot.kook.objects.Channel as KChannel
3033

3134

@@ -67,6 +70,63 @@ public interface KookChannel : Channel, DeleteSupport {
6770
override val name: String
6871
get() = source.name
6972

73+
/**
74+
* 频道创建者id
75+
* @since 4.3.0
76+
*/
77+
public val userId: ID
78+
get() = source.userId.ID
79+
80+
/**
81+
* 频道所属服务器id
82+
* @since 4.3.0
83+
*/
84+
public val guildId: ID
85+
get() = source.guildId.ID
86+
87+
/**
88+
* 频道简介
89+
* @since 4.3.0
90+
*/
91+
public val topic: String
92+
get() = source.topic
93+
94+
/**
95+
* 上级分组的id
96+
* @since 4.3.0
97+
*/
98+
public val parentId: ID
99+
get() = source.parentId.ID
100+
101+
/**
102+
* 频道排序level
103+
* @since 4.3.0
104+
*/
105+
public val level: Int
106+
get() = source.level
107+
108+
/**
109+
* 慢速模式下限制发言的最短时间间隔, 单位为秒(s)
110+
* @since 4.3.0
111+
* @see slowModeDuration
112+
*/
113+
public val slowMode: Int
114+
get() = source.slowMode
115+
116+
/**
117+
* 权限设置是否与分组同步, 1 or 0
118+
* @since 4.3.0
119+
*/
120+
public val permissionSync: Int
121+
get() = source.permissionSync
122+
123+
/**
124+
* 是否有密码
125+
* @since 4.3.0
126+
*/
127+
public val hasPassword: Boolean
128+
get() = source.hasPassword
129+
70130
/**
71131
* 删除此频道。
72132
*
@@ -87,4 +147,29 @@ public interface KookChannel : Channel, DeleteSupport {
87147
*/
88148
@ST
89149
override suspend fun delete(vararg options: DeleteOption)
150+
151+
/**
152+
* 获取一个频道更新器。
153+
* 提供需要修改的内容,然后使用 [KookChannelUpdator.execute] 更新频道数据。
154+
*
155+
* @since 4.3.0
156+
*/
157+
public fun updator(): KookChannelUpdator
90158
}
159+
160+
/**
161+
* 获取频道的慢速模式的持续时间。
162+
* @since 4.3.0
163+
*/
164+
public val KookChannel.slowModeDuration: Duration
165+
get() = when (slowMode) {
166+
0 -> Duration.ZERO
167+
else -> slowMode.seconds
168+
}
169+
170+
/**
171+
* 使用 DSL 直接配置 [KookChannelUpdator.builder] 并更新频道信息。
172+
* @since 4.3.0
173+
*/
174+
public suspend inline fun KookChannel.update(block: UpdateChannelApi.Builder.() -> Unit): KookChannel =
175+
updator().apply { builder.block() }.execute()
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2025. ForteScarlet.
3+
*
4+
* This file is part of simbot-component-kook.
5+
*
6+
* simbot-component-kook is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* simbot-component-kook is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with simbot-component-kook,
18+
* If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package love.forte.simbot.component.kook
22+
23+
import love.forte.simbot.kook.api.ApiResponseException
24+
import love.forte.simbot.kook.api.channel.UpdateChannelApi
25+
import love.forte.simbot.suspendrunner.ST
26+
27+
/**
28+
* [KookChannel] 的更新器。
29+
* @since 4.3.0
30+
*/
31+
public interface KookChannelUpdator {
32+
public val channel: KookChannel
33+
34+
/**
35+
* 用于构建 [UpdateChannelApi] 的构建器。在 [execute] 中构建并执行。
36+
*/
37+
public var builder: UpdateChannelApi.Builder
38+
39+
/**
40+
* 使用当前的 [builder] 在DSL中配置更新信息。
41+
*/
42+
public fun applyBuilder(block: UpdateChannelApi.Builder.() -> UpdateChannelApi.Builder): KookChannelUpdator =
43+
apply {
44+
builder = builder.block()
45+
}
46+
47+
/**
48+
* 根据当前最终的 [builder] 信息,提供给 [UpdateChannelApi] 并执行更新。
49+
*
50+
* @see UpdateChannelApi
51+
*
52+
* @throws ApiResponseException 请求结果的状态码不是 200..300 之间
53+
* @throws love.forte.simbot.kook.api.ApiResultException 请求结果的 `code` 校验失败
54+
*/
55+
@ST
56+
public suspend fun execute(): KookChannel
57+
}

simbot-component-kook-core/src/commonMain/kotlin/love/forte/simbot/component/kook/internal/AbstractKookChatCapableChannelImpl.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import love.forte.simbot.ability.DeleteOption
2424
import love.forte.simbot.common.id.ID
2525
import love.forte.simbot.common.id.literal
2626
import love.forte.simbot.component.kook.KookCategory
27+
import love.forte.simbot.component.kook.KookChannelUpdator
2728
import love.forte.simbot.component.kook.KookChatCapableChannel
2829
import love.forte.simbot.component.kook.bot.internal.KookBotImpl
2930
import love.forte.simbot.component.kook.message.KookChannelMessageDetailsContent
@@ -68,6 +69,8 @@ internal abstract class AbstractKookChatCapableChannelImpl(
6869
override suspend fun delete(vararg options: DeleteOption) {
6970
bot.deleteChannel(source.id, options)
7071
}
72+
73+
override fun updator(): KookChannelUpdator = KookChannelUpdatorImpl(this, bot)
7174
}
7275

7376
internal suspend fun KookChatCapableChannel.send(

0 commit comments

Comments
 (0)