Generify functions

This commit is contained in:
Him188 2020-03-07 11:29:04 +08:00
parent defe7ce054
commit 26210e7845
5 changed files with 90 additions and 44 deletions

View File

@ -20,6 +20,7 @@ import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.OfflineImage
import net.mamoe.mirai.message.data.sendTo
import net.mamoe.mirai.utils.io.toUHexString
@ -159,7 +160,7 @@ suspend fun <C : Contact> ExternalImage.sendTo(contact: C): MessageReceipt<C> =
*
* @see contact 图片上传对象. 由于好友图片与群图片不通用, 上传时必须提供目标联系人
*/
suspend fun ExternalImage.upload(contact: Contact): Image = when (contact) {
suspend fun ExternalImage.upload(contact: Contact): OfflineImage = when (contact) {
is Group -> contact.uploadImage(this)
is QQ -> contact.uploadImage(this)
else -> error("unreachable")

View File

@ -15,6 +15,8 @@ package net.mamoe.mirai.utils
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.ByteWriteChannel
import io.ktor.utils.io.close
import io.ktor.utils.io.core.Output
import io.ktor.utils.io.core.writeFully
import io.ktor.utils.io.pool.useInstance
@ -52,6 +54,19 @@ suspend fun ByteReadChannel.copyTo(dst: Output) {
}
}
/**
* 从接收者管道读取所有数据并写入 [dst]. 不会关闭 [dst]
*/
suspend fun ByteReadChannel.copyTo(dst: ByteWriteChannel) {
@UseExperimental(MiraiInternalAPI::class)
ByteArrayPool.useInstance { buffer ->
var size: Int
while (this.readAvailable(buffer).also { size = it } > 0) {
dst.writeFully(buffer, 0, size)
}
}
}
/* // 垃圾 kotlin, Unresolved reference: ByteWriteChannel
/**
@ -104,6 +119,24 @@ suspend fun ByteReadChannel.copyAndClose(dst: Output) {
}
}
/**
* 从接收者管道读取所有数据并写入 [dst], 最终关闭 [dst]
*/
suspend fun ByteReadChannel.copyAndClose(dst: ByteWriteChannel) {
try {
@UseExperimental(MiraiInternalAPI::class)
ByteArrayPool.useInstance { buffer ->
var size: Int
while (this.readAvailable(buffer).also { size = it } > 0) {
dst.writeFully(buffer, 0, size)
}
}
} finally {
@Suppress("DuplicatedCode")
dst.close()
}
}
/*// 垃圾 kotlin, Unresolved reference: ByteWriteChannel
/**
* 从接收者管道读取所有数据并写入 [dst], 最终关闭 [dst]

View File

@ -11,7 +11,9 @@
package net.mamoe.mirai.message
import io.ktor.utils.io.ByteWriteChannel
import io.ktor.utils.io.core.Input
import io.ktor.utils.io.core.Output
import io.ktor.utils.io.core.use
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.QQ
@ -41,17 +43,15 @@ actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual con
// endregion
// region 发送图片
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 sendImage(image: BufferedImage): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: URL): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: Input): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: InputStream): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: File): MessageReceipt<TSubject> = subject.sendImage(image)
// endregion
// region 上传图片 (扩展)
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)
@ -59,12 +59,11 @@ actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual con
// endregion 上传图片 (扩展)
// region 发送图片 (扩展)
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)
suspend inline fun BufferedImage.send(): MessageReceipt<TSubject> = sendTo(subject)
suspend inline fun URL.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun Input.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun InputStream.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun File.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
// endregion 发送图片 (扩展)
// region 下载图片 (扩展)
@ -80,6 +79,26 @@ actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual con
*/
suspend inline fun Image.downloadAndClose(output: OutputStream) = channel().copyAndClose(output)
/**
* 下载图片到 [output] 但不关闭这个 [output]
*/
suspend inline fun Image.downloadTo(output: Output) = channel().copyTo(output)
/**
* 下载图片到 [output] 并关闭这个 [output]
*/
suspend inline fun Image.downloadAndClose(output: Output) = channel().copyAndClose(output)
/**
* 下载图片到 [output] 但不关闭这个 [output]
*/
suspend inline fun Image.downloadTo(output: ByteWriteChannel) = channel().copyTo(output)
/**
* 下载图片到 [output] 并关闭这个 [output]
*/
suspend inline fun Image.downloadAndClose(output: ByteWriteChannel) = channel().copyAndClose(output)
/*
suspend inline fun Image.downloadAsStream(): InputStream = channel().asInputStream()
suspend inline fun Image.downloadAsExternalImage(): ExternalImage = withContext(Dispatchers.IO) { downloadAsStream().toExternalImage() }

View File

@ -59,15 +59,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
actual suspend fun recall() {
@Suppress("BooleanLiteralArgument")
if (_isRecalled.compareAndSet(false, true)) {
when (val contact = target) {
is Group -> {
contact.bot.recall(source)
}
is QQ -> {
TODO()
}
else -> error("Unknown contact type")
}
target.bot.recall(source)
} else error("message is already or planned to be recalled")
}

View File

@ -16,6 +16,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.OfflineImage
import net.mamoe.mirai.utils.OverFileSizeMaxException
import net.mamoe.mirai.utils.sendTo
import net.mamoe.mirai.utils.toExternalImage
@ -36,37 +37,37 @@ import java.net.URL
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun BufferedImage.sendTo(contact: Contact) = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
suspend fun <C : Contact> BufferedImage.sendTo(contact: C): MessageReceipt<C> = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
/**
* [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun URL.sendAsImageTo(contact: Contact) = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
suspend fun <C : Contact> URL.sendAsImageTo(contact: C): MessageReceipt<C> = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Input.sendAsImageTo(contact: Contact) = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
suspend fun <C : Contact> Input.sendAsImageTo(contact: C): MessageReceipt<C> = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun InputStream.sendAsImageTo(contact: Contact) = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
suspend fun <C : Contact> InputStream.sendAsImageTo(contact: C): MessageReceipt<C> = withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
/**
* [Dispatchers.IO] 中将文件作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun File.sendAsImageTo(contact: Contact) {
suspend fun <C : Contact> File.sendAsImageTo(contact: C): MessageReceipt<C> {
require(this.exists() && this.canRead())
withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
return withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
}
// endregion
@ -78,35 +79,35 @@ suspend fun File.sendAsImageTo(contact: Contact) {
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun BufferedImage.upload(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun BufferedImage.upload(contact: Contact): OfflineImage = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun URL.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun URL.uploadAsImage(contact: Contact): OfflineImage = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun Input.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun Input.uploadAsImage(contact: Contact): OfflineImage = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun InputStream.uploadAsImage(contact: Contact): Image = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
suspend fun InputStream.uploadAsImage(contact: Contact): OfflineImage = withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
/**
* [Dispatchers.IO] 中将文件作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend fun File.uploadAsImage(contact: Contact): Image {
suspend fun File.uploadAsImage(contact: Contact): OfflineImage {
require(this.exists() && this.canRead())
return withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
}
@ -120,35 +121,35 @@ suspend fun File.uploadAsImage(contact: Contact): Image {
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.sendImage(bufferedImage: BufferedImage) = bufferedImage.sendTo(this)
suspend inline fun <C : Contact> C.sendImage(bufferedImage: BufferedImage): MessageReceipt<C> = bufferedImage.sendTo(this)
/**
* [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.sendImage(imageUrl: URL) = imageUrl.sendAsImageTo(this)
suspend inline fun <C : Contact> C.sendImage(imageUrl: URL): MessageReceipt<C> = imageUrl.sendAsImageTo(this)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.sendImage(imageInput: Input) = imageInput.sendAsImageTo(this)
suspend inline fun <C : Contact> C.sendImage(imageInput: Input): MessageReceipt<C> = imageInput.sendAsImageTo(this)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.sendImage(imageStream: InputStream) = imageStream.sendAsImageTo(this)
suspend inline fun <C : Contact> C.sendImage(imageStream: InputStream): MessageReceipt<C> = imageStream.sendAsImageTo(this)
/**
* [Dispatchers.IO] 中将文件作为图片发送到指定联系人
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
suspend inline fun <C : Contact> C.sendImage(file: File): MessageReceipt<C> = file.sendAsImageTo(this)
// endregion
@ -159,34 +160,34 @@ suspend inline fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.uploadImage(bufferedImage: BufferedImage): Image = bufferedImage.upload(this)
suspend inline fun Contact.uploadImage(bufferedImage: BufferedImage): OfflineImage = bufferedImage.upload(this)
/**
* [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片上传, 但不发送
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.uploadImage(imageUrl: URL): Image = imageUrl.uploadAsImage(this)
suspend inline fun Contact.uploadImage(imageUrl: URL): OfflineImage = imageUrl.uploadAsImage(this)
/**
* [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片上传, 但不发送
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.uploadImage(imageInput: Input): Image = imageInput.uploadAsImage(this)
suspend inline fun Contact.uploadImage(imageInput: Input): OfflineImage = imageInput.uploadAsImage(this)
/**
* [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片上传, 但不发送
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.uploadImage(imageStream: InputStream): Image = imageStream.uploadAsImage(this)
suspend inline fun Contact.uploadImage(imageStream: InputStream): OfflineImage = imageStream.uploadAsImage(this)
/**
* [Dispatchers.IO] 中将文件作为图片上传, 但不发送
* @throws OverFileSizeMaxException
*/
@Throws(OverFileSizeMaxException::class)
suspend inline fun Contact.uploadImage(file: File): Image = file.uploadAsImage(this)
suspend inline fun Contact.uploadImage(file: File): OfflineImage = file.uploadAsImage(this)
// endregion