mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-01 20:10:18 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e27c9bd459
@ -2,6 +2,14 @@
|
||||
|
||||
开发版本. 频繁更新, 不保证高稳定性
|
||||
|
||||
## `0.15.1` Unreleased
|
||||
|
||||
### mirai-core
|
||||
- 统一异常处理: 所有群成员相关操作无权限时均抛出异常而不返回 `false`.
|
||||
|
||||
### mirai-core-qqandroid
|
||||
- 初始化未完成时缓存接收的所有事件包 (#46)
|
||||
|
||||
## `0.15.0` 2020/2/14
|
||||
|
||||
### mirai-core
|
||||
|
@ -2,6 +2,7 @@
|
||||
kotlin.code.style=official
|
||||
# config
|
||||
mirai_version=0.15.0
|
||||
mirai_japt_version=1.0.0
|
||||
kotlin.incremental.multiplatform=true
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
# kotlin
|
||||
|
@ -27,11 +27,6 @@ object NotVerifiedSessionException : IllegalAccessException("Session未激活")
|
||||
*/
|
||||
object NoSuchBotException: IllegalAccessException("指定Bot不存在")
|
||||
|
||||
/**
|
||||
* 指定Bot不存在
|
||||
*/
|
||||
object PermissionDeniedException: IllegalAccessException("无操作限权")
|
||||
|
||||
/**
|
||||
* 错误参数
|
||||
*/
|
||||
|
@ -35,6 +35,7 @@ import net.mamoe.mirai.api.http.data.common.DTO
|
||||
import net.mamoe.mirai.api.http.data.common.VerifyDTO
|
||||
import net.mamoe.mirai.api.http.util.jsonParseOrNull
|
||||
import net.mamoe.mirai.api.http.util.toJson
|
||||
import net.mamoe.mirai.contact.PermissionDeniedException
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.helpers.NOPLogger
|
||||
import org.slf4j.helpers.NOPLoggerFactory
|
||||
|
@ -4,7 +4,6 @@ import io.ktor.application.Application
|
||||
import io.ktor.application.call
|
||||
import io.ktor.routing.routing
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.api.http.data.PermissionDeniedException
|
||||
import net.mamoe.mirai.api.http.data.StateCode
|
||||
import net.mamoe.mirai.api.http.data.common.DTO
|
||||
import net.mamoe.mirai.api.http.data.common.VerifyDTO
|
||||
@ -19,37 +18,31 @@ fun Application.groupManageModule() {
|
||||
* 禁言(需要相关权限)
|
||||
*/
|
||||
miraiVerify<MuteDTO>("/muteAll") {
|
||||
it.session.bot.getGroup(it.target).muteAll = true
|
||||
it.session.bot.getGroup(it.target).isMuteAll = true
|
||||
call.respondStateCode(StateCode.Success)
|
||||
}
|
||||
|
||||
miraiVerify<MuteDTO>("/unmuteAll") {
|
||||
it.session.bot.getGroup(it.target).muteAll = false
|
||||
it.session.bot.getGroup(it.target).isMuteAll = false
|
||||
call.respondStateCode(StateCode.Success)
|
||||
}
|
||||
|
||||
miraiVerify<MuteDTO>("/mute") {
|
||||
when (it.session.bot.getGroup(it.target)[it.memberId].mute(it.time)) {
|
||||
true -> call.respondStateCode(StateCode.Success)
|
||||
else -> throw PermissionDeniedException
|
||||
}
|
||||
it.session.bot.getGroup(it.target)[it.memberId].mute(it.time)
|
||||
call.respondStateCode(StateCode.Success)
|
||||
}
|
||||
|
||||
miraiVerify<MuteDTO>("/unmute") {
|
||||
when (it.session.bot.getGroup(it.target).members[it.memberId].unmute()) {
|
||||
true -> call.respondStateCode(StateCode.Success)
|
||||
else -> throw PermissionDeniedException
|
||||
}
|
||||
it.session.bot.getGroup(it.target).members[it.memberId].unmute()
|
||||
call.respondStateCode(StateCode.Success)
|
||||
}
|
||||
|
||||
/**
|
||||
* 移出群聊(需要相关权限)
|
||||
*/
|
||||
miraiVerify<KickDTO>("/kick") {
|
||||
when (it.session.bot.getGroup(it.target)[it.memberId].kick(it.msg)) {
|
||||
true -> call.respondStateCode(StateCode.Success)
|
||||
else -> throw PermissionDeniedException
|
||||
}
|
||||
it.session.bot.getGroup(it.target)[it.memberId].kick(it.msg)
|
||||
call.respondStateCode(StateCode.Success)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,8 +58,8 @@ fun Application.groupManageModule() {
|
||||
with(dto.config) {
|
||||
name?.let { group.name = it }
|
||||
announcement?.let { group.entranceAnnouncement = it }
|
||||
confessTalk?.let { group.confessTalk = it }
|
||||
allowMemberInvite?.let { group.allowMemberInvite = it }
|
||||
confessTalk?.let { group.isConfessTalkEnabled = it }
|
||||
allowMemberInvite?.let { group.isAllowMemberInvite = it }
|
||||
// TODO: 待core接口实现设置可改
|
||||
// autoApprove?.let { group.autoApprove = it }
|
||||
// anonymousChat?.let { group.anonymousChat = it }
|
||||
@ -128,8 +121,8 @@ private data class GroupDetailDTO(
|
||||
val anonymousChat: Boolean? = null
|
||||
) : DTO {
|
||||
constructor(group: Group) : this(
|
||||
group.name, group.entranceAnnouncement, group.confessTalk, group.allowMemberInvite,
|
||||
group.autoApprove, group.anonymousChat
|
||||
group.name, group.entranceAnnouncement, group.isConfessTalkEnabled, group.isAllowMemberInvite,
|
||||
group.isAutoApproveEnabled, group.isAnonymousChatEnabled
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -227,9 +227,9 @@ internal class MemberImpl(
|
||||
|
||||
override val bot: QQAndroidBot get() = qq.bot
|
||||
|
||||
override suspend fun mute(durationSeconds: Int): Boolean {
|
||||
override suspend fun mute(durationSeconds: Int) {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
return false
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
@ -243,12 +243,11 @@ internal class MemberImpl(
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName") // or unresolved reference
|
||||
net.mamoe.mirai.event.events.MemberMuteEvent(this@MemberImpl, durationSeconds, null).broadcast()
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun unmute(): Boolean {
|
||||
override suspend fun unmute() {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
return false
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
@ -262,16 +261,15 @@ internal class MemberImpl(
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName") // or unresolved reference
|
||||
net.mamoe.mirai.event.events.MemberUnmuteEvent(this@MemberImpl, null).broadcast()
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun kick(message: String): Boolean {
|
||||
override suspend fun kick(message: String) {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
return false
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
return TroopManagement.Kick(
|
||||
TroopManagement.Kick(
|
||||
client = bot.client,
|
||||
member = this@MemberImpl,
|
||||
message = message
|
||||
@ -394,7 +392,7 @@ internal class GroupImpl(
|
||||
}
|
||||
|
||||
|
||||
override var allowMemberInvite: Boolean
|
||||
override var isAllowMemberInvite: Boolean
|
||||
get() = _allowMemberInvite
|
||||
set(newValue) {
|
||||
this.checkBotPermissionOperator()
|
||||
@ -414,19 +412,19 @@ internal class GroupImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override var autoApprove: Boolean
|
||||
override var isAutoApproveEnabled: Boolean
|
||||
get() = _autoApprove
|
||||
set(newValue) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override var anonymousChat: Boolean
|
||||
override var isAnonymousChatEnabled: Boolean
|
||||
get() = _anonymousChat
|
||||
set(newValue) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override var confessTalk: Boolean
|
||||
override var isConfessTalkEnabled: Boolean
|
||||
get() = _confessTalk
|
||||
set(newValue) {
|
||||
this.checkBotPermissionOperator()
|
||||
@ -447,7 +445,7 @@ internal class GroupImpl(
|
||||
}
|
||||
|
||||
|
||||
override var muteAll: Boolean
|
||||
override var isMuteAll: Boolean
|
||||
get() = _muteAll
|
||||
set(newValue) {
|
||||
this.checkBotPermissionOperator()
|
||||
|
@ -180,14 +180,14 @@ internal class OnlinePush {
|
||||
return if (target == 0L) {
|
||||
if (time == 0) {
|
||||
GroupMuteAllEvent(
|
||||
origin = group.muteAll.also { group._muteAll = false },
|
||||
origin = group.isMuteAll.also { group._muteAll = false },
|
||||
new = false,
|
||||
operator = operator,
|
||||
group = group
|
||||
)
|
||||
} else {
|
||||
GroupMuteAllEvent(
|
||||
origin = group.muteAll.also { group._muteAll = true },
|
||||
origin = group.isMuteAll.also { group._muteAll = true },
|
||||
new = true,
|
||||
operator = operator,
|
||||
group = group
|
||||
@ -213,7 +213,7 @@ internal class OnlinePush {
|
||||
val operator = group[this.readUInt().toLong()]
|
||||
val switch = this.readInt() == 0
|
||||
return GroupAllowAnonymousChatEvent(
|
||||
origin = group.anonymousChat.also { group._anonymousChat = switch },
|
||||
origin = group.isAnonymousChatEnabled.also { group._anonymousChat = switch },
|
||||
new = switch,
|
||||
operator = operator,
|
||||
group = group
|
||||
@ -236,7 +236,7 @@ internal class OnlinePush {
|
||||
when (message) {
|
||||
"管理员已关闭群聊坦白说" -> {
|
||||
return GroupAllowConfessTalkEvent(
|
||||
origin = group.confessTalk.also { group._confessTalk = false },
|
||||
origin = group.isConfessTalkEnabled.also { group._confessTalk = false },
|
||||
new = false,
|
||||
group = group,
|
||||
isByBot = false
|
||||
@ -244,7 +244,7 @@ internal class OnlinePush {
|
||||
}
|
||||
"管理员已开启群聊坦白说" -> {
|
||||
return GroupAllowConfessTalkEvent(
|
||||
origin = group.confessTalk.also { group._confessTalk = true },
|
||||
origin = group.isConfessTalkEnabled.also { group._confessTalk = true },
|
||||
new = true,
|
||||
group = group,
|
||||
isByBot = false
|
||||
|
@ -215,7 +215,7 @@ fun ByteReadPacket.readIoBuffer(
|
||||
* 解析 SSO 层包装
|
||||
*/
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactories.IncomingPacket {
|
||||
private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactories.IncomingPacket<*> {
|
||||
val commandName: String
|
||||
val ssoSequenceId: Int
|
||||
|
||||
@ -257,7 +257,7 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori
|
||||
* 解析 Uni 层包装
|
||||
*/
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingPacket {
|
||||
private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingPacket<*> {
|
||||
// 00 00 00 30 00 01 2F 7C 00 00 00 00 00 00 00 04 00 00 00 14 67 78 68 72 65 70 6F 72 74 2E 72 65 70 6F 72 74 00 00 00 08 66 82 D3 0B 00 00 00 00
|
||||
// 00 00 00 06 08 00
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
/**
|
||||
* 权限不足
|
||||
*/
|
||||
actual class PermissionDeniedException : IllegalStateException {
|
||||
actual constructor() : super("Permission denied")
|
||||
actual constructor(message: String?) : super(message)
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.mamoe.mirai.event.events
|
||||
|
||||
@Suppress("unused")
|
||||
actual class EventCancelledException : RuntimeException {
|
||||
actual constructor() : super()
|
||||
actual constructor(message: String?) : super(message)
|
||||
actual constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
actual constructor(cause: Throwable?) : super(cause)
|
||||
}
|
@ -27,6 +27,7 @@ import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.LoginFailedException
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.transferTo
|
||||
import kotlin.jvm.JvmStatic
|
||||
|
||||
/**
|
||||
* 机器人对象. 一个机器人实例登录一个 QQ 账号.
|
||||
@ -42,6 +43,7 @@ abstract class Bot : CoroutineScope {
|
||||
/**
|
||||
* 复制一份此时的 [Bot] 实例列表.
|
||||
*/
|
||||
@JvmStatic
|
||||
val instances: List<WeakRef<Bot>> get() = BotImpl.instances.toList()
|
||||
|
||||
/**
|
||||
@ -52,6 +54,7 @@ abstract class Bot : CoroutineScope {
|
||||
/**
|
||||
* 获取一个 [Bot] 实例, 找不到则 [NoSuchElementException]
|
||||
*/
|
||||
@JvmStatic
|
||||
fun instanceWhose(qq: Long): Bot = BotImpl.instanceWhose(qq = qq)
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,24 @@ data class BotAccount(
|
||||
val passwordMd5: ByteArray // md5
|
||||
) {
|
||||
constructor(id: Long, passwordPlainText: String) : this(id, md5(passwordPlainText.toByteArray()))
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as BotAccount
|
||||
|
||||
if (id != other.id) return false
|
||||
if (!passwordMd5.contentEquals(other.passwordMd5)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + passwordMd5.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,8 +38,8 @@ interface Contact : CoroutineScope {
|
||||
/**
|
||||
* 可以是 QQ 号码或者群号码.
|
||||
*
|
||||
* 对于 QQ, `uin` 与 `id` 是相同的意思.
|
||||
* 对于 Group, `groupCode` 与 `id` 是相同的意思.
|
||||
* 对于 [QQ], `uin` 与 `id` 是相同的意思.
|
||||
* 对于 [Group], `groupCode` 与 `id` 是相同的意思.
|
||||
*/
|
||||
val id: Long
|
||||
|
||||
|
@ -46,8 +46,9 @@ interface Group : Contact, CoroutineScope {
|
||||
* 当前仅能修改状态.
|
||||
*
|
||||
* @see GroupMuteAllEvent
|
||||
*/// TODO: 2020/2/5 实现 muteAll 的查询
|
||||
var muteAll: Boolean
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var isMuteAll: Boolean
|
||||
/**
|
||||
* 坦白说状态. `true` 为允许.
|
||||
*
|
||||
@ -56,7 +57,7 @@ interface Group : Contact, CoroutineScope {
|
||||
* @see GroupAllowConfessTalkEvent
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var confessTalk: Boolean
|
||||
var isConfessTalkEnabled: Boolean
|
||||
/**
|
||||
* 允许群员邀请好友入群的状态. `true` 为允许
|
||||
*
|
||||
@ -65,15 +66,15 @@ interface Group : Contact, CoroutineScope {
|
||||
* @see GroupAllowMemberInviteEvent
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
*/
|
||||
var allowMemberInvite: Boolean
|
||||
var isAllowMemberInvite: Boolean
|
||||
/**
|
||||
* 自动加群审批
|
||||
*/
|
||||
val autoApprove: Boolean
|
||||
val isAutoApproveEnabled: Boolean
|
||||
/**
|
||||
* 匿名聊天
|
||||
*/
|
||||
val anonymousChat: Boolean
|
||||
val isAnonymousChatEnabled: Boolean
|
||||
|
||||
/**
|
||||
* 同为 groupCode, 用户看到的群号码.
|
||||
@ -143,7 +144,7 @@ interface Group : Contact, CoroutineScope {
|
||||
|
||||
/**
|
||||
* by @kar98k
|
||||
*/
|
||||
*/ // don't @JvmStatic: JDK 1.8 required
|
||||
fun calculateGroupUinByGroupCode(groupCode: Long): Long {
|
||||
var left: Long = groupCode / 1000000L
|
||||
|
||||
|
@ -35,20 +35,22 @@ interface Member : QQ, Contact {
|
||||
/**
|
||||
* 群名片. 可能为空. 修改时将会触发事件
|
||||
*
|
||||
* 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException]
|
||||
* 在修改时将会异步上传至服务器.
|
||||
*
|
||||
* @see [groupCardOrNick] 获取非空群名片或昵称
|
||||
*
|
||||
* @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
var nameCard: String
|
||||
|
||||
/**
|
||||
* 群头衔
|
||||
*
|
||||
* 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException]
|
||||
* 在修改时将会异步上传至服务器.
|
||||
*
|
||||
* @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
var specialTitle: String
|
||||
|
||||
@ -63,22 +65,25 @@ interface Member : QQ, Contact {
|
||||
* @see Int.daysToSeconds
|
||||
*
|
||||
* @see MemberMuteEvent 成员被禁言事件
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
suspend fun mute(durationSeconds: Int): Boolean
|
||||
suspend fun mute(durationSeconds: Int)
|
||||
|
||||
/**
|
||||
* 解除禁言. 机器人无权限时返回 `false`.
|
||||
* 解除禁言.
|
||||
*
|
||||
* @see MemberUnmuteEvent 成员被取消禁言事件.
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
suspend fun unmute(): Boolean
|
||||
suspend fun unmute()
|
||||
|
||||
/**
|
||||
* 踢出该成员. 机器人无权限时返回 `false`.
|
||||
* 踢出该成员.
|
||||
*
|
||||
* @see MemberLeaveEvent.Kick 成员被踢出事件.
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
suspend fun kick(message: String = ""): Boolean
|
||||
suspend fun kick(message: String = "")
|
||||
|
||||
/**
|
||||
* 当且仅当 `[other] is [Member] && [other].id == this.id && [other].group == this.group` 时为 true
|
||||
@ -94,10 +99,10 @@ interface Member : QQ, Contact {
|
||||
val Member.groupCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick
|
||||
|
||||
@ExperimentalTime
|
||||
suspend inline fun Member.mute(duration: Duration): Boolean {
|
||||
suspend inline fun Member.mute(duration: Duration) {
|
||||
require(duration.inDays <= 30) { "duration must be at most 1 month" }
|
||||
require(duration.inSeconds > 0) { "duration must be greater than 0 second" }
|
||||
return this.mute(duration.inSeconds.toInt())
|
||||
this.mute(duration.inSeconds.toInt())
|
||||
}
|
||||
|
||||
suspend inline fun Member.mute(durationSeconds: Long) = this.mute(durationSeconds.toInt())
|
@ -72,9 +72,9 @@ inline fun Member.isOperator(): Boolean = this.permission.isOperator()
|
||||
/**
|
||||
* 权限不足
|
||||
*/
|
||||
class PermissionDeniedException : IllegalStateException {
|
||||
constructor() : super("Permission denied")
|
||||
constructor(message: String?) : super(message)
|
||||
expect class PermissionDeniedException : IllegalStateException {
|
||||
constructor()
|
||||
constructor(message: String?)
|
||||
}
|
||||
|
||||
@UseExperimental(MiraiExperimentalAPI::class)
|
||||
|
@ -438,14 +438,14 @@ class MessageSubscribersBuilder<T : MessagePacket<*, *>>(
|
||||
*/
|
||||
@MessageDsl
|
||||
inline fun <reified M : Message> has(): ListeningFilter =
|
||||
content { message.any { it::class == M::class } }
|
||||
content { message.any { it is M } }
|
||||
|
||||
/**
|
||||
* 如果消息内容包含 [M] 类型的 [Message], 就执行 [onEvent]
|
||||
*/
|
||||
@MessageDsl
|
||||
inline fun <reified M : Message> has(crossinline onEvent: MessageListener<T>): Listener<T> =
|
||||
content({ message.any { it::class == M::class } }, onEvent)
|
||||
content({ message.any { it is M } }, onEvent)
|
||||
|
||||
/**
|
||||
* 如果 [filter] 返回 `true`
|
||||
|
@ -22,11 +22,11 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
class EventCancelledException : RuntimeException {
|
||||
constructor() : super()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
expect class EventCancelledException : RuntimeException {
|
||||
constructor()
|
||||
constructor(message: String?)
|
||||
constructor(message: String?, cause: Throwable?)
|
||||
constructor(cause: Throwable?)
|
||||
}
|
||||
|
||||
// note: 若你使用 IntelliJ IDEA, 按 alt + 7 可打开结构
|
||||
|
@ -13,6 +13,7 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.message.data.At
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
@ -31,7 +32,7 @@ class GroupMessage(
|
||||
val permission: MemberPermission,
|
||||
sender: Member,
|
||||
override val message: MessageChain
|
||||
) : MessagePacket<Member, Group>(bot) {
|
||||
) : MessagePacket<Member, Group>(bot), Event {
|
||||
val group: Group by group.unsafeWeakRef()
|
||||
override val sender: Member by sender.unsafeWeakRef()
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.groupCardOrNick
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
|
||||
|
||||
@ -22,7 +23,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
*/
|
||||
class At @MiraiInternalAPI constructor(val target: Long, val display: String) : Message {
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
constructor(member: Member) : this(member.id, "@${member.nick}")
|
||||
constructor(member: Member) : this(member.id, "@${member.groupCardOrNick}")
|
||||
|
||||
override fun toString(): String = display
|
||||
|
||||
|
@ -44,6 +44,7 @@ internal val factory: BotFactory = run {
|
||||
/**
|
||||
* 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun Bot(context: Context, qq: Long, password: String, configuration: BotConfiguration = BotConfiguration.Default): Bot =
|
||||
factory.Bot(context, qq, password, configuration)
|
||||
|
||||
@ -57,6 +58,7 @@ inline fun Bot(context: Context, qq: Long, password: String, configuration: (Bot
|
||||
/**
|
||||
* 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun Bot(qq: Long, password: String, configuration: BotConfiguration = BotConfiguration.Default): Bot =
|
||||
factory.Bot(ContextImpl(), qq, password, configuration)
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
/**
|
||||
* 权限不足
|
||||
*/ // 不要删除多平台结构
|
||||
actual class PermissionDeniedException : IllegalStateException {
|
||||
actual constructor() : super("Permission denied")
|
||||
actual constructor(message: String?) : super(message)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package net.mamoe.mirai.event.events
|
||||
|
||||
|
||||
// 不要删除跨平台结构.
|
||||
// 否则在 Java 中这个 class 不会被认为是 java.lang.RuntimeException (Kotlin bug)
|
||||
@Suppress("unused")
|
||||
actual class EventCancelledException : RuntimeException {
|
||||
actual constructor() : super()
|
||||
actual constructor(message: String?) : super(message)
|
||||
actual constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
actual constructor(cause: Throwable?) : super(cause)
|
||||
}
|
@ -62,7 +62,7 @@ internal class DefaultLoginSolver : LoginSolver() {
|
||||
}
|
||||
}
|
||||
bot.logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车")
|
||||
return readLine()?.takeUnless { it.isEmpty() || it.length != 4 }.also {
|
||||
return readLine()!!.takeUnless { it.isEmpty() || it.length != 4 }.also {
|
||||
bot.logger.info("正在提交[$it]中...")
|
||||
}
|
||||
}
|
||||
|
18
mirai-demos/mirai-demo-java/build.gradle
Normal file
18
mirai-demos/mirai-demo-java/build.gradle
Normal file
@ -0,0 +1,18 @@
|
||||
apply plugin: "java"
|
||||
apply plugin: "kotlin"
|
||||
|
||||
dependencies {
|
||||
implementation files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
|
||||
|
||||
implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
|
||||
implementation project(":mirai-core-qqandroid")
|
||||
implementation project(":mirai-japt")
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
|
||||
compileTestJava.options.encoding = 'UTF-8'
|
@ -0,0 +1,28 @@
|
||||
package demo;
|
||||
|
||||
import net.mamoe.mirai.japt.BlockingBot;
|
||||
import net.mamoe.mirai.japt.BlockingContacts;
|
||||
import net.mamoe.mirai.japt.BlockingQQ;
|
||||
import net.mamoe.mirai.japt.Events;
|
||||
import net.mamoe.mirai.message.GroupMessage;
|
||||
|
||||
class BlockingTest {
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
BlockingBot bot = BlockingBot.newInstance(123456, "");
|
||||
|
||||
bot.login();
|
||||
|
||||
bot.getFriendList().forEach(friend -> {
|
||||
System.out.println(friend.getNick());
|
||||
});
|
||||
|
||||
Events.subscribeAlways(GroupMessage.class, (GroupMessage message) -> {
|
||||
final BlockingQQ sender = BlockingContacts.createBlocking(message.getSender());
|
||||
|
||||
sender.sendMessage("Hello");
|
||||
});
|
||||
|
||||
Thread.sleep(999999999);
|
||||
}
|
||||
}
|
BIN
mirai-japt/.README_images/0ff38fe6.png
Normal file
BIN
mirai-japt/.README_images/0ff38fe6.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
mirai-japt/.README_images/4SY8BC@J4ZKQM]7OZ_~BC1I_1.png
Normal file
BIN
mirai-japt/.README_images/4SY8BC@J4ZKQM]7OZ_~BC1I_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
BIN
mirai-japt/.README_images/722W(E$HTTX{D6XFFH]]$43.png
Normal file
BIN
mirai-japt/.README_images/722W(E$HTTX{D6XFFH]]$43.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
mirai-japt/.README_images/ce3034e3.png
Normal file
BIN
mirai-japt/.README_images/ce3034e3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
@ -3,7 +3,51 @@
|
||||
|
||||
Mirai Java Apt
|
||||
|
||||
提供一些阻塞/异步/RxJava API 来让 Java 调用 Mirai 的挂起函数 API 更容易
|
||||
提供 Utils 类来让 Java 调用 Mirai 的内联方法更容易
|
||||
提供阻塞API 来让 Java 调用 Mirai 的 API 更容易
|
||||
|
||||
该模块暂未完成.
|
||||
## Requirements
|
||||
|
||||
- JDK 1.8+
|
||||
|
||||
## 开始
|
||||
|
||||
```java
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
BlockingBot bot = BlockingBot.newInstance(123456, "");
|
||||
|
||||
bot.login();
|
||||
|
||||
bot.getFriendList().forEach(friend -> {
|
||||
System.out.println(friend.getNick());
|
||||
});
|
||||
|
||||
Events.subscribeAlways(GroupMessage.class, (GroupMessage message) -> {
|
||||
final BlockingQQ sender = BlockingContacts.createBlocking(message.getSender());
|
||||
|
||||
sender.sendMessage("Hello");
|
||||
});
|
||||
|
||||
Thread.sleep(999999999);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 便捷开发
|
||||
|
||||
在 IntelliJ IDEA 或 Android Studio 中找到设置 `Editor -> General -> Postfix Completion`, 添加一个设置到 `Java` 分类中:
|
||||
![](.README_images/ce3034e3.png)
|
||||
Applicable expression types:
|
||||
```
|
||||
net.mamoe.mirai.contact.Contact
|
||||
```
|
||||
转换后表达式:
|
||||
```
|
||||
net.mamoe.mirai.japt.BlockingContacts.createBlocking($EXPR$)
|
||||
```
|
||||
|
||||
效果:
|
||||
|
||||
![4SY8BC@J4ZKQM7OZ_~BC1I_1](.README_images/4SY8BC%40J4ZKQM%5D7OZ_~BC1I_1.png)
|
||||
|
||||
![722WEHTTXD6XFFH43](.README_images/722W%28E%24HTTX%7BD6XFFH%5D%5D%2443.png)
|
||||
|
@ -1,8 +1,12 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
java
|
||||
`maven-publish`
|
||||
id("com.jfrog.bintray") version "1.8.4-jetbrains-3" // DO NOT CHANGE THIS VERSION UNLESS YOU WANT TO WASTE YOUR TIME
|
||||
}
|
||||
|
||||
apply(from = rootProject.file("gradle/publish.gradle"))
|
||||
|
||||
val kotlinVersion: String by rootProject.ext
|
||||
val atomicFuVersion: String by rootProject.ext
|
||||
val coroutinesVersion: String by rootProject.ext
|
||||
@ -13,6 +17,12 @@ val serializationVersion: String by rootProject.ext
|
||||
val klockVersion: String by rootProject.ext
|
||||
val ktorVersion: String by rootProject.ext
|
||||
|
||||
description = "Java helper for Mirai"
|
||||
|
||||
@Suppress("PropertyName")
|
||||
val mirai_japt_version: String by rootProject.ext
|
||||
version = mirai_japt_version
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
all {
|
||||
@ -38,6 +48,8 @@ dependencies {
|
||||
api(kotlinx("io", kotlinXIoVersion))
|
||||
api(kotlinx("coroutines-io", coroutinesIoVersion))
|
||||
api(kotlinx("coroutines-core", coroutinesVersion))
|
||||
api(kotlin("stdlib-jdk7", kotlinVersion))
|
||||
api(kotlin("stdlib-jdk8", kotlinVersion))
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>() {
|
||||
|
@ -1,21 +1,57 @@
|
||||
package net.mamoe.mirai.japt;
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket;
|
||||
import net.mamoe.mirai.Bot;
|
||||
import net.mamoe.mirai.BotAccount;
|
||||
import net.mamoe.mirai.BotFactoryJvmKt;
|
||||
import net.mamoe.mirai.contact.QQ;
|
||||
import net.mamoe.mirai.data.AddFriendResult;
|
||||
import net.mamoe.mirai.data.GroupInfo;
|
||||
import net.mamoe.mirai.data.MemberInfo;
|
||||
import net.mamoe.mirai.message.data.Image;
|
||||
import net.mamoe.mirai.network.BotNetworkHandler;
|
||||
import net.mamoe.mirai.utils.BotConfiguration;
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI;
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI;
|
||||
import net.mamoe.mirai.utils.MiraiLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 对 {@link Bot} 的阻塞式包装
|
||||
*
|
||||
* @see Bot
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface BlockingBot {
|
||||
/**
|
||||
* 使用默认配置创建一个机器人实例
|
||||
*
|
||||
* @param id qq 号
|
||||
* @param password 密码
|
||||
* @return 机器人实例
|
||||
*/
|
||||
static BlockingBot newInstance(long id, String password) {
|
||||
return BlockingContacts.createBlocking(BotFactoryJvmKt.Bot(id, password));
|
||||
}
|
||||
|
||||
// TODO: 2020/2/3 需要更新
|
||||
/**
|
||||
* 使用特定配置创建一个机器人实例
|
||||
*
|
||||
* @param id qq 号
|
||||
* @param password 密码
|
||||
* @return 机器人实例
|
||||
*/
|
||||
static BlockingBot newInstance(long id, String password, BotConfiguration configuration) {
|
||||
return BlockingContacts.createBlocking(BotFactoryJvmKt.Bot(id, password, configuration));
|
||||
}
|
||||
|
||||
// 要获取 Bot 实例列表, 请前往 BotKt
|
||||
|
||||
/**
|
||||
* 账号信息
|
||||
@ -29,6 +65,13 @@ public interface BlockingBot {
|
||||
*/
|
||||
long getUin();
|
||||
|
||||
/**
|
||||
* 获取昵称
|
||||
*/
|
||||
@NotNull
|
||||
@MiraiExperimentalAPI(message = "还未支持")
|
||||
String getNick();
|
||||
|
||||
/**
|
||||
* 日志记录器
|
||||
*/
|
||||
@ -37,27 +80,33 @@ public interface BlockingBot {
|
||||
|
||||
// region contacts
|
||||
|
||||
/**
|
||||
* 获取自身 QQ 实例
|
||||
*/
|
||||
@NotNull
|
||||
QQ getSelfQQ();
|
||||
|
||||
/**
|
||||
* 与这个机器人相关的 QQ 列表. 机器人与 QQ 不一定是好友
|
||||
*/
|
||||
@NotNull
|
||||
List<BlockingQQ> getQQs();
|
||||
List<BlockingQQ> getFriendList();
|
||||
|
||||
/**
|
||||
* 获取缓存的 QQ 对象. 若没有对应的缓存, 则会线程安全地创建一个.
|
||||
*/
|
||||
@NotNull
|
||||
BlockingQQ getQQ(long id);
|
||||
BlockingQQ getFriend(long id);
|
||||
|
||||
/**
|
||||
* 与这个机器人相关的群列表. 机器人不一定是群成员.
|
||||
*/
|
||||
@NotNull
|
||||
List<BlockingGroup> getGroups();
|
||||
List<BlockingGroup> getGroupList();
|
||||
|
||||
/**
|
||||
* 获取缓存的群对象. 若没有对应的缓存, 则会线程安全地创建一个.
|
||||
* 若 {@code id} 无效, 将会抛出 {@link java.util.NoSuchElementException}
|
||||
* 若 {@code id} 无效, 将会抛出 {@link NoSuchElementException}
|
||||
*/
|
||||
@NotNull
|
||||
BlockingGroup getGroup(long id);
|
||||
@ -75,20 +124,48 @@ public interface BlockingBot {
|
||||
|
||||
/**
|
||||
* 登录.
|
||||
* <p>
|
||||
* 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.login]
|
||||
*/
|
||||
void login();
|
||||
|
||||
/**
|
||||
* 查询群列表. 返回值前 32 bits 为 uin, 后 32 bits 为 groupCode
|
||||
*/
|
||||
@NotNull
|
||||
Stream<Long> queryGroupList();
|
||||
|
||||
/**
|
||||
* 查询群资料. 获得的仅为当前时刻的资料.
|
||||
* 请优先使用 {@link #getGroup(long)} 然后查看群资料.
|
||||
*/
|
||||
@NotNull
|
||||
GroupInfo queryGroupInfo(long groupCode);
|
||||
|
||||
/**
|
||||
* 查询群成员列表.
|
||||
* 请优先使用 {@link #getGroup(long)} , {@link BlockingGroup#getMembers()} 查看群成员.
|
||||
* <p>
|
||||
* 这个函数很慢. 请不要频繁使用.
|
||||
*/
|
||||
@NotNull
|
||||
Stream<MemberInfo> queryGroupMemberList(long groupUin, long groupCode, long ownerId);
|
||||
|
||||
// endregion
|
||||
|
||||
// region actions
|
||||
|
||||
@NotNull
|
||||
byte[] downloadAsByteArray(@NotNull Image image);
|
||||
|
||||
@NotNull
|
||||
ByteReadPacket download(@NotNull Image image);
|
||||
|
||||
/**
|
||||
* 下载图片到 {@code outputStream}.
|
||||
* <p>
|
||||
* 不会自动关闭 {@code outputStream}
|
||||
*/
|
||||
void download(@NotNull Image image, @NotNull OutputStream outputStream);
|
||||
|
||||
/**
|
||||
* 添加一个好友
|
||||
*
|
||||
|
@ -1,34 +1,87 @@
|
||||
package net.mamoe.mirai.japt;
|
||||
|
||||
import net.mamoe.mirai.Bot;
|
||||
import net.mamoe.mirai.contact.Contact;
|
||||
import net.mamoe.mirai.contact.Member;
|
||||
import net.mamoe.mirai.contact.QQ;
|
||||
import net.mamoe.mirai.event.events.BeforeImageUploadEvent;
|
||||
import net.mamoe.mirai.event.events.EventCancelledException;
|
||||
import net.mamoe.mirai.event.events.ImageUploadEvent;
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent;
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent;
|
||||
import net.mamoe.mirai.message.data.Image;
|
||||
import net.mamoe.mirai.message.data.Message;
|
||||
import net.mamoe.mirai.message.data.MessageChain;
|
||||
import net.mamoe.mirai.utils.ExternalImage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* 对 {@link Contact} 的阻塞式包装.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface BlockingContact {
|
||||
/**
|
||||
* 这个联系人所属 [Bot]
|
||||
* 这个联系人所属 {@link Bot}
|
||||
*/
|
||||
@NotNull
|
||||
BlockingBot getBot();
|
||||
|
||||
/**
|
||||
* 可以是 QQ 号码或者群号码 [GroupId].
|
||||
* 可以是 QQ 号码或者群号码.
|
||||
* <p>
|
||||
* 对于 QQ, {@code uin} 与 {@code id} 是相同的意思.
|
||||
* 对于 Group, {@code groupCode} 与 {@code id} 是相同的意思.
|
||||
*/
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* 向这个对象发送消息.
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消
|
||||
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
|
||||
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
|
||||
* @see GroupMessageSendEvent 发送群消息事件. cancellable
|
||||
*/
|
||||
void sendMessage(@NotNull MessageChain messages);
|
||||
// kotlin bug
|
||||
void sendMessage(@NotNull MessageChain messages) throws EventCancelledException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* 向这个对象发送消息.
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消
|
||||
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
|
||||
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
|
||||
* @see GroupMessageSendEvent 发送群消息事件. cancellable
|
||||
*/
|
||||
void sendMessage(@NotNull String message);
|
||||
void sendMessage(@NotNull String message) throws EventCancelledException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* 向这个对象发送消息.
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消
|
||||
* @throws IllegalStateException 发送群消息时若 [Bot] 被禁言抛出
|
||||
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
|
||||
* @see GroupMessageSendEvent 发送群消息事件. cancellable
|
||||
*/
|
||||
void sendMessage(@NotNull Message message);
|
||||
void sendMessage(@NotNull Message message) throws EventCancelledException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* 上传一个图片以备发送.
|
||||
* 群图片与好友图片在服务器上是通用的, 在 mirai 目前不通用.
|
||||
*
|
||||
* @throws EventCancelledException 当发送消息事件被取消
|
||||
* @see BeforeImageUploadEvent 图片发送前事件, cancellable
|
||||
* @see ImageUploadEvent 图片发送完成事件
|
||||
*/
|
||||
Image uploadImage(@NotNull ExternalImage image) throws EventCancelledException;
|
||||
|
||||
/**
|
||||
* 判断 {@code this} 和 {@code other} 是否是相同的类型, 并且 {@link Contact#getId()} 相同.
|
||||
* <p>
|
||||
* 注:
|
||||
* {@link Contact#getId()} 相同的 {@link Member} 和 {@link QQ}, 他们并不 equals.
|
||||
* 因为, {@link Member} 含义为群员, 必属于一个群.
|
||||
* 而 {@link QQ} 含义为一个独立的人, 可以是好友, 也可以是陌生人.
|
||||
*/
|
||||
boolean equals(Object other);
|
||||
}
|
||||
|
@ -8,24 +8,31 @@ import net.mamoe.mirai.japt.internal.BlockingBotImpl;
|
||||
import net.mamoe.mirai.japt.internal.BlockingGroupImpl;
|
||||
import net.mamoe.mirai.japt.internal.BlockingMemberImpl;
|
||||
import net.mamoe.mirai.japt.internal.BlockingQQImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 构造阻塞式的联系人.
|
||||
*/
|
||||
public final class BlockingContacts {
|
||||
public static BlockingQQ createBlocking(QQ qq) {
|
||||
return new BlockingQQImpl(qq);
|
||||
@NotNull
|
||||
public static BlockingQQ createBlocking(@NotNull QQ qq) {
|
||||
return new BlockingQQImpl(Objects.requireNonNull(qq));
|
||||
}
|
||||
|
||||
public static BlockingGroup createBlocking(Group group) {
|
||||
return new BlockingGroupImpl(group);
|
||||
@NotNull
|
||||
public static BlockingGroup createBlocking(@NotNull Group group) {
|
||||
return new BlockingGroupImpl(Objects.requireNonNull(group));
|
||||
}
|
||||
|
||||
public static BlockingMember createBlocking(Member member) {
|
||||
return new BlockingMemberImpl(member);
|
||||
@NotNull
|
||||
public static BlockingMember createBlocking(@NotNull Member member) {
|
||||
return new BlockingMemberImpl(Objects.requireNonNull(member));
|
||||
}
|
||||
|
||||
public static BlockingBot createBlocking(Bot bot) {
|
||||
return new BlockingBotImpl(bot);
|
||||
@NotNull
|
||||
public static BlockingBot createBlocking(@NotNull Bot bot) {
|
||||
return new BlockingBotImpl(Objects.requireNonNull(bot));
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,106 @@
|
||||
package net.mamoe.mirai.japt;
|
||||
|
||||
import net.mamoe.mirai.contact.Group;
|
||||
import net.mamoe.mirai.contact.*;
|
||||
import net.mamoe.mirai.data.MemberInfo;
|
||||
import net.mamoe.mirai.event.events.*;
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface BlockingGroup extends BlockingContact {
|
||||
/**
|
||||
* 群名称.
|
||||
*/
|
||||
@NotNull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* 修改群名称
|
||||
* 频繁修改可能会被服务器拒绝.
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
* @see MemberPermissionChangeEvent
|
||||
*/
|
||||
void setName(@NotNull String name) throws PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* 入群公告, 没有时为空字符串. (同步事件更新)
|
||||
*/
|
||||
@NotNull
|
||||
String getEntranceAnnouncement();
|
||||
|
||||
/**
|
||||
* 修改入群公告.
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
* @see GroupEntranceAnnouncementChangeEvent
|
||||
*/
|
||||
void setEntranceAnnouncement(@NotNull String announcement) throws PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* 获取全员禁言状态
|
||||
*
|
||||
* @return 全员禁言状态. true 为开启
|
||||
*/
|
||||
boolean isMuteAll();
|
||||
|
||||
/**
|
||||
* 设置全体禁言
|
||||
*
|
||||
* @see GroupMuteAllEvent
|
||||
*/
|
||||
void setMuteAll(boolean enabled) throws PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* 获取坦白说状态
|
||||
*
|
||||
* @return 坦白说状态, true 为允许
|
||||
*/
|
||||
boolean isConfessTalkEnabled();
|
||||
|
||||
/**
|
||||
* 设置坦白说状态
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
* @see GroupAllowConfessTalkEvent
|
||||
*/
|
||||
void setConfessTalk(boolean enabled) throws PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* 获取允许群员邀请好友入群的状态.
|
||||
*
|
||||
* @return 允许群员邀请好友入群的状态. `true` 为允许
|
||||
*/
|
||||
boolean isAllowMemberInvite();
|
||||
|
||||
/**
|
||||
* 设置允许群员邀请好友入群的状态.
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时将会抛出异常
|
||||
* @see GroupAllowMemberInviteEvent
|
||||
*/
|
||||
void setAllowMemberInvite(boolean allow) throws PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* 获取自动加群审批的状态
|
||||
*/
|
||||
boolean isAutoApproveEnabled();
|
||||
|
||||
/**
|
||||
* 匿名聊天是否开启
|
||||
*/
|
||||
boolean isAnonymousChatEnabled();
|
||||
|
||||
/**
|
||||
* 同为 groupCode, 用户看到的群号码.
|
||||
*/
|
||||
@Override
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* 群主 (同步事件更新)
|
||||
*/
|
||||
@ -15,16 +108,29 @@ public interface BlockingGroup extends BlockingContact {
|
||||
BlockingMember getOwner();
|
||||
|
||||
/**
|
||||
* 群名称 (同步事件更新)
|
||||
* 机器人被禁言还剩余多少秒
|
||||
*
|
||||
* @see BotMuteEvent
|
||||
* @see GroupKt#isBotMuted
|
||||
*/
|
||||
@NotNull
|
||||
String getName();
|
||||
int getBotMuteRemaining();
|
||||
|
||||
/**
|
||||
* 入群公告, 没有时为空字符串. (同步事件更新)
|
||||
* 检查机器人是否正处于禁言状态
|
||||
*/
|
||||
default boolean isBotMuted() {
|
||||
int time = getBotMuteRemaining();
|
||||
return time != 0 && time != 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 机器人在这个群里的权限
|
||||
*
|
||||
* @see BotGroupPermissionChangeEvent
|
||||
*/
|
||||
@NotNull
|
||||
String getAnnouncement();
|
||||
@MiraiExperimentalAPI
|
||||
MemberPermission getBotPermission();
|
||||
|
||||
/**
|
||||
* 在 {@link Group} 实例创建的时候查询一次. 并与事件同步事件更新
|
||||
@ -32,7 +138,7 @@ public interface BlockingGroup extends BlockingContact {
|
||||
* **注意**: 获得的列表仅为这一时刻的成员列表的镜像. 它将不会被更新
|
||||
*/
|
||||
@NotNull
|
||||
Map<Long, BlockingMember> getMembers();
|
||||
List<BlockingMember> getMembers();
|
||||
|
||||
/**
|
||||
* 获取群成员. 若此 ID 的成员不存在, 则会抛出 {@link NoSuchElementException}
|
||||
@ -40,11 +146,38 @@ public interface BlockingGroup extends BlockingContact {
|
||||
@NotNull
|
||||
BlockingMember getMember(long id);
|
||||
|
||||
/**
|
||||
* 获取群成员. 若此 ID 的成员不存在则返回 null
|
||||
*/
|
||||
@Nullable
|
||||
BlockingMember getMemberOrNull(long id);
|
||||
|
||||
/**
|
||||
* 检查此 id 的群成员是否存在
|
||||
*/
|
||||
boolean containsMember(long id);
|
||||
|
||||
/**
|
||||
* 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败
|
||||
*/
|
||||
boolean quit();
|
||||
|
||||
/**
|
||||
* 构造一个 [Member].
|
||||
* 非特殊情况请不要使用这个函数. 优先使用 [get].
|
||||
*/
|
||||
@MiraiExperimentalAPI(message = "dangerous")
|
||||
@NotNull
|
||||
Member newMember(@NotNull MemberInfo memberInfo);
|
||||
|
||||
@NotNull
|
||||
String toFullString();
|
||||
|
||||
static long calculateGroupUinByGroupCode(long groupCode) {
|
||||
return Group.Companion.calculateGroupUinByGroupCode(groupCode);
|
||||
}
|
||||
|
||||
static long calculateGroupCodeByGroupUin(long groupUin) {
|
||||
return Group.Companion.calculateGroupCodeByGroupUin(groupUin);
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package net.mamoe.mirai.japt;
|
||||
|
||||
import kotlin.text.StringsKt;
|
||||
import net.mamoe.mirai.contact.MemberPermission;
|
||||
import net.mamoe.mirai.contact.PermissionDeniedException;
|
||||
import net.mamoe.mirai.event.events.MemberCardChangeEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface BlockingMember {
|
||||
public interface BlockingMember extends BlockingQQ {
|
||||
/**
|
||||
* 所在的群
|
||||
*/
|
||||
@ -17,16 +20,72 @@ public interface BlockingMember {
|
||||
@NotNull
|
||||
MemberPermission getPermission();
|
||||
|
||||
/**
|
||||
* 群名片. 可能为空.
|
||||
*/
|
||||
@NotNull
|
||||
String getNameCard();
|
||||
|
||||
/**
|
||||
* 修改群名片. 将会触发事件
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
* @see #getGroupCardOrNick() 获取非空群名片或昵称
|
||||
* @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件
|
||||
*/
|
||||
void setNameCard(@NotNull String nameCard) throws PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* 获取群名片或昵称
|
||||
*/
|
||||
@NotNull
|
||||
default String getGroupCardOrNick() {
|
||||
String nameCard = this.getNameCard();
|
||||
if (!StringsKt.isBlank(nameCard)) {
|
||||
return nameCard;
|
||||
}
|
||||
return this.getNick();
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁言
|
||||
*
|
||||
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
|
||||
* @return 若机器人无权限禁言这个群成员, 返回 `false`
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
boolean mute(int durationSeconds);
|
||||
void mute(int durationSeconds);
|
||||
|
||||
/**
|
||||
* 禁言
|
||||
*
|
||||
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
default void mute(long durationSeconds) {
|
||||
mute((int) durationSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解除禁言
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
boolean unmute();
|
||||
void unmute();
|
||||
|
||||
/**
|
||||
* 踢出该成员.
|
||||
*
|
||||
* @param message 消息
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
void kick(@NotNull String message);
|
||||
|
||||
/**
|
||||
* 踢出该成员.
|
||||
*
|
||||
* @throws PermissionDeniedException 无权限修改时
|
||||
*/
|
||||
default void kick() {
|
||||
kick("");
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,30 @@ package net.mamoe.mirai.japt;
|
||||
import net.mamoe.mirai.data.FriendNameRemark;
|
||||
import net.mamoe.mirai.data.PreviousNameList;
|
||||
import net.mamoe.mirai.data.Profile;
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface BlockingQQ extends BlockingContact {
|
||||
/**
|
||||
* 获取 QQ 号码
|
||||
*
|
||||
* @return QQ 号码
|
||||
*/
|
||||
@Override
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* 获取昵称
|
||||
*
|
||||
* @return 昵称
|
||||
*/
|
||||
String getNick();
|
||||
|
||||
/**
|
||||
* 查询用户资料
|
||||
*/
|
||||
@MiraiExperimentalAPI(message = "还未支持")
|
||||
@NotNull
|
||||
Profile queryProfile();
|
||||
|
||||
@ -20,12 +37,14 @@ public interface BlockingQQ extends BlockingContact {
|
||||
* - 昵称
|
||||
* - 共同群内的群名片
|
||||
*/
|
||||
@MiraiExperimentalAPI(message = "还未支持")
|
||||
@NotNull
|
||||
PreviousNameList queryPreviousNameList();
|
||||
|
||||
/**
|
||||
* 查询机器人账号给这个人设置的备注
|
||||
*/
|
||||
@MiraiExperimentalAPI(message = "还未支持")
|
||||
@NotNull
|
||||
FriendNameRemark queryRemark();
|
||||
}
|
||||
|
@ -20,18 +20,46 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 事件处理
|
||||
*/
|
||||
public final class Events {
|
||||
|
||||
/**
|
||||
* 监听一个事件, 当 {@code onEvent} 返回 {@link ListeningStatus#STOPPED} 时停止监听.
|
||||
* 机器人离线后不会停止监听.
|
||||
*
|
||||
* @param eventClass 事件类
|
||||
* @param onEvent 事件处理. 返回 {@link ListeningStatus#LISTENING} 时继续监听.
|
||||
* @param <E> 事件类型
|
||||
* @return 事件监听器. 可调用 {@link Listener#complete()} 或 {@link Listener#completeExceptionally(Throwable)} 让监听正常停止或异常停止.
|
||||
*/
|
||||
@NotNull
|
||||
public static <E extends Event> Listener<E> subscribe(@NotNull Class<E> eventClass, @NotNull Function<E, ListeningStatus> onEvent) {
|
||||
return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听一个事件, 直到手动停止.
|
||||
* 机器人离线后不会停止监听.
|
||||
*
|
||||
* @param eventClass 事件类
|
||||
* @param onEvent 事件处理. 返回 {@link ListeningStatus#LISTENING} 时继续监听.
|
||||
* @param <E> 事件类型
|
||||
* @return 事件监听器. 可调用 {@link Listener#complete()} 或 {@link Listener#completeExceptionally(Throwable)} 让监听正常停止或异常停止.
|
||||
*/
|
||||
@NotNull
|
||||
public static <E extends Event> Listener<E> subscribeAlways(@NotNull Class<E> eventClass, @NotNull Consumer<E> onEvent) {
|
||||
return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阻塞地广播一个事件.
|
||||
*
|
||||
* @param event 事件
|
||||
* @param <E> 事件类型
|
||||
* @return {@code event} 本身
|
||||
*/
|
||||
@NotNull
|
||||
public static <E extends Event> E broadcast(@NotNull E event) {
|
||||
return EventsImplKt.broadcast(event);
|
||||
|
@ -14,34 +14,55 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.readBytes
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.AddFriendResult
|
||||
import net.mamoe.mirai.data.GroupInfo
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.japt.BlockingBot
|
||||
import net.mamoe.mirai.japt.BlockingGroup
|
||||
import net.mamoe.mirai.japt.BlockingQQ
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.toList
|
||||
import java.io.OutputStream
|
||||
import java.util.stream.Stream
|
||||
import kotlin.streams.asStream
|
||||
|
||||
internal class BlockingBotImpl(private val bot: Bot) : BlockingBot {
|
||||
@MiraiInternalAPI
|
||||
override fun getAccount(): BotAccount = bot.account
|
||||
|
||||
override fun getUin(): Long = bot.uin
|
||||
override fun getLogger(): MiraiLogger = bot.logger
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override fun getQQs(): List<BlockingQQ> = bot.qqs.delegate.toList().map { it.blocking() }
|
||||
@MiraiExperimentalAPI
|
||||
override fun getNick(): String = bot.nick
|
||||
|
||||
override fun getLogger(): MiraiLogger = bot.logger
|
||||
override fun getSelfQQ(): QQ = bot.selfQQ
|
||||
|
||||
override fun queryGroupMemberList(groupUin: Long, groupCode: Long, ownerId: Long): Stream<MemberInfo> =
|
||||
runBlocking { bot.queryGroupMemberList(groupUin, groupCode, ownerId) }.asStream()
|
||||
|
||||
override fun getQQ(id: Long): BlockingQQ = bot.getFriend(id).blocking()
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override fun getGroups(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }
|
||||
override fun getFriendList(): List<BlockingQQ> = bot.qqs.delegate.toList().map { it.blocking() }
|
||||
|
||||
override fun getFriend(id: Long): BlockingQQ = bot.getFriend(id).blocking()
|
||||
override fun queryGroupList(): Stream<Long> = runBlocking { bot.queryGroupList() }.asStream()
|
||||
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override fun getGroupList(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }
|
||||
|
||||
override fun queryGroupInfo(code: Long): GroupInfo = runBlocking { bot.queryGroupInfo(code) }
|
||||
|
||||
override fun getGroup(id: Long): BlockingGroup = runBlocking { bot.getGroup(id).blocking() }
|
||||
override fun getNetwork(): BotNetworkHandler = bot.network
|
||||
override fun login() = runBlocking { bot.login() }
|
||||
override fun downloadAsByteArray(image: Image): ByteArray = bot.run { runBlocking { image.download().readBytes() } }
|
||||
override fun download(image: Image): ByteReadPacket = bot.run { runBlocking { image.download() } }
|
||||
override fun download(image: Image, outputStream: OutputStream) = bot.run { runBlocking { image.downloadTo(outputStream) } }
|
||||
|
||||
override fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult = runBlocking { bot.addFriend(id, message, remark) }
|
||||
override fun approveFriendAddRequest(id: Long, remark: String?) = runBlocking { bot.approveFriendAddRequest(id, remark) }
|
||||
override fun dispose(throwable: Throwable?) = bot.close(throwable)
|
||||
|
@ -17,28 +17,36 @@ import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.FriendNameRemark
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.data.PreviousNameList
|
||||
import net.mamoe.mirai.data.Profile
|
||||
import net.mamoe.mirai.japt.BlockingBot
|
||||
import net.mamoe.mirai.japt.BlockingGroup
|
||||
import net.mamoe.mirai.japt.BlockingMember
|
||||
import net.mamoe.mirai.japt.BlockingQQ
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.toChain
|
||||
import net.mamoe.mirai.message.data.toMessage
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.toList
|
||||
|
||||
internal class BlockingQQImpl(private val delegate: QQ) : BlockingQQ {
|
||||
override fun getBot(): BlockingBot = delegate.bot.blocking()
|
||||
override fun getId(): Long = delegate.id
|
||||
override fun getNick(): String = delegate.nick
|
||||
|
||||
override fun sendMessage(messages: MessageChain) = runBlocking { delegate.sendMessage(messages) }
|
||||
override fun sendMessage(message: String) = runBlocking { delegate.sendMessage(message.toMessage().toChain()) }
|
||||
override fun sendMessage(message: Message) = runBlocking { delegate.sendMessage(message.toChain()) }
|
||||
override fun uploadImage(image: ExternalImage): Image = runBlocking { delegate.uploadImage(image) }
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override fun queryProfile(): Profile = runBlocking { delegate.queryProfile() }
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override fun queryPreviousNameList(): PreviousNameList = runBlocking { delegate.queryPreviousNameList() }
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override fun queryRemark(): FriendNameRemark = runBlocking { delegate.queryRemark() }
|
||||
}
|
||||
|
||||
@ -47,22 +55,76 @@ internal class BlockingGroupImpl(private val delegate: Group) : BlockingGroup {
|
||||
override fun sendMessage(message: String) = runBlocking { delegate.sendMessage(message.toMessage().toChain()) }
|
||||
override fun sendMessage(message: Message) = runBlocking { delegate.sendMessage(message.toChain()) }
|
||||
override fun getOwner(): BlockingMember = delegate.owner.blocking()
|
||||
@MiraiExperimentalAPI
|
||||
override fun newMember(memberInfo: MemberInfo): Member = delegate.Member(memberInfo)
|
||||
|
||||
override fun uploadImage(image: ExternalImage): Image = runBlocking { delegate.uploadImage(image) }
|
||||
override fun setEntranceAnnouncement(announcement: String) {
|
||||
delegate.entranceAnnouncement = announcement
|
||||
}
|
||||
|
||||
override fun getName(): String = delegate.name
|
||||
override fun getId(): Long = delegate.id
|
||||
@MiraiExperimentalAPI
|
||||
override fun getBotPermission(): MemberPermission = delegate.botPermission
|
||||
|
||||
override fun setConfessTalk(enabled: Boolean) {
|
||||
delegate.isConfessTalkEnabled = enabled
|
||||
}
|
||||
|
||||
override fun isAnonymousChatEnabled(): Boolean = delegate.isAnonymousChatEnabled
|
||||
|
||||
override fun isAutoApproveEnabled(): Boolean = delegate.isAutoApproveEnabled
|
||||
|
||||
override fun isConfessTalkEnabled(): Boolean = delegate.isConfessTalkEnabled
|
||||
|
||||
override fun toFullString(): String = delegate.toFullString()
|
||||
override fun containsMember(id: Long): Boolean = delegate.contains(id)
|
||||
|
||||
override fun isAllowMemberInvite(): Boolean = delegate.isAllowMemberInvite
|
||||
|
||||
override fun getMember(id: Long): BlockingMember = delegate[id].blocking()
|
||||
override fun getBot(): BlockingBot = delegate.bot.blocking()
|
||||
override fun getAnnouncement(): String = delegate.entranceAnnouncement
|
||||
override fun getBotMuteRemaining(): Int = delegate.botMuteRemaining
|
||||
|
||||
override fun isMuteAll(): Boolean = delegate.isMuteAll
|
||||
|
||||
override fun setName(name: String) {
|
||||
delegate.name = name
|
||||
}
|
||||
|
||||
override fun setMuteAll(enabled: Boolean) {
|
||||
delegate.isMuteAll = enabled
|
||||
}
|
||||
|
||||
override fun getEntranceAnnouncement(): String = delegate.entranceAnnouncement
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override fun getMembers(): Map<Long, BlockingMember> =
|
||||
delegate.members.delegate.toList().associateBy { it.id }.mapValues { it.value.blocking() }
|
||||
override fun getMembers(): List<BlockingMember> =
|
||||
delegate.members.delegate.toList().map { it.blocking() }
|
||||
|
||||
override fun setAllowMemberInvite(allow: Boolean) {
|
||||
delegate.isAllowMemberInvite = allow
|
||||
}
|
||||
|
||||
override fun getMemberOrNull(id: Long): BlockingMember? {
|
||||
return delegate.getOrNull(id)?.blocking()
|
||||
}
|
||||
|
||||
override fun quit(): Boolean = runBlocking { delegate.quit() }
|
||||
}
|
||||
|
||||
internal class BlockingMemberImpl(private val delegate: Member) : BlockingMember {
|
||||
internal class BlockingMemberImpl(private val delegate: Member) : BlockingMember, BlockingQQ by (delegate as QQ).blocking() {
|
||||
override fun getGroup(): BlockingGroup = delegate.group.blocking()
|
||||
override fun getNameCard(): String = delegate.nameCard
|
||||
|
||||
override fun getPermission(): MemberPermission = delegate.permission
|
||||
override fun mute(durationSeconds: Int): Boolean = runBlocking { delegate.mute(durationSeconds) }
|
||||
override fun setNameCard(nameCard: String) {
|
||||
delegate.nameCard = nameCard
|
||||
}
|
||||
|
||||
override fun mute(durationSeconds: Int) = runBlocking { delegate.mute(durationSeconds) }
|
||||
override fun unmute() = runBlocking { delegate.unmute() }
|
||||
override fun kick(message: String) {
|
||||
runBlocking { delegate.kick(message) }
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
public class BlockingTest {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
//Bot bot = new Bot(new BotAccount(123456, ""), EmptyCoroutineContext.INSTANCE);
|
||||
//if (bot.getNetwork().login() != LoginResult.) {
|
||||
// throw IllegalStateException("Login failed")
|
||||
//}
|
||||
//bot.getContacts().getGroups();
|
||||
|
||||
//var qq = BlockingContacts.createBlocking(bot.getContacts().getQQ(123L))
|
||||
//println(createBlocking.queryRemark())
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ pluginManagement {
|
||||
|
||||
rootProject.name = 'mirai'
|
||||
|
||||
include(':mirai-demos')
|
||||
|
||||
try {
|
||||
def keyProps = new Properties()
|
||||
def keyFile = file("local.properties")
|
||||
@ -46,7 +48,7 @@ include(':mirai-console')
|
||||
include(':mirai-api-http')
|
||||
include(':mirai-demos:mirai-demo-1')
|
||||
include(':mirai-demos:mirai-demo-gentleman')
|
||||
include(':mirai-demos')
|
||||
include(':mirai-demos:mirai-demo-java')
|
||||
include(':mirai-plugins')
|
||||
include(':mirai-plugins:image-sender')
|
||||
|
||||
@ -67,6 +69,7 @@ if (versionPos==-1){
|
||||
|
||||
project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1')
|
||||
project(':mirai-demos:mirai-demo-gentleman').projectDir = file('mirai-demos/mirai-demo-gentleman')
|
||||
project(':mirai-demos:mirai-demo-java').projectDir = file('mirai-demos/mirai-demo-java')
|
||||
project(':mirai-plugins:image-sender').projectDir = file('mirai-plugins/image-sender')
|
||||
|
||||
enableFeaturePreview('GRADLE_METADATA')
|
Loading…
Reference in New Issue
Block a user