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.contact.QQ
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.Image 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.message.data.sendTo
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
@ -159,7 +160,7 @@ suspend fun <C : Contact> ExternalImage.sendTo(contact: C): MessageReceipt<C> =
* *
* @see contact 图片上传对象. 由于好友图片与群图片不通用, 上传时必须提供目标联系人 * @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 Group -> contact.uploadImage(this)
is QQ -> contact.uploadImage(this) is QQ -> contact.uploadImage(this)
else -> error("unreachable") 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.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.Output
import io.ktor.utils.io.core.writeFully import io.ktor.utils.io.core.writeFully
import io.ktor.utils.io.pool.useInstance 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 /* // 垃圾 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 /*// 垃圾 kotlin, Unresolved reference: ByteWriteChannel
/** /**
* 从接收者管道读取所有数据并写入 [dst], 最终关闭 [dst] * 从接收者管道读取所有数据并写入 [dst], 最终关闭 [dst]

View File

@ -11,7 +11,9 @@
package net.mamoe.mirai.message package net.mamoe.mirai.message
import io.ktor.utils.io.ByteWriteChannel
import io.ktor.utils.io.core.Input import io.ktor.utils.io.core.Input
import io.ktor.utils.io.core.Output
import io.ktor.utils.io.core.use import io.ktor.utils.io.core.use
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.contact.QQ
@ -41,17 +43,15 @@ actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual con
// endregion // endregion
// region 发送图片 // region 发送图片
suspend inline fun sendImage(image: BufferedImage) = 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: URL) = subject.sendImage(image) suspend inline fun sendImage(image: Input): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: Input) = subject.sendImage(image) suspend inline fun sendImage(image: InputStream): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: InputStream) = subject.sendImage(image) suspend inline fun sendImage(image: File): MessageReceipt<TSubject> = subject.sendImage(image)
suspend inline fun sendImage(image: File) = subject.sendImage(image)
// endregion // endregion
// region 上传图片 (扩展) // region 上传图片 (扩展)
suspend inline fun BufferedImage.upload(): Image = upload(subject) suspend inline fun BufferedImage.upload(): Image = upload(subject)
suspend inline fun URL.uploadAsImage(): Image = uploadAsImage(subject) suspend inline fun URL.uploadAsImage(): Image = uploadAsImage(subject)
suspend inline fun Input.uploadAsImage(): Image = uploadAsImage(subject) suspend inline fun Input.uploadAsImage(): Image = uploadAsImage(subject)
suspend inline fun InputStream.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 上传图片 (扩展) // endregion 上传图片 (扩展)
// region 发送图片 (扩展) // region 发送图片 (扩展)
suspend inline fun BufferedImage.send() = sendTo(subject) suspend inline fun BufferedImage.send(): MessageReceipt<TSubject> = sendTo(subject)
suspend inline fun URL.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun URL.sendAsImage() = sendAsImageTo(subject) suspend inline fun Input.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun Input.sendAsImage() = sendAsImageTo(subject) suspend inline fun InputStream.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun InputStream.sendAsImage() = sendAsImageTo(subject) suspend inline fun File.sendAsImage(): MessageReceipt<TSubject> = sendAsImageTo(subject)
suspend inline fun File.sendAsImage() = sendAsImageTo(subject)
// endregion 发送图片 (扩展) // endregion 发送图片 (扩展)
// region 下载图片 (扩展) // 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) 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.downloadAsStream(): InputStream = channel().asInputStream()
suspend inline fun Image.downloadAsExternalImage(): ExternalImage = withContext(Dispatchers.IO) { downloadAsStream().toExternalImage() } 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() { actual suspend fun recall() {
@Suppress("BooleanLiteralArgument") @Suppress("BooleanLiteralArgument")
if (_isRecalled.compareAndSet(false, true)) { if (_isRecalled.compareAndSet(false, true)) {
when (val contact = target) { target.bot.recall(source)
is Group -> {
contact.bot.recall(source)
}
is QQ -> {
TODO()
}
else -> error("Unknown contact type")
}
} else error("message is already or planned to be recalled") } 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 kotlinx.coroutines.withContext
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.data.Image 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.OverFileSizeMaxException
import net.mamoe.mirai.utils.sendTo import net.mamoe.mirai.utils.sendTo
import net.mamoe.mirai.utils.toExternalImage import net.mamoe.mirai.utils.toExternalImage
@ -36,37 +37,37 @@ import java.net.URL
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片发送到指定联系人 * [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片发送到指定联系人 * [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片发送到指定联系人 * [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 中将文件作为图片发送到指定联系人 * [Dispatchers.IO] 中将文件作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @Throws(OverFileSizeMaxException::class)
suspend fun File.sendAsImageTo(contact: Contact) { suspend fun <C : Contact> File.sendAsImageTo(contact: C): MessageReceipt<C> {
require(this.exists() && this.canRead()) require(this.exists() && this.canRead())
withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact) return withContext(Dispatchers.IO) { toExternalImage() }.sendTo(contact)
} }
// endregion // endregion
@ -78,35 +79,35 @@ suspend fun File.sendAsImageTo(contact: Contact) {
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] * [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] * [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] * [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] * [Dispatchers.IO] 中将文件作为图片上传后构造 [Image]
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @Throws(OverFileSizeMaxException::class)
suspend fun File.uploadAsImage(contact: Contact): Image { suspend fun File.uploadAsImage(contact: Contact): OfflineImage {
require(this.exists() && this.canRead()) require(this.exists() && this.canRead())
return withContext(Dispatchers.IO) { toExternalImage() }.upload(contact) return withContext(Dispatchers.IO) { toExternalImage() }.upload(contact)
} }
@ -120,35 +121,35 @@ suspend fun File.uploadAsImage(contact: Contact): Image {
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片发送到指定联系人 * [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片发送到指定联系人 * [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片发送到指定联系人 * [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 中将文件作为图片发送到指定联系人 * [Dispatchers.IO] 中将文件作为图片发送到指定联系人
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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 // endregion
@ -159,34 +160,34 @@ suspend inline fun Contact.sendImage(file: File) = file.sendAsImageTo(this)
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片上传, 但不发送 * [Dispatchers.IO] 中下载 [URL] 到临时文件并将其作为图片上传, 但不发送
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片上传, 但不发送 * [Dispatchers.IO] 中读取 [Input] 到临时文件并将其作为图片上传, 但不发送
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 到临时文件并将其作为图片上传, 但不发送 * [Dispatchers.IO] 中读取 [InputStream] 到临时文件并将其作为图片上传, 但不发送
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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] 中将文件作为图片上传, 但不发送 * [Dispatchers.IO] 中将文件作为图片上传, 但不发送
* @throws OverFileSizeMaxException * @throws OverFileSizeMaxException
*/ */
@Throws(OverFileSizeMaxException::class) @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 // endregion