Simplify platform structure, simplify network implementations

This commit is contained in:
Him188 2020-12-17 09:18:25 +08:00
parent 9c71a9c953
commit 6ccd20c377
18 changed files with 174 additions and 472 deletions

View File

@ -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) {

View File

@ -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.*

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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] 时出现的错误.
*/

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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
/**

View File

@ -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) {

View File

@ -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

View File

@ -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()
}
*/

View File

@ -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 {

View File

@ -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)
}