Skip to content

Commit fdcb4df

Browse files
authored
Merge pull request #993 from simple-robot/pref-resurce-io
基于kotlinx-io改善Resource相关API
2 parents 7e2e2b0 + 0d9e287 commit fdcb4df

File tree

15 files changed

+202
-569
lines changed

15 files changed

+202
-569
lines changed

buildSrc/src/main/kotlin/P.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ fun isSnapshot(): Boolean = _isSnapshot
4747
@Suppress("MemberVisibilityCanBePrivate")
4848
sealed class P(override val group: String) : ProjectDetail() {
4949
companion object {
50-
const val VERSION = "4.9.0"
51-
const val NEXT_VERSION = "4.9.1"
50+
const val VERSION = "4.10.0"
51+
const val NEXT_VERSION = "4.10.0"
5252
const val SNAPSHOT_VERSION = "$VERSION-SNAPSHOT"
5353
const val NEXT_SNAPSHOT_VERSION = "$NEXT_VERSION-SNAPSHOT"
5454

simbot-api/api/simbot-api.api

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,11 +2195,15 @@ public abstract interface class love/forte/simbot/message/OfflineImage : love/fo
21952195
public static final field Companion Llove/forte/simbot/message/OfflineImage$Companion;
21962196
public abstract fun data ()[B
21972197
public static fun ofBytes ([B)Llove/forte/simbot/message/OfflineImage;
2198+
public static fun ofFilePath (Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
2199+
public static fun ofFilePath (Ljava/lang/String;[Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
21982200
public static fun ofResource (Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/message/OfflineImage;
21992201
}
22002202

22012203
public final class love/forte/simbot/message/OfflineImage$Companion {
22022204
public final fun ofBytes ([B)Llove/forte/simbot/message/OfflineImage;
2205+
public final fun ofFilePath (Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
2206+
public final fun ofFilePath (Ljava/lang/String;[Ljava/lang/String;)Llove/forte/simbot/message/OfflineImage;
22032207
public final fun ofResource (Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/message/OfflineImage;
22042208
}
22052209

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

2531-
public abstract interface class love/forte/simbot/resource/ByteArrayResource : love/forte/simbot/resource/Resource {
2535+
public abstract interface class love/forte/simbot/resource/ByteArrayResource : love/forte/simbot/resource/Resource, love/forte/simbot/resource/SourceResource {
25322536
public abstract fun data ()[B
2537+
public fun source ()Lkotlinx/io/Source;
25332538
}
25342539

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

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

2548-
public abstract interface class love/forte/simbot/resource/InputStreamResource : love/forte/simbot/resource/Resource {
2549-
public fun data ()[B
2550-
public abstract fun inputStream ()Ljava/io/InputStream;
2553+
public abstract interface class love/forte/simbot/resource/InputStreamResource : love/forte/simbot/resource/SourceResource {
2554+
public fun inputStream ()Ljava/io/InputStream;
25512555
}
25522556

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

2579+
public abstract interface class love/forte/simbot/resource/JvmSourceResource : love/forte/simbot/resource/SourceResource {
2580+
}
2581+
25752582
public abstract interface class love/forte/simbot/resource/JvmStringReadableResource : love/forte/simbot/resource/StringReadableResource {
25762583
public static final field Companion Llove/forte/simbot/resource/JvmStringReadableResource$Companion;
25772584
public static final field DEFAULT_CHARSET Ljava/nio/charset/Charset;
@@ -2582,7 +2589,7 @@ public abstract interface class love/forte/simbot/resource/JvmStringReadableReso
25822589
public final class love/forte/simbot/resource/JvmStringReadableResource$Companion {
25832590
}
25842591

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

26242631
public final class love/forte/simbot/resource/Resources {
2632+
public static final fun inputStream (Llove/forte/simbot/resource/SourceResource;)Ljava/io/InputStream;
26252633
public static final fun valueOf (Ljava/io/File;)Llove/forte/simbot/resource/FileResource;
26262634
public static final fun valueOf (Ljava/io/File;Ljava/nio/charset/Charset;)Llove/forte/simbot/resource/FileResource;
26272635
public static final fun valueOf (Ljava/lang/String;)Llove/forte/simbot/resource/StringResource;
@@ -2631,22 +2639,37 @@ public final class love/forte/simbot/resource/Resources {
26312639
public static final fun valueOf (Ljava/net/URL;Ljava/nio/charset/Charset;)Llove/forte/simbot/resource/URIResource;
26322640
public static final fun valueOf (Ljava/nio/file/Path;Ljava/nio/charset/Charset;[Ljava/nio/file/OpenOption;)Llove/forte/simbot/resource/PathResource;
26332641
public static final fun valueOf (Ljava/nio/file/Path;[Ljava/nio/file/OpenOption;)Llove/forte/simbot/resource/PathResource;
2642+
public static final fun valueOf (Lkotlinx/io/files/Path;)Llove/forte/simbot/resource/SourceResource;
26342643
public static final fun valueOf ([B)Llove/forte/simbot/resource/ByteArrayResource;
26352644
public static synthetic fun valueOf$default (Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/Object;)Llove/forte/simbot/resource/FileResource;
26362645
public static synthetic fun valueOf$default (Ljava/net/URI;Ljava/nio/charset/Charset;ILjava/lang/Object;)Llove/forte/simbot/resource/URIResource;
26372646
public static synthetic fun valueOf$default (Ljava/net/URL;Ljava/nio/charset/Charset;ILjava/lang/Object;)Llove/forte/simbot/resource/URIResource;
26382647
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;
2648+
public static final fun valueOfInputStreamProvider (Lkotlin/jvm/functions/Function0;)Llove/forte/simbot/resource/SourceResource;
2649+
public static final fun valueOfPath (Ljava/lang/String;)Llove/forte/simbot/resource/SourceResource;
2650+
public static final fun valueOfPath (Ljava/lang/String;[Ljava/lang/String;)Llove/forte/simbot/resource/SourceResource;
2651+
public static final fun valueOfSourceProvider (Lkotlin/jvm/functions/Function0;)Llove/forte/simbot/resource/SourceResource;
26392652
}
26402653

2641-
public abstract interface class love/forte/simbot/resource/StringReadableResource : love/forte/simbot/resource/Resource {
2654+
public abstract interface annotation class love/forte/simbot/resource/ScheduledDeprecatedResourceApi : java/lang/annotation/Annotation {
2655+
}
2656+
2657+
public abstract interface class love/forte/simbot/resource/SourceResource : love/forte/simbot/resource/Resource {
2658+
public fun data ()[B
2659+
public abstract fun source ()Lkotlinx/io/Source;
2660+
}
2661+
2662+
public abstract interface class love/forte/simbot/resource/StringReadableResource : love/forte/simbot/resource/SourceResource {
2663+
public fun data ()[B
2664+
public fun source ()Lkotlinx/io/Source;
26422665
public abstract fun string ()Ljava/lang/String;
26432666
}
26442667

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

2649-
public abstract interface class love/forte/simbot/resource/URIResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/JvmStringReadableResource {
2672+
public abstract interface class love/forte/simbot/resource/URIResource : love/forte/simbot/resource/InputStreamResource, love/forte/simbot/resource/JvmSourceResource, love/forte/simbot/resource/JvmStringReadableResource {
26502673
public abstract fun getUri ()Ljava/net/URI;
26512674
public abstract fun inputStream ()Ljava/io/InputStream;
26522675
public fun string ()Ljava/lang/String;

simbot-api/src/commonMain/kotlin/love/forte/simbot/message/OfflineImageResolver.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,8 @@
2323

2424
package love.forte.simbot.message
2525

26-
import love.forte.simbot.resource.ByteArrayResource
27-
import love.forte.simbot.resource.Resource
28-
import love.forte.simbot.resource.ResourceResolver
26+
import love.forte.simbot.resource.*
2927
import love.forte.simbot.resource.ResourceResolver.Companion.resolve
30-
import love.forte.simbot.resource.StringResource
3128
import kotlin.jvm.JvmStatic
3229

3330

@@ -76,6 +73,7 @@ public interface OfflineImageResolver<C> {
7673
* 继承 [OfflineImageResolver] 和 [ResourceResolver],
7774
* 对其中可能出现的实际内容物(例如 [ByteArray] 或 [String])进行处理。
7875
*/
76+
@ScheduledDeprecatedResourceApi
7977
public interface OfflineImageValueResolver<C> :
8078
OfflineImageResolver<C>,
8179
ResourceResolver<C> {

simbot-api/src/commonMain/kotlin/love/forte/simbot/message/StandardMessages.kt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,14 @@ import kotlinx.serialization.SerialName
3030
import kotlinx.serialization.Serializable
3131
import love.forte.simbot.common.id.ID
3232
import love.forte.simbot.common.id.IDContainer
33+
import love.forte.simbot.message.At.Companion.equals
34+
import love.forte.simbot.message.At.Companion.hashCode
3335
import love.forte.simbot.message.OfflineImage.Companion.toOfflineImage
3436
import love.forte.simbot.message.Text.Companion.of
35-
import love.forte.simbot.resource.*
37+
import love.forte.simbot.resource.ByteArrayResource
38+
import love.forte.simbot.resource.Resource
39+
import love.forte.simbot.resource.ResourceBase64Serializer
40+
import love.forte.simbot.resource.fileResource
3641
import kotlin.io.encoding.ExperimentalEncodingApi
3742
import kotlin.js.JsName
3843
import kotlin.jvm.*
@@ -297,12 +302,16 @@ public interface UrlAwareImage : Image, UrlAwareMessage {
297302
*
298303
* “离线”主要表示此图片并未上传到某个目标平台中,也没有与某个远程服务器互相对应的唯一标识。
299304
*
300-
* @see OfflineImage.toOfflineImage
305+
* 离线图片消息由本地构建,不会来自远端服务器或事件内。
306+
* 离线图片消息无法保证可序列化性,尽可能避免对其进行序列化(包括作为 [Messages] 的元素时)。
307+
*
308+
* @see ByteArray.toOfflineImage
309+
* @see Resource.toOfflineImage
301310
*
302311
* @see OfflineByteArrayImage
303-
* @see SimpleOfflineResourceImage
312+
* @see OfflineResourceImage
304313
*/
305-
public interface OfflineImage : Image {
314+
public sealed interface OfflineImage : Image {
306315
/**
307316
* 得到图片的二进制数据
308317
*/
@@ -348,7 +357,6 @@ public interface OfflineImage : Image {
348357
*/
349358
@JvmStatic
350359
@JvmName("ofFilePath")
351-
@ExperimentalIOResourceAPI
352360
public fun fileOfflineImage(filePath: String): OfflineImage =
353361
fileResource(filePath).toOfflineResourceImage()
354362

@@ -363,7 +371,6 @@ public interface OfflineImage : Image {
363371
* @since 4.7.0
364372
*/
365373
@JvmStatic
366-
@ExperimentalIOResourceAPI
367374
@JvmName("ofFilePath")
368375
public fun fileOfflineImage(base: String, vararg parts: String): OfflineImage =
369376
fileResource(base, *parts).toOfflineResourceImage()

simbot-api/src/commonMain/kotlin/love/forte/simbot/resource/Resource.kt

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
package love.forte.simbot.resource
2828

29+
import kotlinx.io.Buffer
30+
import kotlinx.io.Source
2931
import kotlinx.serialization.KSerializer
3032
import kotlinx.serialization.descriptors.PrimitiveKind
3133
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
@@ -46,6 +48,17 @@ import kotlin.jvm.JvmName
4648
* JVM 中的部分扩展、辅助API通过静态类 `Resources` 提供,
4749
* 例如 `Resources.valueOf(...)`。
4850
*
51+
* ## 有限范围
52+
*
53+
* 从 `v4.10.0` 开始,[Resource] 接口转为 `sealed` 并有两个明确的子类型分支:
54+
* - [ByteArrayResource]
55+
* - [SourceResource]
56+
*
57+
* [ByteArrayResource] 代表一个可以**直接**使用 [ByteArray] 进行表示的资源,它也同样可以表示为 [SourceResource]。
58+
*
59+
* 其中,[SourceResource] 借助 `kotlinx-io` 库所提供的能力统一多平台的IO相关API(例如文件系统相关)。
60+
* 如果你想要基于文件系统或其他与IO相关的内容构建一个 [Resource],则参考 [SourceResource]。
61+
*
4962
* ## 序列化
5063
*
5164
* [Resource] 提供了一个基于 [Base64] 进行序列化操作的 [ResourceBase64Serializer]。
@@ -59,9 +72,7 @@ import kotlin.jvm.JvmName
5972
*
6073
* @author ForteScarlet
6174
*/
62-
public interface Resource {
63-
// TODO become `sealed` for ByteArrayResource and SourceResource.
64-
75+
public sealed interface Resource {
6576
/**
6677
* 读取此资源的字节数据。
6778
*
@@ -83,11 +94,15 @@ public fun ByteArray.toResource(): ByteArrayResource = ByteArrayResourceImpl(thi
8394
*
8495
* @author forte
8596
*/
86-
public interface ByteArrayResource : Resource {
97+
public interface ByteArrayResource : Resource, SourceResource {
8798
/**
8899
* 获取到字节数组结果。
89100
*/
90101
override fun data(): ByteArray
102+
103+
override fun source(): Source {
104+
return Buffer().apply { write(data()) }
105+
}
91106
}
92107

93108
/**
@@ -147,12 +162,18 @@ private data class ByteArrayResourceImpl(private val raw: ByteArray) : ByteArray
147162
* 一个可以读取到 [String] 内容物的拓展类型。
148163
* 是其他 [Resource] 类型的附加能力,但不属于一个标准的 [Resource] 类型。
149164
*/
150-
public interface StringReadableResource : Resource {
165+
public interface StringReadableResource : SourceResource {
151166
/**
152167
* 读取此资源的 [String] 内容。
153168
*/
154169
@Throws(Exception::class)
155170
public fun string(): String
171+
172+
override fun data(): ByteArray = string().encodeToByteArray()
173+
174+
override fun source(): Source {
175+
return Buffer().apply { write(data()) }
176+
}
156177
}
157178

158179
/**

simbot-api/src/commonMain/kotlin/love/forte/simbot/resource/ResourceResolver.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,23 @@
2323

2424
package love.forte.simbot.resource
2525

26+
import kotlin.annotation.AnnotationRetention.BINARY
27+
import kotlin.annotation.AnnotationTarget.CLASS
28+
import kotlin.annotation.AnnotationTarget.FUNCTION
2629
import kotlin.jvm.JvmStatic
2730

31+
/**
32+
* 计划被废弃的与 [Resource] 相关的API
33+
*/
34+
@RequiresOptIn(
35+
message = "计划被废弃的与 `Resource` 相关的API. 详见 " +
36+
"`love.forte.simbot.resource.ResourceResolver` 和 " +
37+
"`love.forte.simbot.resource.Resource` 中的有关说明。"
38+
)
39+
@Retention(BINARY)
40+
@Target(CLASS, FUNCTION)
41+
@MustBeDocumented
42+
public annotation class ScheduledDeprecatedResourceApi
2843

2944
/**
3045
* 使用 [ResourceResolver] 分析处理一个 [Resource].
@@ -33,8 +48,14 @@ import kotlin.jvm.JvmStatic
3348
*
3449
* 在 JVM 平台会提供一个具有更多能力的类型。
3550
*
51+
* Note: 由于[Resource]现在已经通过 `sealed` 限制了子类型范围,
52+
* 因此可以直接使用 [ByteArrayResource] 或 [SourceResource]。
53+
* 得益于 `kotlinx-io`,明确 resolve 多平台(尤其是JVM平台)下的独特类型的情况已经不多了。
54+
* [ResourceResolver] 可能会在未来废弃, 且现在开始不再建议使用。
55+
*
3656
* @author ForteScarlet
3757
*/
58+
@ScheduledDeprecatedResourceApi
3859
public interface ResourceResolver<C> {
3960
/**
4061
* 处理一个未知的 [Resource] 类型的 resource.

simbot-api/src/commonMain/kotlin/love/forte/simbot/resource/IOResources.kt renamed to simbot-api/src/commonMain/kotlin/love/forte/simbot/resource/SourceResource.kt

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public annotation class ExperimentalIOResourceAPI
7878
* @since 4.7.0
7979
*/
8080
@JvmName("valueOfPath")
81-
@ExperimentalIOResourceAPI
8281
public fun fileResource(filePath: String): SourceResource {
8382
return Path(filePath).toResource()
8483
}
@@ -94,7 +93,6 @@ public fun fileResource(filePath: String): SourceResource {
9493
* @since 4.7.0
9594
*/
9695
@JvmName("valueOfPath")
97-
@ExperimentalIOResourceAPI
9896
public fun fileResource(base: String, vararg parts: String): SourceResource {
9997
return Path(base, *parts).toResource()
10098
}
@@ -110,19 +108,36 @@ public fun fileResource(base: String, vararg parts: String): SourceResource {
110108
* @since 4.8.0
111109
*/
112110
@JvmName("valueOf")
113-
@ExperimentalIOResourceAPI
114111
public fun Path.toResource(): SourceResource {
115112
return FilePathResource(this)
116113
}
117114

115+
/**
116+
* 提供一个用于产生 [Source] 的供应函数 [provider],
117+
* 并得到一个 [SourceResource]。
118+
*
119+
* 得到的结果每次使用 [SourceResource.source] 都会通过 [provider]
120+
* 获取一个 [Source]。[Source] 应当由使用者决定关闭时机,而不是在 [provider] 中。
121+
*
122+
* @since 4.10.0
123+
*/
124+
@JvmName("valueOfSourceProvider")
125+
public fun sourceResource(provider: () -> Source): SourceResource {
126+
return SourceResourceImpl(provider)
127+
}
128+
129+
118130
/**
119131
* 一个可以得到 [kotlinx.io.Source] 的 [Resource]。
120132
*
133+
* 在 JVM 平台中 `Resources` 中会提供更多基于JVM文件系统构建 [SourceResource] 的 API。
134+
*
121135
* @see fileResource
136+
* @see sourceResource
137+
* @see Path.toResource
122138
*
123139
* @since 4.7.0
124140
*/
125-
@ExperimentalIOResourceAPI
126141
public interface SourceResource : Resource {
127142
/**
128143
* 得到一个用于本次数据读取的 [Source].
@@ -154,7 +169,6 @@ public interface SourceResource : Resource {
154169
override fun data(): ByteArray = source().use { it.readByteArray() }
155170
}
156171

157-
@ExperimentalIOResourceAPI
158172
private data class FilePathResource(val path: Path) : SourceResource {
159173
private val source
160174
get() = SystemFileSystem.source(path)
@@ -163,3 +177,9 @@ private data class FilePathResource(val path: Path) : SourceResource {
163177
override fun source(): Source = source.buffered()
164178
}
165179

180+
/**
181+
* @since 4.10.0
182+
*/
183+
private data class SourceResourceImpl(val provider: () -> Source) : SourceResource {
184+
override fun source(): Source = provider()
185+
}

0 commit comments

Comments
 (0)