Kotlin coroutine

This commit is contained in:
Him188moe 2019-09-19 22:11:57 +08:00
parent 4b96bf0ee8
commit 4f4bc05da6
13 changed files with 108 additions and 88 deletions

View File

@ -21,23 +21,23 @@ abstract class Contact internal constructor(val bot: Bot, val number: Long) {
/**
* Async
*/
abstract fun sendMessage(message: MessageChain)
abstract suspend fun sendMessage(message: MessageChain)
/**
* 上传图片
*/
fun uploadImage(session: LoginSession, image: UnsolvedImage): CompletableFuture<Unit> {
suspend fun uploadImage(session: LoginSession, image: UnsolvedImage): CompletableFuture<Unit> {
return image.upload(session, this)
}
fun sendMessage(message: Message) {
suspend fun sendMessage(message: Message) {
if (message is MessageChain) {
return sendMessage(message)
}
return sendMessage(message.toChain())
}
fun sendMessage(message: String) {
suspend fun sendMessage(message: String) {
this.sendMessage(PlainText(message))
}

View File

@ -25,7 +25,7 @@ class Group(bot: Bot, number: Long) : Contact(bot, number), Closeable {
val groupId = groupNumberToId(number)
val members = ContactList<QQ>()
override fun sendMessage(message: MessageChain) {
override suspend fun sendMessage(message: MessageChain) {
bot.network.message.sendGroupMessage(this, message)
}

View File

@ -18,7 +18,7 @@ import net.mamoe.mirai.message.defaults.MessageChain
* @author Him188moe
*/
class QQ(bot: Bot, number: Long) : Contact(bot, number) {
override fun sendMessage(message: MessageChain) {
override suspend fun sendMessage(message: MessageChain) {
bot.network.message.sendFriendMessage(this, message)
}

View File

@ -26,7 +26,7 @@ class UnsolvedImage(filename: String, val image: BufferedImage) : Image(getImage
constructor(imageFile: File) : this(imageFile.name, ImageIO.read(imageFile))
constructor(url: URL) : this(File(url.file))
fun upload(session: LoginSession, contact: Contact): CompletableFuture<Unit> {
suspend fun upload(session: LoginSession, contact: Contact): CompletableFuture<Unit> {//todo be suspend
return session.expectPacket<ServerTryGetImageIDResponsePacket> {
toSend { ClientTryGetImageIDPacket(session.bot.account.qqNumber, session.sessionKey, contact.number, image) }

View File

@ -1,5 +1,6 @@
package net.mamoe.mirai.network
import kotlinx.coroutines.*
import net.mamoe.mirai.Bot
import net.mamoe.mirai.MiraiServer
import net.mamoe.mirai.event.events.bot.BotLoginSucceedEvent
@ -40,8 +41,11 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
internal val temporaryPacketHandlers = Collections.synchronizedList(mutableListOf<TemporaryPacketHandler<*>>())
override fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*>) {
temporaryPacketHandler.send(action.session)
runBlocking {
temporaryPacketHandler.send(action.session)
}
temporaryPacketHandlers.add(temporaryPacketHandler)
}
@ -95,7 +99,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
internal inner class BotSocket : Closeable, DataPacketSocket {
override fun distributePacket(packet: ServerPacket) {
override suspend fun distributePacket(packet: ServerPacket) {
try {
packet.decode()
} catch (e: java.lang.Exception) {
@ -150,12 +154,8 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
val packet = DatagramPacket(ByteArray(2048), 2048)
kotlin.runCatching { socket?.receive(packet) }
.onSuccess {
MiraiThreadPool.getInstance().submit {
try {
distributePacket(ServerPacket.ofByteArray(packet.data.removeZeroTail()))
} catch (e: Exception) {
e.printStackTrace()
}
GlobalScope.launch {
distributePacket(ServerPacket.ofByteArray(packet.data.removeZeroTail()))
}
}.onFailure {
if (it.message == "Socket closed" || it.message == "socket closed") {
@ -184,7 +184,9 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
bot.waitForPacket(ServerPacket::class, timeoutMillis) {
loginFuture!!.complete(LoginState.TIMEOUT)
}
sendPacket(ClientTouchPacket(bot.account.qqNumber, serverIP))
runBlocking {
sendPacket(ClientTouchPacket(bot.account.qqNumber, serverIP))
}
return this.loginFuture!!
}
@ -193,8 +195,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
* Not async
*/
@Synchronized
override fun sendPacket(packet: ClientPacket) {
override suspend fun sendPacket(packet: ClientPacket) {
checkNotNull(socket) { "network closed" }
if (socket!!.isClosed) {
return
@ -208,7 +209,9 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
}
val data = packet.toByteArray()
socket!!.send(DatagramPacket(data, data.size))
withContext(Dispatchers.IO) {
socket!!.send(DatagramPacket(data, data.size))
}
bot.cyanL("Packet sent: $packet")
PacketSentEvent(bot, packet).broadcast()
@ -255,7 +258,7 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
private var heartbeatFuture: ScheduledFuture<*>? = null
fun onPacketReceived(packet: ServerPacket) {
suspend fun onPacketReceived(packet: ServerPacket) {
when (packet) {
is ServerTouchResponsePacket -> {
if (packet.serverIP != null) {//redirection
@ -304,7 +307,9 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
this.token00BA = packet.token00BA
if (packet.transmissionCompleted) {
bot.notice(CharImageUtil.createCharImg(ImageIO.read(this.captchaCache!!.inputStream())))
withContext(Dispatchers.IO) {
bot.notice(CharImageUtil.createCharImg(ImageIO.read(captchaCache!!.inputStream())))
}
bot.notice("需要验证码登录, 验证码为 4 字母")
try {
(MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.captchaCache!!)
@ -350,7 +355,9 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
is ServerSessionKeyResponsePacket -> {
sessionKey = packet.sessionKey
heartbeatFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
socket.sendPacket(ClientHeartbeatPacket(bot.account.qqNumber, sessionKey))
runBlocking {
socket.sendPacket(ClientHeartbeatPacket(bot.account.qqNumber, sessionKey))
}
}, 90000, 90000, TimeUnit.MILLISECONDS)
socket.loginFuture!!.complete(LoginState.SUCCESS)
@ -390,7 +397,9 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
}
fun changeOnlineStatus(status: ClientLoginStatus) {
socket.sendPacket(ClientChangeOnlineStatusPacket(bot.account.qqNumber, sessionKey, status))
NetworkScope.launch {
socket.sendPacket(ClientChangeOnlineStatusPacket(bot.account.qqNumber, sessionKey, status))
}
}
override fun close() {

View File

@ -0,0 +1,21 @@
package net.mamoe.mirai.network
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
import kotlin.coroutines.CoroutineContext
object NetworkScope : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = lazy {
ThreadPoolExecutor(
1,
4,
8000, TimeUnit.MILLISECONDS,
SynchronousQueue()
).asCoroutineDispatcher()
}.value//todo improve
}

View File

@ -1,5 +1,6 @@
package net.mamoe.mirai.network.handler
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.network.LoginSession
import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.network.packet.action.AddFriendResult
@ -32,7 +33,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
private var sKeyRefresherFuture: ScheduledFuture<*>? = null
override fun onPacketReceived(packet: ServerPacket) {
override suspend fun onPacketReceived(packet: ServerPacket) {
when (packet) {
is ServerCanAddFriendResponsePacket -> {
this.uploadImageSessions.forEach {
@ -60,7 +61,9 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
session.cookies = "uin=o" + session.bot.account.qqNumber + ";skey=" + session.sKey + ";"
sKeyRefresherFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
session.socket.sendPacket(ClientSKeyRefreshmentRequestPacket(session.bot.account.qqNumber, session.sessionKey))
runBlocking {
session.socket.sendPacket(ClientSKeyRefreshmentRequestPacket(session.bot.account.qqNumber, session.sessionKey))
}
}, 1800000, 1800000, TimeUnit.MILLISECONDS)
session.gtk = getGTK(session.sKey)
@ -75,13 +78,13 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
}
fun addFriend(qqNumber: Long, message: Supplier<String>) {
suspend fun addFriend(qqNumber: Long, message: Supplier<String>) {
addFriend(qqNumber, lazy { message.get() })
}
@JvmSynthetic
fun addFriend(qqNumber: Long, message: Lazy<String> = lazyOf("")): CompletableFuture<AddFriendResult> {
suspend fun addFriend(qqNumber: Long, message: Lazy<String> = lazyOf("")): CompletableFuture<AddFriendResult> {
val future = CompletableFuture<AddFriendResult>()
val session = AddFriendSession(qqNumber, future, message)
// uploadImageSessions.add(session)
@ -90,12 +93,12 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
}
fun requestSKey() {
suspend fun requestSKey() {
session.socket.sendPacket(ClientSKeyRequestPacket(session.bot.account.qqNumber, session.sessionKey))
}
fun requestAccountInfo() {
suspend fun requestAccountInfo() {
session.socket.sendPacket(ClientAccountInfoRequestPacket(session.bot.account.qqNumber, session.sessionKey))
}
@ -165,7 +168,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
lateinit var id: ByteArray
fun onPacketReceived(packet: ServerPacket) {
suspend fun onPacketReceived(packet: ServerPacket) {
if (!::id.isInitialized) {
return
}
@ -202,7 +205,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
}
fun sendAddRequest() {
suspend fun sendAddRequest() {
session.socket.sendPacket(ClientCanAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey).also { this.id = it.packetIdLast })
}

View File

@ -6,9 +6,7 @@ import net.mamoe.mirai.network.BotNetworkHandlerImpl
import net.mamoe.mirai.network.LoginSession
import net.mamoe.mirai.network.packet.ClientPacket
import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.task.MiraiThreadPool
import java.io.Closeable
import java.util.concurrent.Future
/**
* 网络接口.
@ -23,7 +21,7 @@ interface DataPacketSocket : Closeable {
/**
* 分发数据包给 [PacketHandler]
*/
fun distributePacket(packet: ServerPacket)
suspend fun distributePacket(packet: ServerPacket)
/**
* 发送一个数据包(非异步).
@ -32,20 +30,7 @@ interface DataPacketSocket : Closeable {
*
* @see [LoginSession.expectPacket] kotlin DSL
*/
fun sendPacket(packet: ClientPacket)
/**
* 发送一个数据包(异步).
*
* 可通过 hook 事件 [ServerPacketReceivedEvent] 来获取服务器返回.
*
* @see [LoginSession.expectPacket] kotlin DSL
*/
fun sendPacketAsync(packet: ClientPacket): Future<*> {
return MiraiThreadPool.getInstance().submit {
sendPacket(packet)
}
}
suspend fun sendPacket(packet: ClientPacket)
fun isClosed(): Boolean

View File

@ -1,5 +1,6 @@
package net.mamoe.mirai.network.handler
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.event.events.group.GroupMessageEvent
@ -30,46 +31,49 @@ class MessagePacketHandler(session: LoginSession) : PacketHandler(session) {
init {
//todo for test
FriendMessageEvent::class.hookWhile {
if (session.socket.isClosed()) {
return@hookWhile false
}
when {
it.message valueEquals "你好" -> it.sender.sendMessage("你好!")
it.message.toString().startsWith("复读") -> it.sender.sendMessage(it.message())
it.message.toString().startsWith("发群") -> {
it.message().list.toMutableList().let { messages ->
messages.removeAt(0)
sendGroupMessage(Group(session.bot, 580266363), MessageChain(messages))
}
return@hookWhile runBlocking {
if (session.socket.isClosed()) {
return@runBlocking false
}
when {
it.message valueEquals "你好" -> it.sender.sendMessage("你好!")
it.message.toString().startsWith("复读") -> it.sender.sendMessage(it.message())
it.message.toString().startsWith("发群") -> {
it.message().list.toMutableList().let { messages ->
messages.removeAt(0)
sendGroupMessage(Group(session.bot, 580266363), MessageChain(messages))
}
}
/*it.message valueEquals "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
image.upload(session, Group(session.bot, 580266363)).get()
})*/
it.message valueEquals "发图片群2" -> sendGroupMessage(Group(session.bot, 580266363), Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg").toChain())
/* it.message valueEquals "发图片" -> sendFriendMessage(it.sender, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
image.upload(session, it.sender).get()
})*/
it.message valueEquals "发图片2" -> sendFriendMessage(it.sender, PlainText("test") + Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))
}
/*it.message valueEquals "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
image.upload(session, Group(session.bot, 580266363)).get()
})*/
it.message valueEquals "发图片群2" -> sendGroupMessage(Group(session.bot, 580266363), Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg").toChain())
/* it.message valueEquals "发图片" -> sendFriendMessage(it.sender, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
image.upload(session, it.sender).get()
})*/
it.message valueEquals "发图片2" -> sendFriendMessage(it.sender, PlainText("test") + Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))
}
return@hookWhile true
return@runBlocking true
}
}
GroupMessageEvent::class.hookWhile {
if (session.socket.isClosed()) {
return@hookWhile false
return@hookWhile runBlocking {
if (session.socket.isClosed()) {
return@runBlocking false
}
when {
it.message.contains("复读") -> it.group.sendMessage(it.chain)
}
return@runBlocking true
}
when {
it.message.contains("复读") -> it.group.sendMessage(it.chain)
}
return@hookWhile true
}
}
override fun onPacketReceived(packet: ServerPacket) {
override suspend fun onPacketReceived(packet: ServerPacket) {
when (packet) {
is ServerGroupUploadFileEventPacket -> {
//todo
@ -99,11 +103,11 @@ class MessagePacketHandler(session: LoginSession) : PacketHandler(session) {
}
}
fun sendFriendMessage(qq: QQ, message: MessageChain) {
session.socket.sendPacketAsync(ClientSendFriendMessagePacket(session.bot.account.qqNumber, qq.number, session.sessionKey, message))
suspend fun sendFriendMessage(qq: QQ, message: MessageChain) {
session.socket.sendPacket(ClientSendFriendMessagePacket(session.bot.account.qqNumber, qq.number, session.sessionKey, message))
}
fun sendGroupMessage(group: Group, message: MessageChain) {
suspend fun sendGroupMessage(group: Group, message: MessageChain) {
session.socket.sendPacket(ClientSendGroupMessagePacket(session.bot.account.qqNumber, group.groupId, session.sessionKey, message))
}
}

View File

@ -11,7 +11,7 @@ import java.io.Closeable
abstract class PacketHandler(
val session: LoginSession
) : Closeable {
abstract fun onPacketReceived(packet: ServerPacket)
abstract suspend fun onPacketReceived(packet: ServerPacket)
override fun close() {

View File

@ -32,7 +32,7 @@ open class TemporaryPacketHandler<P : ServerPacket>(
this.expect = handler
}
fun send(session: LoginSession) {
suspend fun send(session: LoginSession) {
this.session = session
session.socket.sendPacket(toSend)
}

View File

@ -6,8 +6,6 @@ import lombok.Data;
@Data
@AllArgsConstructor
public class BotAccount {
public final long qqNumber;
private final String password;
public final String password;
}

View File

@ -40,7 +40,7 @@ object Main {
println("-------------------------------------------")
exitProcess(0)*/
var jpcap: JpcapCaptor? = null
val jpcap: JpcapCaptor?
val caplen = 4096
val promiscCheck = true