diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt new file mode 100644 index 000000000..8a8202034 --- /dev/null +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt @@ -0,0 +1,40 @@ +package net.mamoe.mirai.network + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.io.core.use +import kotlinx.io.streams.inputStream +import net.mamoe.mirai.Bot +import net.mamoe.mirai.message.Image +import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter +import net.mamoe.mirai.network.protocol.tim.packet.SessionKey +import net.mamoe.mirai.utils.ExternalImage +import net.mamoe.mirai.utils.InternalAPI +import net.mamoe.mirai.utils.toExternalImage +import java.io.File +import java.io.InputStream +import java.io.OutputStream + +/** + * Android 平台相关扩展. 详情查看 [BotSessionBase] + * + * @author Him188moe + */ +@UseExperimental(InternalAPI::class) +actual class BotSession actual constructor( + bot: Bot, + sessionKey: SessionKey, + socket: DataPacketSocketAdapter, + NetworkScope: CoroutineScope +) : BotSessionBase(bot, sessionKey, socket, NetworkScope) { + + suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() + suspend inline fun Image.downloadAsBitmap(): Bitmap = withContext(Dispatchers.IO) { downloadAsStream().use { BitmapFactory.decodeStream(it) } } + suspend inline fun Image.downloadAsExternalImage(): ExternalImage = download().use { it.toExternalImage() } + + suspend inline fun Image.downloadTo(file: File) = file.outputStream().use { downloadTo(it) } + suspend inline fun Image.downloadTo(output: OutputStream) = download().inputStream().use { input -> withContext(Dispatchers.IO) { input.copyTo(output) } } +} \ No newline at end of file diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/PlatformBotSession.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/PlatformBotSession.kt new file mode 100644 index 000000000..a0dd316ef --- /dev/null +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/PlatformBotSession.kt @@ -0,0 +1,2 @@ +package net.mamoe.mirai.network + diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/event/MessagePacket.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/event/MessagePacket.kt new file mode 100644 index 000000000..f85c9a4e1 --- /dev/null +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/event/MessagePacket.kt @@ -0,0 +1,10 @@ +package net.mamoe.mirai.network.protocol.tim.packet.event + +import net.mamoe.mirai.contact.Contact +import net.mamoe.mirai.utils.InternalAPI + +/** + * 平台相关扩展 + */ +@UseExperimental(InternalAPI::class) +actual sealed class MessagePacket : MessagePacketBase() \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt index 3b5f0c27d..9b8cd4929 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt @@ -6,13 +6,13 @@ import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.Job -import net.mamoe.mirai.Bot +import kotlinx.io.core.ByteReadPacket +import net.mamoe.mirai.* import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.GroupId import net.mamoe.mirai.contact.GroupInternalId import net.mamoe.mirai.contact.QQ -import net.mamoe.mirai.getGroup -import net.mamoe.mirai.getQQ +import net.mamoe.mirai.message.Image import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler import net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter @@ -20,7 +20,9 @@ import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket import net.mamoe.mirai.network.protocol.tim.packet.Packet import net.mamoe.mirai.network.protocol.tim.packet.SessionKey -import net.mamoe.mirai.sendPacket +import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImagePacket +import net.mamoe.mirai.network.protocol.tim.packet.action.ImageLink +import net.mamoe.mirai.utils.InternalAPI import net.mamoe.mirai.utils.getGTK import net.mamoe.mirai.utils.internal.PositiveNumbers import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail @@ -39,9 +41,23 @@ internal inline fun TIMBotNetworkHandler.BotSession( * 登录会话. 当登录完成后, 客户端会拿到 sessionKey. * 此时建立 session, 然后开始处理事务. * + * 本类中含有各平台相关扩展函数等. + * * @author Him188moe */ -data class BotSession( +@UseExperimental(InternalAPI::class) +expect class BotSession( + bot: Bot, + sessionKey: SessionKey, + socket: DataPacketSocketAdapter, + NetworkScope: CoroutineScope +) : BotSessionBase + +/** + * [BotSession] 平台通用基础 + */ +@InternalAPI +abstract class BotSessionBase( val bot: Bot, val sessionKey: SessionKey, val socket: DataPacketSocketAdapter, @@ -97,7 +113,7 @@ data class BotSession( noinline handler: suspend (P) -> R ): Deferred { val deferred: CompletableDeferred = CompletableDeferred(coroutineContext[Job]) - bot.network.addHandler(TemporaryPacketHandler(P::class, deferred, this@BotSession, checkSequence, coroutineContext + deferred).also { + bot.network.addHandler(TemporaryPacketHandler(P::class, deferred, this@BotSessionBase as BotSession, checkSequence, coroutineContext + deferred).also { it.toSend(this) it.onExpect(handler) }) @@ -125,6 +141,10 @@ data class BotSession( suspend inline fun UInt.group(): Group = bot.getGroup(GroupId(this)) suspend inline fun GroupId.group(): Group = bot.getGroup(this) suspend inline fun GroupInternalId.group(): Group = bot.getGroup(this) + + suspend fun Image.getLink(): ImageLink = FriendImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect() + suspend inline fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray() + suspend inline fun Image.download(): ByteReadPacket = getLink().download() } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt new file mode 100644 index 000000000..c95c3453f --- /dev/null +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt @@ -0,0 +1,39 @@ +package net.mamoe.mirai.network + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.withContext +import kotlinx.io.core.use +import kotlinx.io.streams.inputStream +import net.mamoe.mirai.Bot +import net.mamoe.mirai.message.Image +import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter +import net.mamoe.mirai.network.protocol.tim.packet.SessionKey +import net.mamoe.mirai.utils.ExternalImage +import net.mamoe.mirai.utils.InternalAPI +import net.mamoe.mirai.utils.toExternalImage +import java.awt.image.BufferedImage +import java.io.File +import java.io.InputStream +import java.io.OutputStream +import javax.imageio.ImageIO + +/** + * JVM 平台相关扩展. 详情查看 [BotSessionBase] + */ +@UseExperimental(InternalAPI::class) +@Suppress("unused") +actual class BotSession actual constructor( + bot: Bot, + sessionKey: SessionKey, + socket: DataPacketSocketAdapter, + NetworkScope: CoroutineScope +) : BotSessionBase(bot, sessionKey, socket, NetworkScope) { + + suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() + suspend inline fun Image.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } } + suspend inline fun Image.downloadAsExternalImage(): ExternalImage = download().use { it.toExternalImage() } + + suspend inline fun Image.downloadTo(file: File) = file.outputStream().use { downloadTo(it) } + suspend inline fun Image.downloadTo(output: OutputStream) = download().inputStream().use { input -> withContext(IO) { input.transferTo(output) } } +} \ No newline at end of file