mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-14 23:20:49 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
aca459f60d
CHANGELOG.mdgradle.properties
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network
mirai-core/src/commonMain/kotlin/net.mamoe.mirai
settings.gradle@ -2,10 +2,12 @@
|
||||
|
||||
开发版本. 频繁更新, 不保证高稳定性
|
||||
|
||||
## `0.13.0` *On the way*
|
||||
## `0.13.0` 2020/2/12
|
||||
|
||||
### mirai-core
|
||||
1. 修改 BotFactory, 添加 `context` 参数.
|
||||
2. currentTimeMillis 减少不必要对象创建
|
||||
3. 优化无锁链表性能 (大幅提升 `addAll` 性能)
|
||||
|
||||
### mirai-core-qqanroid
|
||||
安卓协议发布, 基于最新 QQ, 版本 `8.2.0`
|
||||
@ -14,7 +16,8 @@
|
||||
- 消息: 文字消息, 图片消息(含表情消息), 群员 At.
|
||||
- 列表: 群列表, 群员列表, 好友列表均已稳定.
|
||||
- 群操作: 查看和修改群名, 查看和修改群属性(含全体禁言, 坦白说, 自动批准加入, 匿名聊天, 允许成员拉人), 设置和解除成员禁言, 查看和修改成员名片, 踢出成员.
|
||||
- 事件: 接受群消息和好友消息并解析
|
||||
- 消息事件: 接受群消息和好友消息并解析
|
||||
- 群事件: 群员加入, 群员离开, 禁言和解除禁言, 群属性(含全体禁言, 坦白说, 匿名聊天, 允许成员拉人)改动.
|
||||
|
||||
### mirai-api-http
|
||||
HTTP API 已完成, by [@ryoii](https://github.com/ryoii).
|
||||
|
@ -1,7 +1,7 @@
|
||||
# style guide
|
||||
kotlin.code.style=official
|
||||
# config
|
||||
mirai_version=0.12.0
|
||||
mirai_version=0.13.0
|
||||
kotlin.incremental.multiplatform=true
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
# kotlin
|
||||
|
@ -47,9 +47,10 @@ import kotlin.time.ExperimentalTime
|
||||
internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler() {
|
||||
override val bot: QQAndroidBot by bot.unsafeWeakRef()
|
||||
override val supervisor: CompletableJob = SupervisorJob(bot.coroutineContext[Job])
|
||||
override val logger: MiraiLogger get() = bot.configuration.networkLoggerSupplier(this)
|
||||
|
||||
override val coroutineContext: CoroutineContext = bot.coroutineContext + CoroutineExceptionHandler { _, throwable ->
|
||||
bot.logger.error("Exception in NetworkHandler", throwable)
|
||||
logger.error("Exception in NetworkHandler", throwable)
|
||||
}
|
||||
|
||||
private lateinit var channel: PlatformSocket
|
||||
@ -62,7 +63,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
channel.connect("113.96.13.208", 8080)
|
||||
this.launch(CoroutineName("Incoming Packet Receiver")) { processReceive() }
|
||||
|
||||
// bot.logger.info("Trying login")
|
||||
// logger.info("Trying login")
|
||||
var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect()
|
||||
mainloop@ while (true) {
|
||||
when (response) {
|
||||
@ -104,7 +105,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
is WtLogin.Login.LoginPacketResponse.Success -> {
|
||||
bot.logger.info("Login successful")
|
||||
logger.info("Login successful")
|
||||
break@mainloop
|
||||
}
|
||||
}
|
||||
@ -118,7 +119,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
override suspend fun init(): Unit = coroutineScope {
|
||||
this@QQAndroidBotNetworkHandler.subscribeAlways<BotOfflineEvent> {
|
||||
if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
|
||||
this.bot.logger.error("被挤下线")
|
||||
logger.error("被挤下线")
|
||||
close()
|
||||
}
|
||||
}
|
||||
@ -130,7 +131,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
|
||||
val friendListJob = launch {
|
||||
try {
|
||||
bot.logger.info("开始加载好友信息")
|
||||
logger.info("开始加载好友信息")
|
||||
var currentFriendCount = 0
|
||||
var totalFriendCount: Short
|
||||
while (true) {
|
||||
@ -149,21 +150,21 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
currentFriendCount++
|
||||
}
|
||||
}
|
||||
bot.logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}")
|
||||
logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}")
|
||||
if (currentFriendCount >= totalFriendCount) {
|
||||
break
|
||||
}
|
||||
// delay(200)
|
||||
}
|
||||
bot.logger.info("好友列表加载完成, 共 ${currentFriendCount}个")
|
||||
logger.info("好友列表加载完成, 共 ${currentFriendCount}个")
|
||||
} catch (e: Exception) {
|
||||
bot.logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表")
|
||||
logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表")
|
||||
}
|
||||
}
|
||||
|
||||
val groupJob = launch {
|
||||
try {
|
||||
bot.logger.info("开始加载群组列表与群成员列表")
|
||||
logger.info("开始加载群组列表与群成员列表")
|
||||
val troopListData = FriendList.GetTroopListSimplify(bot.client)
|
||||
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 2)
|
||||
|
||||
@ -196,15 +197,15 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
bot.logger.error("群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试")
|
||||
bot.logger.error(e)
|
||||
logger.error("群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试")
|
||||
logger.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个")
|
||||
logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个")
|
||||
} catch (e: Exception) {
|
||||
bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
|
||||
bot.logger.error(e)
|
||||
logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
|
||||
logger.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,7 +318,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
if (packet is CancellableEvent && packet.isCancelled) return
|
||||
}
|
||||
|
||||
bot.logger.info("Received: ${packet.toString().replace("\n", """\n""").replace("\r", "")}")
|
||||
logger.info("Received: ${packet.toString().replace("\n", """\n""").replace("\r", "")}")
|
||||
|
||||
packetFactory?.run {
|
||||
when (this) {
|
||||
@ -416,13 +417,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
} catch (e: ReadPacketInternalException) {
|
||||
bot.logger.error("Socket channel read failed: ${e.message}")
|
||||
logger.error("Socket channel read failed: ${e.message}")
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
} catch (e: CancellationException) {
|
||||
return
|
||||
} catch (e: Throwable) {
|
||||
bot.logger.error("Caught unexpected exceptions", e)
|
||||
logger.error("Caught unexpected exceptions", e)
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
}
|
||||
@ -438,7 +439,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
* 发送一个包, 但不期待任何返回.
|
||||
*/
|
||||
suspend fun OutgoingPacket.sendWithoutExpect() {
|
||||
bot.logger.info("Send: ${this.commandName}")
|
||||
logger.info("Send: ${this.commandName}")
|
||||
withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
|
||||
channel.send(delegate)
|
||||
}
|
||||
@ -461,7 +462,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
|
||||
channel.send(delegate)
|
||||
}
|
||||
bot.logger.info("Send: ${this.commandName}")
|
||||
logger.info("Send: ${this.commandName}")
|
||||
return withTimeoutOrNull(timeoutMillis) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
handler.await() as E
|
||||
@ -480,7 +481,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
|
||||
channel.send(data, 0, length)
|
||||
}
|
||||
bot.logger.info("Send: ${this.commandName}")
|
||||
logger.info("Send: ${this.commandName}")
|
||||
return withTimeoutOrNull(timeoutMillis) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
handler.await() as E
|
||||
|
@ -132,9 +132,9 @@ internal class OnlinePush {
|
||||
bot.getGroupByUin(groupUin).let { group ->
|
||||
val member = group[target] as MemberImpl
|
||||
this.discardExact(1)
|
||||
return MemberLeaveEvent.Kick(member, group.members[readUInt().toLong()].also {
|
||||
group.members.delegate.remove(it)
|
||||
})
|
||||
return MemberLeaveEvent.Kick(member.also {
|
||||
group.members.delegate.remove(member)
|
||||
}, group.members[readUInt().toLong()])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,14 +187,18 @@ internal class OnlinePush {
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (target == bot.uin) {
|
||||
|
||||
}
|
||||
val member = group[target]
|
||||
if (time == 0) {
|
||||
MemberUnmuteEvent(operator = operator, member = member)
|
||||
return if (target == bot.uin) {
|
||||
if (time == 0) {
|
||||
BotUnmuteEvent(operator)
|
||||
} else
|
||||
BotMuteEvent(durationSeconds = time, operator = operator)
|
||||
} else {
|
||||
MemberMuteEvent(operator = operator, member = member, durationSeconds = time)
|
||||
val member = group[target]
|
||||
if (time == 0) {
|
||||
MemberUnmuteEvent(operator = operator, member = member)
|
||||
} else {
|
||||
MemberMuteEvent(operator = operator, member = member, durationSeconds = time)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
@UseExperimental(RawAccountIdUse::class)
|
||||
override val uin: Long
|
||||
get() = account.id
|
||||
final override val logger: MiraiLogger by lazy { configuration.logger ?: DefaultLogger("Bot($uin)").also { configuration.logger = it } }
|
||||
final override val logger: MiraiLogger by lazy { configuration.botLoggerSupplier(this) }
|
||||
|
||||
init {
|
||||
instances.addLast(this.weakRef())
|
||||
|
@ -79,6 +79,12 @@ suspend fun <E : Event> E.broadcast(): E = apply {
|
||||
this@broadcast.broadcastInternal() // inline, no extra cost
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置为 `true` 以关闭事件.
|
||||
* 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回.
|
||||
*/
|
||||
var EventDisabled = false
|
||||
|
||||
/**
|
||||
* 可控制是否需要广播这个事件包
|
||||
*/
|
||||
|
@ -129,12 +129,27 @@ data class BotGroupPermissionChangeEvent(
|
||||
*/
|
||||
data class BotMuteEvent(
|
||||
val durationSeconds: Int,
|
||||
override val group: Group,
|
||||
/**
|
||||
* 操作人. 为 null 则为机器人操作
|
||||
* 操作人.
|
||||
*/
|
||||
val operator: Member?
|
||||
) : GroupEvent, Packet, BotPassiveEvent
|
||||
val operator: Member
|
||||
) : GroupEvent, Packet, BotPassiveEvent {
|
||||
override val group: Group
|
||||
get() = operator.group
|
||||
}
|
||||
|
||||
/**
|
||||
* Bot 被取消禁言
|
||||
*/
|
||||
data class BotUnmuteEvent(
|
||||
/**
|
||||
* 操作人.
|
||||
*/
|
||||
val operator: Member
|
||||
) : GroupEvent, Packet, BotPassiveEvent {
|
||||
override val group: Group
|
||||
get() = operator.group
|
||||
}
|
||||
|
||||
/**
|
||||
* Bot 加入了一个新群
|
||||
|
@ -11,22 +11,17 @@ package net.mamoe.mirai.event.internal
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.EventDisabled
|
||||
import net.mamoe.mirai.event.Listener
|
||||
import net.mamoe.mirai.event.ListeningStatus
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import net.mamoe.mirai.utils.MiraiDebugAPI
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.logStacktrace
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlin.jvm.JvmField
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* 设置为 `true` 以关闭事件.
|
||||
* 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回.
|
||||
*/
|
||||
var EventDisabled = false
|
||||
val EventLogger: MiraiLoggerWithSwitch = DefaultLogger("Event").withSwitch(false)
|
||||
|
||||
@PublishedApi
|
||||
internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listener: L): L {
|
||||
@ -108,6 +103,8 @@ internal object EventListenerManager {
|
||||
internal suspend inline fun Event.broadcastInternal() {
|
||||
if (EventDisabled) return
|
||||
|
||||
EventLogger.info { "Event broadcast: $this" }
|
||||
|
||||
callAndRemoveIfRequired(this::class.listeners())
|
||||
|
||||
var supertypes = this::class.supertypes
|
||||
|
@ -17,6 +17,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.io.PlatformDatagramChannel
|
||||
|
||||
/**
|
||||
@ -47,6 +48,11 @@ abstract class BotNetworkHandler : CoroutineScope {
|
||||
*/
|
||||
abstract val supervisor: CompletableJob
|
||||
|
||||
/**
|
||||
* logger
|
||||
*/
|
||||
abstract val logger: MiraiLogger
|
||||
|
||||
/**
|
||||
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回.
|
||||
* 本函数将挂起直到登录成功.
|
||||
|
@ -11,6 +11,7 @@ package net.mamoe.mirai.utils
|
||||
|
||||
import kotlinx.io.core.IoBuffer
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.jvm.JvmStatic
|
||||
@ -38,7 +39,11 @@ class BotConfiguration {
|
||||
/**
|
||||
* 日志记录器
|
||||
*/
|
||||
var logger: MiraiLogger? = null
|
||||
var botLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Bot(${it.uin})") }
|
||||
/**
|
||||
* 网络层日志构造器
|
||||
*/
|
||||
var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.uin})") }
|
||||
/**
|
||||
* 设备信息覆盖
|
||||
*/
|
||||
|
@ -12,14 +12,12 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.util.date.GMTDate
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.io.core.toByteArray
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
inline val currentTimeMillis: Long get() = GMTDate().timestamp
|
||||
expect val currentTimeMillis: Long
|
||||
|
||||
inline val currentTimeSeconds: Long get() = currentTimeMillis / 1000
|
||||
|
||||
|
@ -21,15 +21,19 @@ pluginManagement {
|
||||
|
||||
rootProject.name = 'mirai'
|
||||
|
||||
def keyProps = new Properties()
|
||||
def keyFile = file("local.properties")
|
||||
if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) }
|
||||
if (!keyProps.getProperty("sdk.dir", "").isEmpty()) {
|
||||
include(':mirai-demos:mirai-demo-android')
|
||||
project(':mirai-demos:mirai-demo-android').projectDir = file('mirai-demos/mirai-demo-android')
|
||||
} else {
|
||||
println("Android SDK 可能未安装. \n将不会加载模块 `mirai-demo-android`, 但这并不影响其他 demo 的加载 ")
|
||||
println("Android SDK might not be installed. \nModule `mirai-demo-android` will not be included, but other demos will not be influenced")
|
||||
try {
|
||||
def keyProps = new Properties()
|
||||
def keyFile = file("local.properties")
|
||||
if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) }
|
||||
if (!keyProps.getProperty("sdk.dir", "").isEmpty()) {
|
||||
include(':mirai-demos:mirai-demo-android')
|
||||
project(':mirai-demos:mirai-demo-android').projectDir = file('mirai-demos/mirai-demo-android')
|
||||
} else {
|
||||
println("Android SDK 可能未安装. \n将不会加载模块 `mirai-demo-android`, 但这并不影响其他 demo 的加载 ")
|
||||
println("Android SDK might not be installed. \nModule `mirai-demo-android` will not be included, but other demos will not be influenced")
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
include(':mirai-core')
|
||||
@ -47,10 +51,18 @@ include(':mirai-plugins')
|
||||
include(':mirai-plugins:image-sender')
|
||||
|
||||
def javaVersion = System.getProperty("java.version")
|
||||
if (javaVersion.substring(0, javaVersion.indexOf(".")).toInteger() >= 11) {
|
||||
include(':mirai-debug')
|
||||
} else {
|
||||
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
|
||||
def versionPos = javaVersion.indexOf(".")
|
||||
if (versionPos==-1) versionPos = javaVersion.indexOf("-")
|
||||
if (versionPos==-1){
|
||||
println("jdk version unknown")
|
||||
}else{
|
||||
def javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
|
||||
if (javaVersionNum >= 11) {
|
||||
println("jdk版本为 "+ javaVersionNum)
|
||||
include(':mirai-debug')
|
||||
} else {
|
||||
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
|
||||
}
|
||||
}
|
||||
|
||||
project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1')
|
||||
|
Loading…
Reference in New Issue
Block a user