Skip to content

Commit

Permalink
Merge pull request #993 from simple-robot/pref-resurce-io
Browse files Browse the repository at this point in the history
基于kotlinx-io改善Resource相关API
  • Loading branch information
ForteScarlet authored Dec 22, 2024
2 parents 7e2e2b0 + 0d9e287 commit fdcb4df
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 569 deletions.
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/P.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ fun isSnapshot(): Boolean = _isSnapshot
@Suppress("MemberVisibilityCanBePrivate")
sealed class P(override val group: String) : ProjectDetail() {
companion object {
const val VERSION = "4.9.0"
const val NEXT_VERSION = "4.9.1"
const val VERSION = "4.10.0"
const val NEXT_VERSION = "4.10.0"
const val SNAPSHOT_VERSION = "$VERSION-SNAPSHOT"
const val NEXT_SNAPSHOT_VERSION = "$NEXT_VERSION-SNAPSHOT"

Expand Down
39 changes: 31 additions & 8 deletions simbot-api/api/simbot-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -2195,11 +2195,15 @@ public abstract interface class love/forte/simbot/message/OfflineImage : love/fo
public static final field Companion Llove/forte/simbot/message/OfflineImage$Companion;
public abstract fun data ()[B
public static fun ofBytes ([B)Llove/forte/simbot/message/OfflineImage;
public static fun ofFilePath (Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
public static fun ofFilePath (Ljava/lang/String;[Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
public static fun ofResource (Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/message/OfflineImage;
}

public final class love/forte/simbot/message/OfflineImage$Companion {
public final fun ofBytes ([B)Llove/forte/simbot/message/OfflineImage;
public final fun ofFilePath (Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
public final fun ofFilePath (Ljava/lang/String;[Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
public final fun ofResource (Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/message/OfflineImage;
}

Expand Down Expand Up @@ -2528,14 +2532,15 @@ public abstract class love/forte/simbot/resource/AbstractJvmResourceValueResolve
public final fun resolveURI (Llove/forte/simbot/resource/URIResource;Ljava/lang/Object;)V
}

public abstract interface class love/forte/simbot/resource/ByteArrayResource : love/forte/simbot/resource/Resource {
public abstract interface class love/forte/simbot/resource/ByteArrayResource : love/forte/simbot/resource/Resource, love/forte/simbot/resource/SourceResource {
public abstract fun data ()[B
public fun source ()Lkotlinx/io/Source;
}

public abstract interface annotation class love/forte/simbot/resource/ExperimentalIOResourceAPI : java/lang/annotation/Annotation {
}

public abstract interface class love/forte/simbot/resource/FileResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/ReaderResource {
public abstract interface class love/forte/simbot/resource/FileResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/JvmSourceResource, love/forte/simbot/resource/ReaderResource {
public fun data ()[B
public abstract fun getFile ()Ljava/io/File;
public fun inputStream ()Ljava/io/InputStream;
Expand All @@ -2545,9 +2550,8 @@ public abstract interface class love/forte/simbot/resource/FileResource : love/f
public abstract fun string (Ljava/nio/charset/Charset;)Ljava/lang/String;
}

public abstract interface class love/forte/simbot/resource/InputStreamResource : love/forte/simbot/resource/Resource {
public fun data ()[B
public abstract fun inputStream ()Ljava/io/InputStream;
public abstract interface class love/forte/simbot/resource/InputStreamResource : love/forte/simbot/resource/SourceResource {
public fun inputStream ()Ljava/io/InputStream;
}

public abstract interface class love/forte/simbot/resource/JvmResourceResolver : love/forte/simbot/resource/ResourceResolver {
Expand All @@ -2572,6 +2576,9 @@ public abstract interface class love/forte/simbot/resource/JvmResourceValueResol
public abstract fun resolveURINotFileScheme (Ljava/net/URI;Ljava/lang/Object;)V
}

public abstract interface class love/forte/simbot/resource/JvmSourceResource : love/forte/simbot/resource/SourceResource {
}

public abstract interface class love/forte/simbot/resource/JvmStringReadableResource : love/forte/simbot/resource/StringReadableResource {
public static final field Companion Llove/forte/simbot/resource/JvmStringReadableResource$Companion;
public static final field DEFAULT_CHARSET Ljava/nio/charset/Charset;
Expand All @@ -2582,7 +2589,7 @@ public abstract interface class love/forte/simbot/resource/JvmStringReadableReso
public final class love/forte/simbot/resource/JvmStringReadableResource$Companion {
}

public abstract interface class love/forte/simbot/resource/PathResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/ReaderResource {
public abstract interface class love/forte/simbot/resource/PathResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/JvmSourceResource, love/forte/simbot/resource/ReaderResource {
public fun data ()[B
public abstract fun getPath ()Ljava/nio/file/Path;
public abstract fun inputStream ()Ljava/io/InputStream;
Expand Down Expand Up @@ -2622,6 +2629,7 @@ public final class love/forte/simbot/resource/ResourceResolver$Companion {
}

public final class love/forte/simbot/resource/Resources {
public static final fun inputStream (Llove/forte/simbot/resource/SourceResource;)Ljava/io/InputStream;
public static final fun valueOf (Ljava/io/File;)Llove/forte/simbot/resource/FileResource;
public static final fun valueOf (Ljava/io/File;Ljava/nio/charset/Charset;)Llove/forte/simbot/resource/FileResource;
public static final fun valueOf (Ljava/lang/String;)Llove/forte/simbot/resource/StringResource;
Expand All @@ -2631,22 +2639,37 @@ public final class love/forte/simbot/resource/Resources {
public static final fun valueOf (Ljava/net/URL;Ljava/nio/charset/Charset;)Llove/forte/simbot/resource/URIResource;
public static final fun valueOf (Ljava/nio/file/Path;Ljava/nio/charset/Charset;[Ljava/nio/file/OpenOption;)Llove/forte/simbot/resource/PathResource;
public static final fun valueOf (Ljava/nio/file/Path;[Ljava/nio/file/OpenOption;)Llove/forte/simbot/resource/PathResource;
public static final fun valueOf (Lkotlinx/io/files/Path;)Llove/forte/simbot/resource/SourceResource;
public static final fun valueOf ([B)Llove/forte/simbot/resource/ByteArrayResource;
public static synthetic fun valueOf$default (Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/Object;)Llove/forte/simbot/resource/FileResource;
public static synthetic fun valueOf$default (Ljava/net/URI;Ljava/nio/charset/Charset;ILjava/lang/Object;)Llove/forte/simbot/resource/URIResource;
public static synthetic fun valueOf$default (Ljava/net/URL;Ljava/nio/charset/Charset;ILjava/lang/Object;)Llove/forte/simbot/resource/URIResource;
public static synthetic fun valueOf$default (Ljava/nio/file/Path;Ljava/nio/charset/Charset;[Ljava/nio/file/OpenOption;ILjava/lang/Object;)Llove/forte/simbot/resource/PathResource;
public static final fun valueOfInputStreamProvider (Lkotlin/jvm/functions/Function0;)Llove/forte/simbot/resource/SourceResource;
public static final fun valueOfPath (Ljava/lang/String;)Llove/forte/simbot/resource/SourceResource;
public static final fun valueOfPath (Ljava/lang/String;[Ljava/lang/String;)Llove/forte/simbot/resource/SourceResource;
public static final fun valueOfSourceProvider (Lkotlin/jvm/functions/Function0;)Llove/forte/simbot/resource/SourceResource;
}

public abstract interface class love/forte/simbot/resource/StringReadableResource : love/forte/simbot/resource/Resource {
public abstract interface annotation class love/forte/simbot/resource/ScheduledDeprecatedResourceApi : java/lang/annotation/Annotation {
}

public abstract interface class love/forte/simbot/resource/SourceResource : love/forte/simbot/resource/Resource {
public fun data ()[B
public abstract fun source ()Lkotlinx/io/Source;
}

public abstract interface class love/forte/simbot/resource/StringReadableResource : love/forte/simbot/resource/SourceResource {
public fun data ()[B
public fun source ()Lkotlinx/io/Source;
public abstract fun string ()Ljava/lang/String;
}

public abstract interface class love/forte/simbot/resource/StringResource : love/forte/simbot/resource/StringReadableResource {
public abstract fun string ()Ljava/lang/String;
}

public abstract interface class love/forte/simbot/resource/URIResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/JvmStringReadableResource {
public abstract interface class love/forte/simbot/resource/URIResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/JvmSourceResource, love/forte/simbot/resource/JvmStringReadableResource {
public abstract fun getUri ()Ljava/net/URI;
public abstract fun inputStream ()Ljava/io/InputStream;
public fun string ()Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@

package love.forte.simbot.message

import love.forte.simbot.resource.ByteArrayResource
import love.forte.simbot.resource.Resource
import love.forte.simbot.resource.ResourceResolver
import love.forte.simbot.resource.*
import love.forte.simbot.resource.ResourceResolver.Companion.resolve
import love.forte.simbot.resource.StringResource
import kotlin.jvm.JvmStatic


Expand Down Expand Up @@ -76,6 +73,7 @@ public interface OfflineImageResolver<C> {
* 继承 [OfflineImageResolver] 和 [ResourceResolver],
* 对其中可能出现的实际内容物(例如 [ByteArray] 或 [String])进行处理。
*/
@ScheduledDeprecatedResourceApi
public interface OfflineImageValueResolver<C> :
OfflineImageResolver<C>,
ResourceResolver<C> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,14 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import love.forte.simbot.common.id.ID
import love.forte.simbot.common.id.IDContainer
import love.forte.simbot.message.At.Companion.equals
import love.forte.simbot.message.At.Companion.hashCode
import love.forte.simbot.message.OfflineImage.Companion.toOfflineImage
import love.forte.simbot.message.Text.Companion.of
import love.forte.simbot.resource.*
import love.forte.simbot.resource.ByteArrayResource
import love.forte.simbot.resource.Resource
import love.forte.simbot.resource.ResourceBase64Serializer
import love.forte.simbot.resource.fileResource
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.js.JsName
import kotlin.jvm.*
Expand Down Expand Up @@ -297,12 +302,16 @@ public interface UrlAwareImage : Image, UrlAwareMessage {
*
* “离线”主要表示此图片并未上传到某个目标平台中,也没有与某个远程服务器互相对应的唯一标识。
*
* @see OfflineImage.toOfflineImage
* 离线图片消息由本地构建,不会来自远端服务器或事件内。
* 离线图片消息无法保证可序列化性,尽可能避免对其进行序列化(包括作为 [Messages] 的元素时)。
*
* @see ByteArray.toOfflineImage
* @see Resource.toOfflineImage
*
* @see OfflineByteArrayImage
* @see SimpleOfflineResourceImage
* @see OfflineResourceImage
*/
public interface OfflineImage : Image {
public sealed interface OfflineImage : Image {
/**
* 得到图片的二进制数据
*/
Expand Down Expand Up @@ -348,7 +357,6 @@ public interface OfflineImage : Image {
*/
@JvmStatic
@JvmName("ofFilePath")
@ExperimentalIOResourceAPI
public fun fileOfflineImage(filePath: String): OfflineImage =
fileResource(filePath).toOfflineResourceImage()

Expand All @@ -363,7 +371,6 @@ public interface OfflineImage : Image {
* @since 4.7.0
*/
@JvmStatic
@ExperimentalIOResourceAPI
@JvmName("ofFilePath")
public fun fileOfflineImage(base: String, vararg parts: String): OfflineImage =
fileResource(base, *parts).toOfflineResourceImage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

package love.forte.simbot.resource

import kotlinx.io.Buffer
import kotlinx.io.Source
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
Expand All @@ -46,6 +48,17 @@ import kotlin.jvm.JvmName
* JVM 中的部分扩展、辅助API通过静态类 `Resources` 提供,
* 例如 `Resources.valueOf(...)`。
*
* ## 有限范围
*
* 从 `v4.10.0` 开始,[Resource] 接口转为 `sealed` 并有两个明确的子类型分支:
* - [ByteArrayResource]
* - [SourceResource]
*
* [ByteArrayResource] 代表一个可以**直接**使用 [ByteArray] 进行表示的资源,它也同样可以表示为 [SourceResource]。
*
* 其中,[SourceResource] 借助 `kotlinx-io` 库所提供的能力统一多平台的IO相关API(例如文件系统相关)。
* 如果你想要基于文件系统或其他与IO相关的内容构建一个 [Resource],则参考 [SourceResource]。
*
* ## 序列化
*
* [Resource] 提供了一个基于 [Base64] 进行序列化操作的 [ResourceBase64Serializer]。
Expand All @@ -59,9 +72,7 @@ import kotlin.jvm.JvmName
*
* @author ForteScarlet
*/
public interface Resource {
// TODO become `sealed` for ByteArrayResource and SourceResource.

public sealed interface Resource {
/**
* 读取此资源的字节数据。
*
Expand All @@ -83,11 +94,15 @@ public fun ByteArray.toResource(): ByteArrayResource = ByteArrayResourceImpl(thi
*
* @author forte
*/
public interface ByteArrayResource : Resource {
public interface ByteArrayResource : Resource, SourceResource {
/**
* 获取到字节数组结果。
*/
override fun data(): ByteArray

override fun source(): Source {
return Buffer().apply { write(data()) }
}
}

/**
Expand Down Expand Up @@ -147,12 +162,18 @@ private data class ByteArrayResourceImpl(private val raw: ByteArray) : ByteArray
* 一个可以读取到 [String] 内容物的拓展类型。
* 是其他 [Resource] 类型的附加能力,但不属于一个标准的 [Resource] 类型。
*/
public interface StringReadableResource : Resource {
public interface StringReadableResource : SourceResource {
/**
* 读取此资源的 [String] 内容。
*/
@Throws(Exception::class)
public fun string(): String

override fun data(): ByteArray = string().encodeToByteArray()

override fun source(): Source {
return Buffer().apply { write(data()) }
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,23 @@

package love.forte.simbot.resource

import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.jvm.JvmStatic

/**
* 计划被废弃的与 [Resource] 相关的API
*/
@RequiresOptIn(
message = "计划被废弃的与 `Resource` 相关的API. 详见 " +
"`love.forte.simbot.resource.ResourceResolver` 和 " +
"`love.forte.simbot.resource.Resource` 中的有关说明。"
)
@Retention(BINARY)
@Target(CLASS, FUNCTION)
@MustBeDocumented
public annotation class ScheduledDeprecatedResourceApi

/**
* 使用 [ResourceResolver] 分析处理一个 [Resource].
Expand All @@ -33,8 +48,14 @@ import kotlin.jvm.JvmStatic
*
* 在 JVM 平台会提供一个具有更多能力的类型。
*
* Note: 由于[Resource]现在已经通过 `sealed` 限制了子类型范围,
* 因此可以直接使用 [ByteArrayResource] 或 [SourceResource]。
* 得益于 `kotlinx-io`,明确 resolve 多平台(尤其是JVM平台)下的独特类型的情况已经不多了。
* [ResourceResolver] 可能会在未来废弃, 且现在开始不再建议使用。
*
* @author ForteScarlet
*/
@ScheduledDeprecatedResourceApi
public interface ResourceResolver<C> {
/**
* 处理一个未知的 [Resource] 类型的 resource.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ public annotation class ExperimentalIOResourceAPI
* @since 4.7.0
*/
@JvmName("valueOfPath")
@ExperimentalIOResourceAPI
public fun fileResource(filePath: String): SourceResource {
return Path(filePath).toResource()
}
Expand All @@ -94,7 +93,6 @@ public fun fileResource(filePath: String): SourceResource {
* @since 4.7.0
*/
@JvmName("valueOfPath")
@ExperimentalIOResourceAPI
public fun fileResource(base: String, vararg parts: String): SourceResource {
return Path(base, *parts).toResource()
}
Expand All @@ -110,19 +108,36 @@ public fun fileResource(base: String, vararg parts: String): SourceResource {
* @since 4.8.0
*/
@JvmName("valueOf")
@ExperimentalIOResourceAPI
public fun Path.toResource(): SourceResource {
return FilePathResource(this)
}

/**
* 提供一个用于产生 [Source] 的供应函数 [provider],
* 并得到一个 [SourceResource]。
*
* 得到的结果每次使用 [SourceResource.source] 都会通过 [provider]
* 获取一个 [Source]。[Source] 应当由使用者决定关闭时机,而不是在 [provider] 中。
*
* @since 4.10.0
*/
@JvmName("valueOfSourceProvider")
public fun sourceResource(provider: () -> Source): SourceResource {
return SourceResourceImpl(provider)
}


/**
* 一个可以得到 [kotlinx.io.Source] 的 [Resource]。
*
* 在 JVM 平台中 `Resources` 中会提供更多基于JVM文件系统构建 [SourceResource] 的 API。
*
* @see fileResource
* @see sourceResource
* @see Path.toResource
*
* @since 4.7.0
*/
@ExperimentalIOResourceAPI
public interface SourceResource : Resource {
/**
* 得到一个用于本次数据读取的 [Source].
Expand Down Expand Up @@ -154,7 +169,6 @@ public interface SourceResource : Resource {
override fun data(): ByteArray = source().use { it.readByteArray() }
}

@ExperimentalIOResourceAPI
private data class FilePathResource(val path: Path) : SourceResource {
private val source
get() = SystemFileSystem.source(path)
Expand All @@ -163,3 +177,9 @@ private data class FilePathResource(val path: Path) : SourceResource {
override fun source(): Source = source.buffered()
}

/**
* @since 4.10.0
*/
private data class SourceResourceImpl(val provider: () -> Source) : SourceResource {
override fun source(): Source = provider()
}
Loading

0 comments on commit fdcb4df

Please sign in to comment.