mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-04 08:27:00 +08:00
e256ec06d3
* Proto structs for group file * RemoteFile fundamental abstraction and proto structs * Configure JVM target for mirai-console-intellij * Add Group.filesRoot * Fix build * Implement a FileSystem for RemoteFile resolution * Fix RemoteFile FileSystem and implement resolve and listFiles * Implement file info query and file download * Support uploading group file * Support file feeds * 2.5-M2-dev-1 * Fix tests * 2.5-M2-dev-2 * Add uuid-based resolving, support getting file details * Support FileMessage receive * Support sending FileMessage * 2.5-M2-dev-3 * Add DownloadInfo.id * Improve RemoteFile.delete * Support move, delete, rename, mkdir. Simplify listFiles * - Rename RemoteFile.write to .upload. - Prefer id matching - Improve move * Add permission checks * Improve permission checks * Rearrange functions and add constant ROOT_PATH * Introduce FileSupported, add extensions * Introduce ProgressionCallback * Fix docs and uploadFileAndSend * Remove empty FileHighway.kt * Add test testNormalize * Add RemoteFile.contact, change RemoteFile.uploadAndSend return type to MessageReceipt * Move @JvmBlockingBridge to file * Change FileMessage.toRemoteFile parameter type Group to FileSupported * Add impl notes #1082
156 lines
4.5 KiB
Kotlin
156 lines
4.5 KiB
Kotlin
/*
|
|
* Copyright 2019-2021 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
|
|
*/
|
|
|
|
@file:JvmMultifileClass
|
|
@file:JvmName("MiraiUtils")
|
|
|
|
package net.mamoe.mirai.utils
|
|
|
|
import io.ktor.client.*
|
|
import io.ktor.client.features.*
|
|
import kotlinx.io.core.Input
|
|
import kotlinx.io.core.readAvailable
|
|
import java.io.*
|
|
import java.net.Inet4Address
|
|
import java.security.MessageDigest
|
|
import java.util.zip.Deflater
|
|
import java.util.zip.GZIPInputStream
|
|
import java.util.zip.GZIPOutputStream
|
|
import java.util.zip.Inflater
|
|
import kotlin.contracts.InvocationKind
|
|
import kotlin.contracts.contract
|
|
|
|
@JvmOverloads
|
|
public fun ByteArray.unzip(offset: Int = 0, length: Int = size - offset): ByteArray {
|
|
checkOffsetAndLength(offset, length)
|
|
if (length == 0) return ByteArray(0)
|
|
|
|
val inflater = Inflater()
|
|
inflater.reset()
|
|
ByteArrayOutputStream().use { output ->
|
|
inflater.setInput(this, offset, length)
|
|
ByteArray(DEFAULT_BUFFER_SIZE).let {
|
|
while (!inflater.finished()) {
|
|
output.write(it, 0, inflater.inflate(it))
|
|
}
|
|
}
|
|
|
|
inflater.end()
|
|
return output.toByteArray()
|
|
}
|
|
}
|
|
|
|
public fun InputStream.md5(): ByteArray {
|
|
return digest("md5")
|
|
}
|
|
|
|
public fun InputStream.digest(algorithm: String): ByteArray {
|
|
val digest = MessageDigest.getInstance(algorithm)
|
|
digest.reset()
|
|
use { input ->
|
|
object : OutputStream() {
|
|
override fun write(b: Int) {
|
|
digest.update(b.toByte())
|
|
}
|
|
|
|
override fun write(b: ByteArray, off: Int, len: Int) {
|
|
digest.update(b, off, len)
|
|
}
|
|
}.use { output ->
|
|
input.copyTo(output)
|
|
}
|
|
}
|
|
return digest.digest()
|
|
}
|
|
|
|
public fun InputStream.sha1(): ByteArray {
|
|
return digest("SHA-1")
|
|
}
|
|
|
|
/**
|
|
* Localhost 解析
|
|
*/
|
|
public fun localIpAddress(): String = runCatching {
|
|
Inet4Address.getLocalHost().hostAddress
|
|
}.getOrElse { "192.168.1.123" }
|
|
|
|
public fun String.md5(): ByteArray = toByteArray().md5()
|
|
|
|
@JvmOverloads
|
|
public fun ByteArray.md5(offset: Int = 0, length: Int = size - offset): ByteArray {
|
|
checkOffsetAndLength(offset, length)
|
|
return MessageDigest.getInstance("MD5").apply { update(this@md5, offset, length) }.digest()
|
|
}
|
|
|
|
public fun String.sha1(): ByteArray = toByteArray().sha1()
|
|
|
|
@JvmOverloads
|
|
public fun ByteArray.sha1(offset: Int = 0, length: Int = size - offset): ByteArray {
|
|
checkOffsetAndLength(offset, length)
|
|
return MessageDigest.getInstance("SHA-1").apply { update(this@sha1, offset, length) }.digest()
|
|
}
|
|
|
|
@JvmOverloads
|
|
public fun ByteArray.ungzip(offset: Int = 0, length: Int = size - offset): ByteArray {
|
|
return GZIPInputStream(inputStream(offset, length)).use { it.readBytes() }
|
|
}
|
|
|
|
@JvmOverloads
|
|
public fun ByteArray.gzip(offset: Int = 0, length: Int = size - offset): ByteArray {
|
|
ByteArrayOutputStream().use { buf ->
|
|
GZIPOutputStream(buf).use { gzip ->
|
|
inputStream(offset, length).use { t -> t.copyTo(gzip) }
|
|
}
|
|
buf.flush()
|
|
return buf.toByteArray()
|
|
}
|
|
}
|
|
|
|
@JvmOverloads
|
|
public fun ByteArray.zip(offset: Int = 0, length: Int = size - offset): ByteArray {
|
|
checkOffsetAndLength(offset, length)
|
|
if (length == 0) return ByteArray(0)
|
|
|
|
val deflater = Deflater()
|
|
deflater.setInput(this, offset, length)
|
|
deflater.finish()
|
|
|
|
ByteArray(DEFAULT_BUFFER_SIZE).let {
|
|
return it.take(deflater.deflate(it)).toByteArray().also { deflater.end() }
|
|
}
|
|
}
|
|
|
|
public inline fun <C : Closeable, R> C.withUse(block: C.() -> R): R {
|
|
contract {
|
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
|
}
|
|
return use(block)
|
|
}
|
|
|
|
@Throws(IOException::class)
|
|
@JvmOverloads
|
|
public fun Input.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE): Long {
|
|
var bytesCopied: Long = 0
|
|
val buffer = ByteArray(bufferSize)
|
|
var bytes = readAvailable(buffer)
|
|
while (bytes >= 0) {
|
|
out.write(buffer, 0, bytes)
|
|
bytesCopied += bytes
|
|
bytes = readAvailable(buffer)
|
|
}
|
|
return bytesCopied
|
|
}
|
|
|
|
public inline fun <I : Closeable, O : Closeable, R> I.withOut(output: O, block: I.(output: O) -> R): R {
|
|
contract {
|
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
|
}
|
|
return use { output.use { block(this, output) } }
|
|
}
|