mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-23 14:20:24 +08:00
Merge remote-tracking branch 'origin/master'
# Conflicts: # mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
This commit is contained in:
commit
bd6388297d
@ -5,6 +5,7 @@ import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.telephony.TelephonyManager
|
||||
import kotlinx.io.core.toByteArray
|
||||
import net.mamoe.mirai.utils.Context
|
||||
import net.mamoe.mirai.utils.localIpAddress
|
||||
import net.mamoe.mirai.utils.md5
|
||||
import java.io.File
|
||||
|
@ -3,29 +3,29 @@ package net.mamoe.mirai.qqandroid.network
|
||||
import kotlinx.atomicfu.AtomicRef
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Input
|
||||
import kotlinx.io.core.buildPacket
|
||||
import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.MultiPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.BroadcastControllable
|
||||
import net.mamoe.mirai.event.Cancellable
|
||||
import net.mamoe.mirai.event.Subscribable
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
|
||||
import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.getValue
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
@ -41,14 +41,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
|
||||
private lateinit var channel: PlatformSocket
|
||||
|
||||
|
||||
override suspend fun login() {
|
||||
if (::channel.isInitialized) {
|
||||
channel.close()
|
||||
}
|
||||
channel = PlatformSocket()
|
||||
channel.connect("113.96.13.208", 8080)
|
||||
launch(CoroutineName("Incoming Packet Receiver")) { processReceive() }
|
||||
this.launch(CoroutineName("Incoming Packet Receiver")) { processReceive() }
|
||||
|
||||
// bot.logger.info("Trying login")
|
||||
var response: LoginPacket.LoginPacketResponse = LoginPacket.SubCommand9(bot.client).sendAndExpect()
|
||||
@ -104,10 +103,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
override suspend fun init() {
|
||||
//start updating friend/group list
|
||||
bot.logger.info("Start updating friend/group list")
|
||||
bot.logger.info("开始加载好友信息")
|
||||
|
||||
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
|
||||
if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 开始加载Contact表
|
||||
* */
|
||||
var currentFriendCount = 0
|
||||
var totalFriendCount: Short = 0
|
||||
var totalFriendCount: Short
|
||||
while (true) {
|
||||
val data = FriendList.GetFriendGroupList(
|
||||
bot.client,
|
||||
@ -117,14 +124,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
0
|
||||
).sendAndExpect<FriendList.GetFriendGroupList.Response>()
|
||||
totalFriendCount = data.totalFriendCount
|
||||
bot.qqs.delegate.addAll(
|
||||
data.friendList.map {
|
||||
QQImpl(this@QQAndroidBotNetworkHandler.bot, EmptyCoroutineContext, it.friendUin!!).also {
|
||||
currentFriendCount++
|
||||
}
|
||||
}
|
||||
)
|
||||
bot.logger.info("正在加载好友信息 ${currentFriendCount}/${totalFriendCount}")
|
||||
data.friendList.forEach {
|
||||
// atomic add
|
||||
bot.qqs.delegate.addLast(QQImpl(bot, EmptyCoroutineContext, it.friendUin).also {
|
||||
currentFriendCount++
|
||||
})
|
||||
}
|
||||
bot.logger.verbose("正在加载好友信息 ${currentFriendCount}/${totalFriendCount}")
|
||||
if (currentFriendCount >= totalFriendCount) {
|
||||
break
|
||||
}
|
||||
@ -138,22 +144,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
).sendAndExpect<FriendList.GetTroopList.Response>(100000)
|
||||
println(data.contentToString())
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 单线程处理包的接收, 分割和连接.
|
||||
*/
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val PacketReceiveDispatcher = newCoroutineDispatcher(1)
|
||||
|
||||
/**
|
||||
* 单线程处理包的解析 (协程挂起效率够)
|
||||
*/
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val PacketProcessDispatcher = newCoroutineDispatcher(1)
|
||||
|
||||
/**
|
||||
* 缓存超时处理的 [Job]. 超时后将清空缓存, 以免阻碍后续包的处理
|
||||
*/
|
||||
@ -168,12 +160,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
private var expectingRemainingLength: Long = 0
|
||||
|
||||
/**
|
||||
* 在 [PacketProcessDispatcher] 调度器中解析包内容.
|
||||
* 解析包内容.
|
||||
*
|
||||
* @param input 一个完整的包的内容, 去掉开头的 int 包长度
|
||||
*/
|
||||
fun parsePacketAsync(input: Input): Job {
|
||||
return this.launch(PacketProcessDispatcher) {
|
||||
return this.launch {
|
||||
input.use { parsePacket(it) }
|
||||
}
|
||||
}
|
||||
@ -320,28 +312,29 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
val rawInput = try {
|
||||
channel.read()
|
||||
} catch (e: ClosedChannelException) {
|
||||
dispose()
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
} catch (e: ReadPacketInternalException) {
|
||||
bot.logger.error("Socket channel read failed: ${e.message}")
|
||||
dispose()
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
} catch (e: CancellationException) {
|
||||
return
|
||||
} catch (e: Throwable) {
|
||||
bot.logger.error("Caught unexpected exceptions", e)
|
||||
dispose()
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
}
|
||||
launch(context = PacketReceiveDispatcher + CoroutineName("Incoming Packet handler"), start = CoroutineStart.ATOMIC) {
|
||||
processPacket(rawInput)
|
||||
launch(CoroutineName("Incoming Packet handler"), start = CoroutineStart.ATOMIC) {
|
||||
packetReceiveLock.withLock {
|
||||
processPacket(rawInput)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val packetReceiveLock: Mutex = Mutex()
|
||||
|
||||
/**
|
||||
* 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms)
|
||||
*/
|
||||
@ -364,7 +357,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
private suspend inline fun <E : Packet> OutgoingPacket.doSendAndReceive(timeoutMillis: Long = 3000, handler: PacketListener): E {
|
||||
channel.send(delegate)
|
||||
withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
|
||||
channel.send(delegate)
|
||||
}
|
||||
bot.logger.info("Send: ${this.commandName}")
|
||||
return withTimeoutOrNull(timeoutMillis) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@ -386,11 +381,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
fun filter(commandName: String, sequenceId: Int) = this.commandName == commandName && this.sequenceId == sequenceId
|
||||
}
|
||||
|
||||
override fun dispose(cause: Throwable?) {
|
||||
override fun close(cause: Throwable?) {
|
||||
if (::channel.isInitialized) {
|
||||
channel.close()
|
||||
}
|
||||
super.dispose(cause)
|
||||
super.close(cause)
|
||||
}
|
||||
|
||||
override suspend fun awaitDisconnection() = supervisor.join()
|
||||
|
@ -67,7 +67,7 @@ internal class FriendListSubSrvRspCode(
|
||||
|
||||
@Serializable
|
||||
internal class FriendInfo(
|
||||
@SerialId(0) val friendUin: Long? = 0,
|
||||
@SerialId(0) val friendUin: Long,
|
||||
@SerialId(1) val groupId: Byte,
|
||||
@SerialId(2) val faceId: Short,
|
||||
@SerialId(3) val remark: String = "",
|
||||
|
@ -11,6 +11,6 @@ class SyncCookie(
|
||||
@SerialId(4) val unknown2: Long = 3497826378,
|
||||
@SerialId(5) val const1: Long = 1680172298,
|
||||
@SerialId(6) val const2: Long = 2424173273,
|
||||
@SerialId(7) val unknown3: Long = 83,
|
||||
@SerialId(7) val unknown3: Long = 0,
|
||||
@SerialId(8) val unknown4: Long = 0
|
||||
) : ProtoBuf
|
@ -16,7 +16,6 @@ import net.mamoe.mirai.utils.io.writeQQ
|
||||
* 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket].
|
||||
* 只有最终的包才会被包装为 [OutgoingPacket].
|
||||
*/
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
internal class OutgoingPacket constructor(
|
||||
name: String?,
|
||||
val commandName: String,
|
||||
|
@ -25,8 +25,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.qqandroid.utils.toMessageChain
|
||||
import net.mamoe.mirai.qqandroid.utils.toRichTextElems
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
||||
import net.mamoe.mirai.utils.io.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.toReadPacket
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -61,8 +61,8 @@ internal class MessageSvc {
|
||||
client: QQAndroidClient,
|
||||
msgTime: Long //PbPushMsg.msg.msgHead.msgTime
|
||||
): OutgoingPacket = buildOutgoingUniPacket(
|
||||
client,
|
||||
extraData = EXTRA_DATA.toReadPacket()
|
||||
client//,
|
||||
// extraData = EXTRA_DATA.toReadPacket()
|
||||
) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbGetMsgReq.serializer(),
|
||||
@ -163,8 +163,9 @@ internal class MessageSvc {
|
||||
)
|
||||
),
|
||||
msgSeq = client.atomicNextMessageSequenceId(),
|
||||
msgRand = Random.nextInt().absoluteValue
|
||||
// syncCookie = client.c2cMessageSync.syncCookie.takeIf { it.isNotEmpty() } ?: "08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00".hexToBytes(),
|
||||
msgRand = Random.nextInt().absoluteValue,
|
||||
syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() }
|
||||
?: SyncCookie(currentTimeSeconds).toByteArray(SyncCookie.serializer())
|
||||
// msgVia = 1
|
||||
)
|
||||
)
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,4 +24,10 @@ object TIMPC : BotFactory {
|
||||
* 使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
fun Bot(qq: Long, password: String, configuration: BotConfiguration = BotConfiguration.Default): Bot = TIMPCBot(BotAccount(qq, password), configuration)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
inline fun TIMPC.Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)): Bot =
|
||||
this.Bot(qq, password, BotConfiguration().apply(configuration))
|
@ -91,8 +91,8 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
|
||||
heartbeatJob?.join()
|
||||
}
|
||||
|
||||
override fun dispose(cause: Throwable?) {
|
||||
super.dispose(cause)
|
||||
override fun close(cause: Throwable?) {
|
||||
super.close(cause)
|
||||
|
||||
this.heartbeatJob?.cancel(CancellationException("handler closed"))
|
||||
this.heartbeatJob = null
|
||||
@ -312,6 +312,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
|
||||
else -> error("No decrypter is found")
|
||||
} as? D ?: error("Internal error: could not cast decrypter which is found for factory to class Decrypter")
|
||||
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
suspend fun onPacketReceived(packet: Any) {//complex function, but it doesn't matter
|
||||
when (packet) {
|
||||
is TouchPacket.TouchResponse.OK -> {
|
||||
|
@ -22,6 +22,7 @@ data class BotAccount(
|
||||
/**
|
||||
* 标记直接访问 [BotAccount.id], 而不是访问 [Bot.uin]. 这可能会不兼容未来的 API 修改.
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(CLASS, TYPEALIAS, FUNCTION, PROPERTY, FIELD, CONSTRUCTOR)
|
||||
@Experimental(level = Experimental.Level.WARNING)
|
||||
|
@ -6,6 +6,7 @@ import kotlinx.coroutines.*
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.closeAndJoin
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.logStacktrace
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -92,35 +93,39 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
try {
|
||||
if (::_network.isInitialized) {
|
||||
BotOfflineEvent(this).broadcast()
|
||||
_network.dispose(cause)
|
||||
_network.closeAndJoin(cause)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("Cannot close network handler", e)
|
||||
}
|
||||
_network = createNetworkHandler(this.coroutineContext)
|
||||
|
||||
loginLoop@ while (true) {
|
||||
_network = createNetworkHandler(this.coroutineContext)
|
||||
try {
|
||||
_network.login()
|
||||
break@loginLoop
|
||||
} catch (e: Exception) {
|
||||
e.logStacktrace()
|
||||
_network.dispose(e)
|
||||
_network.closeAndJoin(e)
|
||||
}
|
||||
logger.warning("Login failed. Retrying in 3s...")
|
||||
delay(3000)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
return _network.init()
|
||||
} catch (e: Exception) {
|
||||
e.logStacktrace()
|
||||
_network.dispose(e)
|
||||
repeat(1) block@{
|
||||
repeat(2) {
|
||||
try {
|
||||
_network.init()
|
||||
return@block
|
||||
} catch (e: Exception) {
|
||||
e.logStacktrace()
|
||||
}
|
||||
logger.warning("Init failed. Retrying in 3s...")
|
||||
delay(3000)
|
||||
}
|
||||
logger.warning("Init failed. Retrying in 3s...")
|
||||
delay(3000)
|
||||
logger.error("cannot init. some features may be affected")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected abstract fun createNetworkHandler(coroutineContext: CoroutineContext): N
|
||||
@ -130,12 +135,12 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override fun dispose(throwable: Throwable?) {
|
||||
if (throwable == null) {
|
||||
network.dispose()
|
||||
network.close()
|
||||
this.botJob.complete()
|
||||
groups.delegate.clear()
|
||||
qqs.delegate.clear()
|
||||
} else {
|
||||
network.dispose(throwable)
|
||||
network.close(throwable)
|
||||
this.botJob.completeExceptionally(throwable)
|
||||
groups.delegate.clear()
|
||||
qqs.delegate.clear()
|
||||
|
@ -24,7 +24,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
|
||||
* - Key 刷新
|
||||
* - 所有数据包处理和发送
|
||||
*
|
||||
* [BotNetworkHandler.dispose] 时将会 [取消][Job.cancel] 所有此作用域下的协程
|
||||
* [BotNetworkHandler.close] 时将会 [取消][Job.cancel] 所有此作用域下的协程
|
||||
*/
|
||||
@Suppress("PropertyName")
|
||||
abstract class BotNetworkHandler : CoroutineScope {
|
||||
@ -49,6 +49,8 @@ abstract class BotNetworkHandler : CoroutineScope {
|
||||
|
||||
/**
|
||||
* 初始化获取好友列表等值.
|
||||
*
|
||||
* 不要使用这个 API. 它会在登录完成后被自动调用.
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
open suspend fun init() {
|
||||
@ -62,13 +64,18 @@ abstract class BotNetworkHandler : CoroutineScope {
|
||||
/**
|
||||
* 关闭网络接口, 停止所有有关协程和任务
|
||||
*/
|
||||
open fun dispose(cause: Throwable? = null) {
|
||||
open fun close(cause: Throwable? = null) {
|
||||
if (supervisor.isActive) {
|
||||
if (cause != null) {
|
||||
supervisor.cancel(CancellationException("handler closed", cause))
|
||||
supervisor.cancel(CancellationException("NetworkHandler closed", cause))
|
||||
} else {
|
||||
supervisor.cancel()
|
||||
supervisor.cancel(CancellationException("NetworkHandler closed"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null){
|
||||
this.close(cause)
|
||||
this.supervisor.join()
|
||||
}
|
@ -4,6 +4,7 @@ package net.mamoe.mirai
|
||||
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.Context
|
||||
import net.mamoe.mirai.utils.ContextImpl
|
||||
|
||||
// Do not use ServiceLoader. Probably not working on MPP
|
||||
@PublishedApi
|
||||
@ -20,7 +21,14 @@ internal val factory: BotFactory = run {
|
||||
No BotFactory found. Please ensure that you've added dependency of protocol modules.
|
||||
Available modules:
|
||||
- net.mamoe:mirai-core-timpc
|
||||
- net.mamoe:mirai-core-qqandroid (recommended)
|
||||
You should have at lease one protocol module installed.
|
||||
-------------------------------------------------------
|
||||
找不到 BotFactory. 请确保你依赖了至少一个协议模块.
|
||||
可用的协议模块:
|
||||
- net.mamoe:mirai-core-timpc
|
||||
- net.mamoe:mirai-core-qqandroid (推荐)
|
||||
请添加上述任一模块的依赖(与 mirai-core 版本相同)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
@ -34,4 +42,17 @@ fun Bot(context: Context, qq: Long, password: String, configuration: BotConfigur
|
||||
* 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
inline fun Bot(context: Context, qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)): Bot =
|
||||
factory.Bot(context, qq, password, configuration)
|
||||
factory.Bot(context, qq, password, configuration)
|
||||
|
||||
|
||||
/**
|
||||
* 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
fun Bot(qq: Long, password: String, configuration: BotConfiguration = BotConfiguration.Default): Bot =
|
||||
factory.Bot(ContextImpl(), qq, password, configuration)
|
||||
|
||||
/**
|
||||
* 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
|
||||
*/
|
||||
inline fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)): Bot =
|
||||
factory.Bot(ContextImpl(), qq, password, configuration)
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.message.data.ImageId
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.firstOrNull
|
||||
import net.mamoe.mirai.message.sendAsImageTo
|
||||
import net.mamoe.mirai.timpc.Bot
|
||||
import net.mamoe.mirai.timpc.TIMPC
|
||||
import net.mamoe.mirai.utils.suspendToExternalImage
|
||||
import java.io.File
|
||||
@ -39,10 +40,8 @@ private fun readTestAccount(): BotAccount? {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() {
|
||||
val bot = TIMPC.Bot( // JVM 下也可以不写 `TIMPC.` 引用顶层函数
|
||||
readTestAccount() ?: BotAccount(//填写你的账号
|
||||
id = 1994701121,
|
||||
passwordPlainText = "123456"
|
||||
)
|
||||
1994701121,
|
||||
"123456"
|
||||
) {
|
||||
// 覆盖默认的配置
|
||||
randomDeviceName = false
|
||||
@ -134,6 +133,7 @@ fun Bot.messageDSL() {
|
||||
reply(message)
|
||||
}
|
||||
|
||||
listener.complete() // 停止监听
|
||||
|
||||
// 自定义的 filter, filter 中 it 为转为 String 的消息.
|
||||
// 也可以用任何能在处理时使用的变量, 如 subject, sender, message
|
||||
|
@ -14,6 +14,7 @@ import kotlinx.io.core.IoBuffer
|
||||
import kotlinx.io.core.readBytes
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.subscribeMessages
|
||||
import net.mamoe.mirai.timpc.Bot
|
||||
import net.mamoe.mirai.timpc.TIMPC
|
||||
import net.mamoe.mirai.utils.LoginFailedException
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
|
@ -8,7 +8,6 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.alsoLogin
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.event.Subscribable
|
||||
@ -23,32 +22,18 @@ import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.message.data.buildXMLMessage
|
||||
import net.mamoe.mirai.message.data.getValue
|
||||
import net.mamoe.mirai.message.sendAsImageTo
|
||||
import net.mamoe.mirai.utils.ContextImpl
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import javax.swing.filechooser.FileSystemView
|
||||
import kotlin.random.Random
|
||||
|
||||
private fun readTestAccount(): BotAccount? {
|
||||
val file = File("testAccount.txt")
|
||||
if (!file.exists() || !file.canRead()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val lines = file.readLines()
|
||||
return try {
|
||||
BotAccount(lines[0].toLong(), lines[1])
|
||||
} catch (e: Throwable) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() {
|
||||
val bot = Bot(
|
||||
readTestAccount() ?: BotAccount(
|
||||
id = 913366033,
|
||||
passwordPlainText = "a18260132383"
|
||||
)
|
||||
ContextImpl(),
|
||||
913366033,
|
||||
"a18260132383"
|
||||
) {
|
||||
// override config here.
|
||||
}.alsoLogin()
|
||||
|
Loading…
Reference in New Issue
Block a user