mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-03 05:34:42 +08:00
Simplify platform structure, simplify network implementations
This commit is contained in:
parent
9c71a9c953
commit
6ccd20c377
@ -130,7 +130,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
||||
|
||||
while (isActive) {
|
||||
try {
|
||||
channel.connect(coroutineContext + CoroutineName("Socket"), host, port)
|
||||
channel.connect(host, port)
|
||||
break
|
||||
} catch (e: SocketException) {
|
||||
if (e is NoRouteToHostException || e.message?.contains("Network is unreachable") == true) {
|
||||
|
@ -24,8 +24,8 @@ import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.PacketLogger
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.Tlv
|
||||
import net.mamoe.mirai.internal.utils.*
|
||||
import net.mamoe.mirai.internal.utils.cryptor.ECDH
|
||||
import net.mamoe.mirai.internal.utils.cryptor.TEA
|
||||
import net.mamoe.mirai.internal.utils.crypto.ECDH
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.network.LoginFailedException
|
||||
import net.mamoe.mirai.network.NoServerAvailableException
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
@ -31,7 +31,6 @@ import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.withUse
|
||||
import net.mamoe.mirai.utils.internal.ReusableInput
|
||||
import net.mamoe.mirai.utils.verbose
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
@ -143,7 +142,7 @@ internal object HighwayHelper {
|
||||
val socket = PlatformSocket()
|
||||
while (client.bot.network.areYouOk() && client.bot.isActive) {
|
||||
try {
|
||||
socket.connect(EmptyCoroutineContext, serverIp, serverPort)
|
||||
socket.connect(serverIp, serverPort)
|
||||
break
|
||||
} catch (e: SocketException) {
|
||||
delay(3000)
|
||||
|
@ -14,8 +14,8 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.buildPacket
|
||||
import kotlinx.io.core.writeFully
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.utils.cryptor.ECDH
|
||||
import net.mamoe.mirai.internal.utils.cryptor.ECDHKeyPair
|
||||
import net.mamoe.mirai.internal.utils.crypto.ECDH
|
||||
import net.mamoe.mirai.internal.utils.crypto.ECDHKeyPair
|
||||
import net.mamoe.mirai.internal.utils.io.encryptAndWrite
|
||||
import net.mamoe.mirai.internal.utils.io.writeShortLVByteArray
|
||||
|
||||
|
@ -26,8 +26,8 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
|
||||
import net.mamoe.mirai.internal.network.readUShortLVByteArray
|
||||
import net.mamoe.mirai.internal.utils.*
|
||||
import net.mamoe.mirai.internal.utils.cryptor.TEA
|
||||
import net.mamoe.mirai.internal.utils.cryptor.adjustToPublicKey
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.internal.utils.crypto.adjustToPublicKey
|
||||
import net.mamoe.mirai.internal.utils.io.readPacketExact
|
||||
import net.mamoe.mirai.internal.utils.io.readString
|
||||
import net.mamoe.mirai.internal.utils.io.useBytes
|
||||
|
@ -16,7 +16,7 @@ import net.mamoe.mirai.internal.network.*
|
||||
import net.mamoe.mirai.internal.network.protocol.LoginType
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.*
|
||||
import net.mamoe.mirai.internal.utils.*
|
||||
import net.mamoe.mirai.internal.utils.cryptor.TEA
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
import net.mamoe.mirai.internal.utils.guidFlag
|
||||
import net.mamoe.mirai.internal.utils.io.*
|
||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.atomicfu.AtomicLong
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.atomicfu.locks.reentrantLock
|
||||
import kotlinx.atomicfu.locks.withLock
|
||||
import net.mamoe.mirai.utils.currentTimeMillis
|
||||
|
||||
|
||||
/**
|
||||
* Dynamically sized cache list with retention period.
|
||||
* No concurrency guaranteed on same elements.
|
||||
*/
|
||||
internal class AtomicResizeCacheList<E>(private val retention: Long) {
|
||||
private inner class Cache {
|
||||
@Volatile
|
||||
@JvmField
|
||||
var element: E? = null
|
||||
|
||||
val time: AtomicLong = atomic(0L)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val initialCapacity: Int = 32
|
||||
}
|
||||
|
||||
private val list: MutableList<Cache> = ArrayList(initialCapacity)
|
||||
private val lock = reentrantLock()
|
||||
|
||||
/**
|
||||
* Adds an element, also cleanup outdated caches, but no duplication is removed.
|
||||
* No concurrency guaranteed on same [element].
|
||||
*/
|
||||
private fun add(element: E) {
|
||||
val currentTime = currentTimeMillis()
|
||||
findAvailable@ while (true) {
|
||||
for (cache in list) {
|
||||
val instant = cache.time.value
|
||||
when {
|
||||
instant == 0L -> {
|
||||
if (cache.time.compareAndSet(instant, currentTime + retention)) {
|
||||
cache.element = element
|
||||
return
|
||||
} else continue@findAvailable
|
||||
}
|
||||
// outdated
|
||||
instant < currentTime -> cache.time.compareAndSet(instant, 0)
|
||||
}
|
||||
}
|
||||
// no more Cache instance available
|
||||
lock.withLock {
|
||||
list.add(Cache().apply {
|
||||
this.element = element
|
||||
this.time.value = currentTime + retention
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No concurrency guaranteed on same [element]
|
||||
*/
|
||||
private fun removeDuplication(element: E): Boolean {
|
||||
val duplicate = list.firstOrNull { it.time.value != 0L && it.element == element } ?: return false
|
||||
duplicate.time.value = 0
|
||||
return true
|
||||
}
|
||||
|
||||
fun ensureNoDuplication(element: E): Boolean {
|
||||
return if (removeDuplication(element)) {
|
||||
false
|
||||
} else {
|
||||
add(element)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
@ -9,26 +9,97 @@
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Closeable
|
||||
import kotlinx.io.nio.readPacketAtMost
|
||||
import kotlinx.io.nio.writePacket
|
||||
import java.net.InetSocketAddress
|
||||
import java.nio.channels.DatagramChannel
|
||||
import java.nio.channels.ReadableByteChannel
|
||||
import java.nio.channels.WritableByteChannel
|
||||
|
||||
/**
|
||||
* 多平台适配的 DatagramChannel.
|
||||
*/
|
||||
internal expect class PlatformDatagramChannel(serverHost: String, serverPort: Short) : Closeable {
|
||||
/**
|
||||
* @throws SendPacketInternalException
|
||||
*/
|
||||
suspend inline fun send(packet: ByteReadPacket): Boolean
|
||||
internal class PlatformDatagramChannel(serverHost: String, serverPort: Short) : Closeable {
|
||||
@PublishedApi
|
||||
internal val channel: DatagramChannel =
|
||||
DatagramChannel.open().connect(InetSocketAddress(serverHost, serverPort.toInt()))
|
||||
val isOpen: Boolean get() = channel.isOpen
|
||||
override fun close() = channel.close()
|
||||
|
||||
/**
|
||||
* @throws ReadPacketInternalException
|
||||
*/
|
||||
suspend inline fun read(): ByteReadPacket
|
||||
suspend inline fun send(packet: ByteReadPacket): Boolean = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
(channel as WritableByteChannel).writePacket(packet)
|
||||
} catch (e: Throwable) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
|
||||
val isOpen: Boolean
|
||||
suspend inline fun read(): ByteReadPacket = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
(channel as ReadableByteChannel).readPacketAtMost(Long.MAX_VALUE)
|
||||
} catch (e: Throwable) {
|
||||
throw ReadPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
actual class PlatformDatagramChannel actual constructor(serverHost: String, serverPort: Short) : Closeable {
|
||||
private val serverAddress: InetSocketAddress = InetSocketAddress(serverHost, serverPort.toInt())
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val socket = runBlocking { aSocket(ActorSelectorManager(Dispatchers.IO)).tcp()
|
||||
.connect(remoteAddress = serverAddress) }
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val readChannel = socket.openReadChannel()
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val writeChannel = socket.openWriteChannel(true)
|
||||
|
||||
@KtorExperimentalAPI
|
||||
@Throws(ReadPacketInternalException::class)
|
||||
actual suspend fun read(buffer: IoBuffer) =
|
||||
try {
|
||||
readChannel.readAvailable(buffer)
|
||||
} catch (e: ClosedChannelException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw ReadPacketInternalException(e)
|
||||
}
|
||||
|
||||
|
||||
@KtorExperimentalAPI
|
||||
@Throws(SendPacketInternalException::class)
|
||||
actual suspend fun send(buffer: IoBuffer) =
|
||||
buffer.readDirect {
|
||||
try {
|
||||
writeChannel.writeFully(it)
|
||||
} catch (e: ClosedChannelException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@KtorExperimentalAPI
|
||||
@Throws(IOException::class)
|
||||
override fun close() {
|
||||
socket.close()
|
||||
}
|
||||
|
||||
@KtorExperimentalAPI
|
||||
actual val isOpen: Boolean
|
||||
get() = socket.isClosed.not()
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* 在 [PlatformDatagramChannel.send] 或 [PlatformDatagramChannel.read] 时出现的错误.
|
||||
*/
|
||||
|
@ -9,38 +9,95 @@
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Closeable
|
||||
import kotlinx.io.errors.IOException
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.io.streams.readPacketAtMost
|
||||
import kotlinx.io.streams.writePacket
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.IOException
|
||||
import java.net.NoRouteToHostException
|
||||
import java.net.Socket
|
||||
import java.net.UnknownHostException
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* 多平台适配的 TCP Socket.
|
||||
* TCP Socket.
|
||||
*/
|
||||
internal expect class PlatformSocket() : Closeable {
|
||||
@kotlin.Throws(SocketException::class)
|
||||
suspend fun connect(coroutineContext: CoroutineContext, serverHost: String, serverPort: Int)
|
||||
internal class PlatformSocket : Closeable {
|
||||
private lateinit var socket: Socket
|
||||
|
||||
val isOpen: Boolean
|
||||
get() =
|
||||
if (::socket.isInitialized)
|
||||
socket.isConnected
|
||||
else false
|
||||
|
||||
override fun close() {
|
||||
if (::socket.isInitialized) {
|
||||
socket.close()
|
||||
}
|
||||
thread.shutdownNow()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal lateinit var writeChannel: BufferedOutputStream
|
||||
|
||||
@PublishedApi
|
||||
internal lateinit var readChannel: BufferedInputStream
|
||||
|
||||
suspend fun send(packet: ByteArray, offset: Int, length: Int) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
withContext(Dispatchers.IO) {
|
||||
writeChannel.write(packet, offset, length)
|
||||
writeChannel.flush()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SendPacketInternalException
|
||||
*/
|
||||
suspend fun send(packet: ByteArray, offset: Int = 0, length: Int = packet.size - offset)
|
||||
suspend fun send(packet: ByteReadPacket) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
writeChannel.writePacket(packet)
|
||||
writeChannel.flush()
|
||||
} catch (e: IOException) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SendPacketInternalException
|
||||
*/
|
||||
suspend fun send(packet: ByteReadPacket)
|
||||
private val thread = Executors.newSingleThreadExecutor()
|
||||
|
||||
/**
|
||||
* @throws ReadPacketInternalException
|
||||
*/
|
||||
suspend fun read(): ByteReadPacket
|
||||
suspend fun read(): ByteReadPacket = suspendCancellableCoroutine { cont ->
|
||||
thread.submit {
|
||||
kotlin.runCatching {
|
||||
readChannel.readPacketAtMost(Long.MAX_VALUE)
|
||||
}.let {
|
||||
cont.resumeWith(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isOpen: Boolean
|
||||
|
||||
override fun close()
|
||||
suspend fun connect(serverHost: String, serverPort: Int) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
withContext(Dispatchers.IO) {
|
||||
socket = Socket(serverHost, serverPort)
|
||||
readChannel = socket.getInputStream().buffered()
|
||||
writeChannel = socket.getOutputStream().buffered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal expect open class SocketException : IOException
|
||||
internal expect class NoRouteToHostException : SocketException
|
||||
internal expect class UnknownHostException : IOException
|
||||
|
||||
internal typealias SocketException = java.net.SocketException
|
||||
internal typealias NoRouteToHostException = NoRouteToHostException
|
||||
internal typealias UnknownHostException = UnknownHostException
|
@ -135,7 +135,9 @@ internal fun Any?._miraiContentToString(prefix: String = ""): String = when (thi
|
||||
}
|
||||
}
|
||||
|
||||
internal expect fun KProperty1<*, *>.getValueAgainstPermission(receiver: Any): Any?
|
||||
internal fun KProperty1<*, *>.getValueAgainstPermission(receiver: Any): Any? {
|
||||
return this.javaField?.apply { isAccessible = true }?.get(receiver)
|
||||
}
|
||||
|
||||
private fun Any.canBeIgnored(): Boolean {
|
||||
return when (this) {
|
||||
|
@ -7,13 +7,11 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils.cryptor
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import net.mamoe.mirai.internal.utils.chunkedHexToBytes
|
||||
|
||||
internal expect interface ECDHPrivateKey {
|
||||
fun getEncoded(): ByteArray
|
||||
}
|
||||
internal expect interface ECDHPrivateKey
|
||||
|
||||
internal expect interface ECDHPublicKey {
|
||||
fun getEncoded(): ByteArray
|
@ -7,7 +7,7 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils.cryptor
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.pool.useInstance
|
||||
@ -16,7 +16,6 @@ import net.mamoe.mirai.internal.utils.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.toUHexString
|
||||
import kotlin.experimental.and
|
||||
import kotlin.experimental.xor
|
||||
import kotlin.jvm.JvmStatic
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
@ -15,9 +15,7 @@ package net.mamoe.mirai.internal.utils.io
|
||||
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.internal.utils.coerceAtMostOrFail
|
||||
import net.mamoe.mirai.internal.utils.cryptor.TEA
|
||||
import kotlin.jvm.JvmMultifileClass
|
||||
import kotlin.jvm.JvmName
|
||||
import net.mamoe.mirai.internal.utils.crypto.TEA
|
||||
|
||||
internal fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLength: Int) {
|
||||
if (array.size <= maxLength) {
|
||||
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Closeable
|
||||
import kotlinx.io.errors.IOException
|
||||
import kotlinx.io.streams.readPacketAtMost
|
||||
import kotlinx.io.streams.writePacket
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.BufferedOutputStream
|
||||
import java.net.Socket
|
||||
import java.net.SocketException
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* 多平台适配的 TCP Socket.
|
||||
*/
|
||||
internal actual class PlatformSocket : Closeable {
|
||||
private lateinit var socket: Socket
|
||||
|
||||
actual val isOpen: Boolean
|
||||
get() =
|
||||
if (::socket.isInitialized)
|
||||
socket.isConnected
|
||||
else false
|
||||
|
||||
actual override fun close() {
|
||||
if (::socket.isInitialized) {
|
||||
socket.close()
|
||||
}
|
||||
thread.shutdownNow()
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal lateinit var writeChannel: BufferedOutputStream
|
||||
|
||||
@PublishedApi
|
||||
internal lateinit var readChannel: BufferedInputStream
|
||||
|
||||
actual suspend fun send(packet: ByteArray, offset: Int, length: Int) {
|
||||
withContext(Dispatchers.IO) {
|
||||
writeChannel.write(packet, offset, length)
|
||||
writeChannel.flush()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SendPacketInternalException
|
||||
*/
|
||||
actual suspend fun send(packet: ByteReadPacket) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
writeChannel.writePacket(packet)
|
||||
writeChannel.flush()
|
||||
} catch (e: IOException) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val thread = Executors.newSingleThreadExecutor()
|
||||
|
||||
/**
|
||||
* @throws ReadPacketInternalException
|
||||
*/
|
||||
actual suspend fun read(): ByteReadPacket = suspendCancellableCoroutine { cont ->
|
||||
thread.submit {
|
||||
kotlin.runCatching {
|
||||
readChannel.readPacketAtMost(Long.MAX_VALUE)
|
||||
}.let {
|
||||
cont.resumeWith(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend fun connect(coroutineContext: CoroutineContext, serverHost: String, serverPort: Int) {
|
||||
withContext(Dispatchers.IO) {
|
||||
socket = Socket(serverHost, serverPort)
|
||||
readChannel = socket.getInputStream().buffered()
|
||||
writeChannel = socket.getOutputStream().buffered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ACTUAL_WITHOUT_EXPECT")
|
||||
internal actual typealias NoRouteToHostException = java.net.NoRouteToHostException
|
||||
|
||||
@Suppress("ACTUAL_WITHOUT_EXPECT")
|
||||
internal actual typealias SocketException = SocketException
|
||||
|
||||
// ktor aSocket
|
||||
|
||||
/*
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import io.ktor.network.selector.ActorSelectorManager
|
||||
import io.ktor.network.sockets.*
|
||||
import io.ktor.util.KtorExperimentalAPI
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.ktor.utils.io.ByteWriteChannel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Closeable
|
||||
import kotlinx.io.core.ExperimentalIoApi
|
||||
import kotlinx.io.core.buildPacket
|
||||
import kotlinx.io.errors.IOException
|
||||
import useBytes
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.SocketException
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* 多平台适配的 TCP Socket.
|
||||
*/
|
||||
internal actual class PlatformSocket : Closeable {
|
||||
private lateinit var socket: io.ktor.network.sockets.Socket
|
||||
|
||||
actual val isOpen: Boolean
|
||||
get() =
|
||||
if (::socket.isInitialized)
|
||||
!socket.isClosed
|
||||
else false
|
||||
|
||||
actual override fun close() {
|
||||
if (::socket.isInitialized) {
|
||||
socket.close()
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal lateinit var writeChannel: ByteWriteChannel
|
||||
|
||||
@PublishedApi
|
||||
internal lateinit var readChannel: ByteReadChannel
|
||||
|
||||
actual suspend fun send(packet: ByteArray, offset: Int, length: Int) {
|
||||
withContext(Dispatchers.IO) {
|
||||
writeChannel.writeFully(packet, offset, length)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SendPacketInternalException
|
||||
*/
|
||||
actual suspend fun send(packet: ByteReadPacket) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
packet.useBytes { data: ByteArray, length: Int ->
|
||||
writeChannel.writeFully(data, offset = 0, length = length)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ReadPacketInternalException
|
||||
*/
|
||||
actual suspend fun read(): ByteReadPacket {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
buildPacket {
|
||||
readChannel.read {
|
||||
writeFully(it)
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
throw ReadPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalIoApi::class, KtorExperimentalAPI::class)
|
||||
actual suspend fun connect(coroutineContext: CoroutineContext, serverHost: String, serverPort: Int) {
|
||||
withContext(Dispatchers.IO) {
|
||||
socket = aSocket(ActorSelectorManager(coroutineContext)).tcp().tcpNoDelay()
|
||||
.connect(InetSocketAddress(serverHost, serverPort))
|
||||
readChannel = socket.openReadChannel()
|
||||
writeChannel = socket.openWriteChannel(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual typealias NoRouteToHostException = java.net.NoRouteToHostException
|
||||
|
||||
actual typealias SocketException = SocketException
|
||||
*/
|
||||
@Suppress("ACTUAL_WITHOUT_EXPECT")
|
||||
internal actual typealias UnknownHostException = java.net.UnknownHostException
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Closeable
|
||||
import kotlinx.io.nio.readPacketAtMost
|
||||
import kotlinx.io.nio.writePacket
|
||||
import java.net.InetSocketAddress
|
||||
import java.nio.channels.DatagramChannel
|
||||
import java.nio.channels.ReadableByteChannel
|
||||
import java.nio.channels.WritableByteChannel
|
||||
|
||||
|
||||
/**
|
||||
* 多平台适配的 DatagramChannel.
|
||||
*/
|
||||
internal actual class PlatformDatagramChannel actual constructor(
|
||||
serverHost: String,
|
||||
serverPort: Short
|
||||
) : Closeable {
|
||||
@PublishedApi
|
||||
internal val channel: DatagramChannel = DatagramChannel.open().connect(InetSocketAddress(serverHost, serverPort.toInt()))
|
||||
actual val isOpen: Boolean get() = channel.isOpen
|
||||
override fun close() = channel.close()
|
||||
|
||||
actual suspend inline fun send(packet: ByteReadPacket): Boolean = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
(channel as WritableByteChannel).writePacket(packet)
|
||||
} catch (e: Throwable) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
|
||||
actual suspend inline fun read(): ByteReadPacket = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
(channel as ReadableByteChannel).readPacketAtMost(Long.MAX_VALUE)
|
||||
} catch (e: Throwable) {
|
||||
throw ReadPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
actual class PlatformDatagramChannel actual constructor(serverHost: String, serverPort: Short) : Closeable {
|
||||
private val serverAddress: InetSocketAddress = InetSocketAddress(serverHost, serverPort.toInt())
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val socket = runBlocking { aSocket(ActorSelectorManager(Dispatchers.IO)).tcp()
|
||||
.connect(remoteAddress = serverAddress) }
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val readChannel = socket.openReadChannel()
|
||||
|
||||
@KtorExperimentalAPI
|
||||
val writeChannel = socket.openWriteChannel(true)
|
||||
|
||||
@KtorExperimentalAPI
|
||||
@Throws(ReadPacketInternalException::class)
|
||||
actual suspend fun read(buffer: IoBuffer) =
|
||||
try {
|
||||
readChannel.readAvailable(buffer)
|
||||
} catch (e: ClosedChannelException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw ReadPacketInternalException(e)
|
||||
}
|
||||
|
||||
|
||||
@KtorExperimentalAPI
|
||||
@Throws(SendPacketInternalException::class)
|
||||
actual suspend fun send(buffer: IoBuffer) =
|
||||
buffer.readDirect {
|
||||
try {
|
||||
writeChannel.writeFully(it)
|
||||
} catch (e: ClosedChannelException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
throw SendPacketInternalException(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@KtorExperimentalAPI
|
||||
@Throws(IOException::class)
|
||||
override fun close() {
|
||||
socket.close()
|
||||
}
|
||||
|
||||
@KtorExperimentalAPI
|
||||
actual val isOpen: Boolean
|
||||
get() = socket.isClosed.not()
|
||||
}
|
||||
*/
|
@ -7,7 +7,7 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils.cryptor
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import net.mamoe.mirai.internal.utils.MiraiPlatformUtils
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
@ -31,9 +31,7 @@ internal actual class ECDHKeyPairImpl(
|
||||
override val initialShareKey: ByteArray by lazy { ECDH.calculateShareKey(privateKey, initialPublicKey) }
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
internal actual fun ECDH() =
|
||||
ECDH(ECDH.generateKeyPair())
|
||||
internal actual fun ECDH() = ECDH(ECDH.generateKeyPair())
|
||||
|
||||
internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
|
||||
actual companion object {
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
internal actual fun KProperty1<*, *>.getValueAgainstPermission(receiver: Any): Any? {
|
||||
return this.javaField?.apply { isAccessible = true }?.get(receiver)
|
||||
}
|
Loading…
Reference in New Issue
Block a user