Platform specific APIs

This commit is contained in:
Him188 2019-11-16 00:48:18 +08:00
parent 6576b1c217
commit c839253e18
4 changed files with 78 additions and 36 deletions

View File

@ -4,10 +4,7 @@ package net.mamoe.mirai.message
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.download
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.Http
import kotlin.js.JsName
import kotlin.jvm.Volatile
@ -165,19 +162,10 @@ inline class Image(inline val id: ImageId) : Message {
* 对于好友, [value] 类似于 `/01ee6426-5ff1-4cf0-8278-e8634d2909ef`, 由服务器返回.
*
* @see ExternalImage.groupImageId 群图片的 [ImageId] 获取
* @see FriendImageIdRequestPacket.Response.RequireUpload.imageId 好友图片的 [ImageId] 获取
* @see FriendImagePacket 好友图片的 [ImageId] 获取
*/
inline class ImageId(inline val value: String)
/**
* 图片数据地址.
*/
inline class ImageLink(inline val value: String) {
// TODO: 2019/11/15 应添加更多方法. 避免使用 byte[]
suspend fun downloadAsByteArray(): ByteArray = Http.download(value)
}
fun ImageId.checkLength() = check(value.length == 37 || value.length == 42) { "Illegal ImageId length" }
fun ImageId.requireLength() = require(value.length == 37 || value.length == 42) { "Illegal ImageId length" }
@ -281,7 +269,7 @@ fun SingleMessageChain(delegate: Message): MessageChain {
*
* @see SingleMessageChain
* @see SingleMessageChainImpl
*/
*/ // TODO: 2019/11/15 有歧义
fun Message.singleChain(): MessageChain = if (this is MessageChain) this else SingleMessageChain(this)
/**

View File

@ -5,28 +5,33 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import net.mamoe.mirai.Bot
import net.mamoe.mirai.*
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.event.BroadcastControllable
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.getGroup
import net.mamoe.mirai.getQQ
import net.mamoe.mirai.message.*
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ImageLink
import net.mamoe.mirai.network.sessionKey
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.printTLVMap
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readTLVMap
import net.mamoe.mirai.utils.io.readUShortLVByteArray
import net.mamoe.mirai.utils.sendTo
import net.mamoe.mirai.utils.upload
sealed class MessagePacket<TSubject : Contact> : EventPacket, BotEvent() {
/**
* 平台相关扩展
*/
@UseExperimental(InternalAPI::class)
expect sealed class MessagePacket<TSubject : Contact>() : MessagePacketBase<TSubject>
@InternalAPI
abstract class MessagePacketBase<TSubject : Contact> : EventPacket, BotEvent() {
internal lateinit var botVar: Bot
override val bot: Bot get() = botVar
@ -70,6 +75,13 @@ sealed class MessagePacket<TSubject : Contact> : EventPacket, BotEvent() {
suspend inline fun String.send() = this.toMessage().sendTo(subject)
// endregion
// region Image download
suspend fun Image.getLink(): ImageLink = bot.withSession { FriendImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect() }
suspend inline fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray()
suspend inline fun Image.download(): ByteReadPacket = getLink().download()
// endregion
}
// region group message

View File

@ -75,28 +75,28 @@ suspend fun BufferedImage.upload(contact: Contact): Image = withContext(Dispatch
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun URL.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun URL.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Input.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun Input.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun InputStream.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun InputStream.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中将文件作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun File.upload(contact: Contact): Image {
suspend fun File.uploadAsImage(contact: Contact): Image {
require(this.exists() && this.canRead())
return withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
}
@ -110,35 +110,35 @@ suspend fun File.upload(contact: Contact): Image {
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.sendImage(bufferedImage: BufferedImage) = bufferedImage.sendTo(this)
suspend inline fun Contact.sendImage(bufferedImage: BufferedImage) = bufferedImage.sendTo(this)
/**
* [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.sendImage(imageUrl: URL) = imageUrl.sendAsImageTo(this)
suspend inline fun Contact.sendImage(imageUrl: URL) = imageUrl.sendAsImageTo(this)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.sendImage(imageInput: Input) = imageInput.sendAsImageTo(this)
suspend inline fun Contact.sendImage(imageInput: Input) = imageInput.sendAsImageTo(this)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.sendImage(imageStream: InputStream) = imageStream.sendAsImageTo(this)
suspend inline fun Contact.sendImage(imageStream: InputStream) = imageStream.sendAsImageTo(this)
/**
* [Dispatchers.IO] 中将文件作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
suspend inline fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
// endregion
@ -149,34 +149,34 @@ suspend fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.uploadImage(bufferedImage: BufferedImage): Image = bufferedImage.upload(this)
suspend inline fun Contact.uploadImage(bufferedImage: BufferedImage): Image = bufferedImage.upload(this)
/**
* [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.uploadImage(imageUrl: URL): Image = imageUrl.upload(this)
suspend inline fun Contact.uploadImage(imageUrl: URL): Image = imageUrl.uploadAsImage(this)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.uploadImage(imageInput: Input): Image = imageInput.upload(this)
suspend inline fun Contact.uploadImage(imageInput: Input): Image = imageInput.uploadAsImage(this)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.uploadImage(imageStream: InputStream): Image = imageStream.upload(this)
suspend inline fun Contact.uploadImage(imageStream: InputStream): Image = imageStream.uploadAsImage(this)
/**
* [Dispatchers.IO] 中将文件作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Contact.uploadImage(file: File): Image = file.upload(this)
suspend inline fun Contact.uploadImage(file: File): Image = file.uploadAsImage(this)
// endregion

View File

@ -0,0 +1,42 @@
@file:Suppress("unused")
package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.Input
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.*
import net.mamoe.mirai.utils.InternalAPI
import java.awt.image.BufferedImage
import java.io.File
import java.io.InputStream
import java.net.URL
/**
* 平台相关扩展
*/
@UseExperimental(InternalAPI::class)
actual sealed class MessagePacket<TSubject : Contact> : MessagePacketBase<TSubject>() {
suspend inline fun uploadImage(image: BufferedImage): Image = subject.uploadImage(image)
suspend inline fun uploadImage(image: URL): Image = subject.uploadImage(image)
suspend inline fun uploadImage(image: Input): Image = subject.uploadImage(image)
suspend inline fun uploadImage(image: InputStream): Image = subject.uploadImage(image)
suspend inline fun uploadImage(image: File): Image = subject.uploadImage(image)
suspend inline fun sendImage(image: BufferedImage) = subject.sendImage(image)
suspend inline fun sendImage(image: URL) = subject.sendImage(image)
suspend inline fun sendImage(image: Input) = subject.sendImage(image)
suspend inline fun sendImage(image: InputStream) = subject.sendImage(image)
suspend inline fun sendImage(image: File) = subject.sendImage(image)
suspend inline fun BufferedImage.upload(): Image = upload(subject)
suspend inline fun URL.uploadAsImage(): Image = uploadAsImage(subject)
suspend inline fun Input.uploadAsImage(): Image = uploadAsImage(subject)
suspend inline fun InputStream.uploadAsImage(): Image = uploadAsImage(subject)
suspend inline fun File.uploadAsImage(): Image = uploadAsImage(subject)
suspend inline fun BufferedImage.send() = sendTo(subject)
suspend inline fun URL.sendAsImage() = sendAsImageTo(subject)
suspend inline fun Input.sendAsImage() = sendAsImageTo(subject)
suspend inline fun InputStream.sendAsImage() = sendAsImageTo(subject)
suspend inline fun File.sendAsImage() = sendAsImageTo(subject)
}