Browse Source

[core] Introduce `Streamable` for simplified multiplatform `asFlow` a… (#2256)

* [core] Introduce `Streamable` for simplified multiplatform `asFlow` and `asStream`. Make `Announcements.asFlow` not suspend.

* Remove `@JvmBlockingBridge` in native
Him188 3 years ago
parent
commit
16609fb1e0

+ 12 - 10
mirai-core-api/compatibility-validation/android/api/android.api

@@ -660,9 +660,7 @@ public final class net/mamoe/mirai/contact/active/ActiveRecord {
 	public final fun getPeriodDays ()I
 }
 
-public abstract interface class net/mamoe/mirai/contact/active/GroupActive {
-	public abstract fun asFlow ()Lkotlinx/coroutines/flow/Flow;
-	public abstract fun asStream ()Ljava/util/stream/Stream;
+public abstract interface class net/mamoe/mirai/contact/active/GroupActive : net/mamoe/mirai/utils/Streamable {
 	public abstract fun getRankTitles ()Ljava/util/Map;
 	public abstract fun getTemperatureTitles ()Ljava/util/Map;
 	public abstract fun isHonorVisible ()Z
@@ -837,19 +835,15 @@ public final class net/mamoe/mirai/contact/announcement/AnnouncementParametersBu
 	public static final fun buildAnnouncementParameters (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/contact/announcement/AnnouncementParameters;
 }
 
-public abstract interface class net/mamoe/mirai/contact/announcement/Announcements {
-	public fun asFlow ()Lkotlinx/coroutines/flow/Flow;
-	public abstract fun asFlow (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public abstract fun asStream ()Ljava/util/stream/Stream;
+public abstract interface class net/mamoe/mirai/contact/announcement/Announcements : net/mamoe/mirai/utils/Streamable {
+	public synthetic fun asFlow (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static synthetic fun asFlow (Lnet/mamoe/mirai/contact/announcement/Announcements;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun delete (Ljava/lang/String;)Z
 	public abstract fun delete (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun get (Ljava/lang/String;)Lnet/mamoe/mirai/contact/announcement/OnlineAnnouncement;
 	public abstract fun get (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun publish (Lnet/mamoe/mirai/contact/announcement/Announcement;)Lnet/mamoe/mirai/contact/announcement/OnlineAnnouncement;
 	public abstract fun publish (Lnet/mamoe/mirai/contact/announcement/Announcement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public fun toList ()Ljava/util/List;
-	public fun toList (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public static synthetic fun toList$suspendImpl (Lnet/mamoe/mirai/contact/announcement/Announcements;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun uploadImage (Lnet/mamoe/mirai/utils/ExternalResource;)Lnet/mamoe/mirai/contact/announcement/AnnouncementImage;
 	public abstract fun uploadImage (Lnet/mamoe/mirai/utils/ExternalResource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 }
@@ -6163,6 +6157,14 @@ public final class net/mamoe/mirai/utils/SingleFileLogger : net/mamoe/mirai/util
 	public fun warning (Ljava/lang/Throwable;)V
 }
 
+public abstract interface class net/mamoe/mirai/utils/Streamable {
+	public abstract fun asFlow ()Lkotlinx/coroutines/flow/Flow;
+	public abstract fun asStream ()Ljava/util/stream/Stream;
+	public fun toList ()Ljava/util/List;
+	public fun toList (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static synthetic fun toList$suspendImpl (Lnet/mamoe/mirai/utils/Streamable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+}
+
 public final class net/mamoe/mirai/utils/Utils {
 	public static final synthetic fun BotConfiguration (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/utils/BotConfiguration;
 	public static final fun debug (Lnet/mamoe/mirai/utils/MiraiLogger;Lkotlin/jvm/functions/Function0;)V

+ 12 - 10
mirai-core-api/compatibility-validation/jvm/api/jvm.api

@@ -660,9 +660,7 @@ public final class net/mamoe/mirai/contact/active/ActiveRecord {
 	public final fun getPeriodDays ()I
 }
 
-public abstract interface class net/mamoe/mirai/contact/active/GroupActive {
-	public abstract fun asFlow ()Lkotlinx/coroutines/flow/Flow;
-	public abstract fun asStream ()Ljava/util/stream/Stream;
+public abstract interface class net/mamoe/mirai/contact/active/GroupActive : net/mamoe/mirai/utils/Streamable {
 	public abstract fun getRankTitles ()Ljava/util/Map;
 	public abstract fun getTemperatureTitles ()Ljava/util/Map;
 	public abstract fun isHonorVisible ()Z
@@ -837,19 +835,15 @@ public final class net/mamoe/mirai/contact/announcement/AnnouncementParametersBu
 	public static final fun buildAnnouncementParameters (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/contact/announcement/AnnouncementParameters;
 }
 
-public abstract interface class net/mamoe/mirai/contact/announcement/Announcements {
-	public fun asFlow ()Lkotlinx/coroutines/flow/Flow;
-	public abstract fun asFlow (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public abstract fun asStream ()Ljava/util/stream/Stream;
+public abstract interface class net/mamoe/mirai/contact/announcement/Announcements : net/mamoe/mirai/utils/Streamable {
+	public synthetic fun asFlow (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static synthetic fun asFlow (Lnet/mamoe/mirai/contact/announcement/Announcements;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun delete (Ljava/lang/String;)Z
 	public abstract fun delete (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun get (Ljava/lang/String;)Lnet/mamoe/mirai/contact/announcement/OnlineAnnouncement;
 	public abstract fun get (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun publish (Lnet/mamoe/mirai/contact/announcement/Announcement;)Lnet/mamoe/mirai/contact/announcement/OnlineAnnouncement;
 	public abstract fun publish (Lnet/mamoe/mirai/contact/announcement/Announcement;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public fun toList ()Ljava/util/List;
-	public fun toList (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public static synthetic fun toList$suspendImpl (Lnet/mamoe/mirai/contact/announcement/Announcements;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public fun uploadImage (Lnet/mamoe/mirai/utils/ExternalResource;)Lnet/mamoe/mirai/contact/announcement/AnnouncementImage;
 	public abstract fun uploadImage (Lnet/mamoe/mirai/utils/ExternalResource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 }
@@ -6159,6 +6153,14 @@ public final class net/mamoe/mirai/utils/StandardCharImageLoginSolver$Companion
 	public final fun createBlocking (Lkotlin/jvm/functions/Function0;Lnet/mamoe/mirai/utils/MiraiLogger;)Lnet/mamoe/mirai/utils/StandardCharImageLoginSolver;
 }
 
+public abstract interface class net/mamoe/mirai/utils/Streamable {
+	public abstract fun asFlow ()Lkotlinx/coroutines/flow/Flow;
+	public abstract fun asStream ()Ljava/util/stream/Stream;
+	public fun toList ()Ljava/util/List;
+	public fun toList (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public static synthetic fun toList$suspendImpl (Lnet/mamoe/mirai/utils/Streamable;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+}
+
 public final class net/mamoe/mirai/utils/Utils {
 	public static final synthetic fun BotConfiguration (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/utils/BotConfiguration;
 	public static final fun debug (Lnet/mamoe/mirai/utils/MiraiLogger;Lkotlin/jvm/functions/Function0;)V

+ 2 - 9
mirai-core-api/src/commonMain/kotlin/contact/active/GroupActive.kt

@@ -11,12 +11,12 @@
 
 package net.mamoe.mirai.contact.active
 
-import kotlinx.coroutines.flow.Flow
 import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
 import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.data.GroupHonorType
 import net.mamoe.mirai.utils.NotStableForInheritance
+import net.mamoe.mirai.utils.Streamable
 import kotlin.jvm.JvmName
 
 /**
@@ -62,7 +62,7 @@ import kotlin.jvm.JvmName
  * @since 2.13
  */
 @NotStableForInheritance
-public expect interface GroupActive {
+public interface GroupActive : Streamable<ActiveRecord> {
 
     /**
      * 是否在群聊中显示荣誉
@@ -133,13 +133,6 @@ public expect interface GroupActive {
      */
     public suspend fun refresh()
 
-    /**
-     * 创建一个能获取该群内所有群活跃度记录的 [Flow]. 在 [Flow] 被使用时才会分页下载 [ActiveRecord].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [ActiveRecord] 和 [Flow] 的[收集][Flow.collect].
-     */
-    public fun asFlow(): Flow<ActiveRecord>
-
     /**
      * 获取活跃度图表数据
      */

+ 21 - 21
mirai-core-api/src/commonMain/kotlin/contact/announcement/Announcements.kt

@@ -7,15 +7,17 @@
  * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
-@file:Suppress("INAPPLICABLE_JVM_NAME")
-
 package net.mamoe.mirai.contact.announcement
 
 import kotlinx.coroutines.flow.Flow
+import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
 import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.contact.PermissionDeniedException
+import net.mamoe.mirai.utils.DeprecatedSinceMirai
 import net.mamoe.mirai.utils.ExternalResource
 import net.mamoe.mirai.utils.NotStableForInheritance
+import net.mamoe.mirai.utils.Streamable
+import kotlin.jvm.JvmName
 
 
 /**
@@ -29,7 +31,7 @@ import net.mamoe.mirai.utils.NotStableForInheritance
  *
  * ### 获取公告列表
  *
- * 通过 [asFlow] 或 [asStream] 可以获取到*惰性*流, 在从流中收集数据时才会请求服务器获取数据. 通常建议在 Kotlin 使用协程的 [asFlow], 在 Java 使用 [asStream].
+ * 通过 [asFlow] 或 `asStream` 可以获取到*惰性*流, 在从流中收集数据时才会请求服务器获取数据. 通常建议在 Kotlin 使用协程的 [asFlow], 在 Java 使用 `asStream`.
  *
  * 若要获取全部公告列表, 可使用 [toList].
  *
@@ -40,24 +42,7 @@ import net.mamoe.mirai.utils.NotStableForInheritance
  * @since 2.7
  */
 @NotStableForInheritance
-public expect interface Announcements {
-    /**
-     * 创建一个能获取该群内所有群公告列表的 [Flow]. 在 [Flow] 被使用时才会分页下载 [OnlineAnnouncement].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [OfflineAnnouncement] 和 [Flow] 的[收集][Flow.collect].
-     */
-    public suspend fun asFlow(): Flow<OnlineAnnouncement>
-
-    /**
-     * 获取所有群公告列表, 将全部 [OnlineAnnouncement] 都下载后再返回.
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取并返回已经成功获取到的 [OfflineAnnouncement] 列表.
-     *
-     * @return 此时刻的群公告只读列表.
-     */
-    public open suspend fun toList(): List<OnlineAnnouncement>
-
-
+public interface Announcements : Streamable<OnlineAnnouncement> {
     /**
      * 删除一条群公告. 需要管理员权限. 使用 [OnlineAnnouncement.delete] 与此方法效果相同.
      *
@@ -69,6 +54,7 @@ public expect interface Announcements {
      *
      * @see OnlineAnnouncement.delete
      */
+    @JvmBlockingBridge
     public suspend fun delete(fid: String): Boolean
 
     /**
@@ -77,6 +63,7 @@ public expect interface Announcements {
      * @return 返回 `null` 表示不存在该 [fid] 的群公告
      * @throws IllegalStateException 当协议异常时抛出
      */
+    @JvmBlockingBridge
     public suspend fun get(fid: String): OnlineAnnouncement?
 
     /**
@@ -85,6 +72,7 @@ public expect interface Announcements {
      * @throws IllegalStateException 当协议异常时抛出
      * @see Announcement.publishTo
      */
+    @JvmBlockingBridge
     public suspend fun publish(announcement: Announcement): OnlineAnnouncement
 
     /**
@@ -93,5 +81,17 @@ public expect interface Announcements {
      * **注意**: 需要由调用方[关闭][ExternalResource.close] [resource].
      * @throws IllegalStateException 当协议异常时抛出
      */
+    @JvmBlockingBridge
     public suspend fun uploadImage(resource: ExternalResource): AnnouncementImage
+
+
+    // no blocking bridge for this method
+    @Suppress("INAPPLICABLE_JVM_NAME")
+    @JvmName("asFlow")
+    @Deprecated(
+        "Kept for binary compatibility. Use non-suspend overload instead.",
+        level = DeprecationLevel.HIDDEN
+    )
+    @DeprecatedSinceMirai(hiddenSince = "2.13")
+    public suspend fun asFlow0(): Flow<OnlineAnnouncement> = asFlow()
 }

+ 41 - 0
mirai-core-api/src/commonMain/kotlin/utils/Streamable.kt

@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019-2022 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/dev/LICENSE
+ */
+
+@file:JvmBlockingBridge
+
+package net.mamoe.mirai.utils
+
+import kotlinx.coroutines.flow.Flow
+import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
+import net.mamoe.mirai.contact.announcement.Announcements
+import net.mamoe.mirai.contact.announcement.OnlineAnnouncement
+
+/**
+ * 表示一个可以创建[数据流][Flow]的对象.
+ *
+ * 实现这个接口的对象可以看做为元素 [T] 的集合.
+ * 例如 [Announcements] 可以看作是 [OnlineAnnouncement] 的集合,
+ * 使用 [Announcements.asFlow] 可以获取到包含所有 [OnlineAnnouncement] 列表的 [Flow]
+ * 在 JVM, 还可以使用 `Announcements.asStream` 可以获取到包含所有 [OnlineAnnouncement] 列表的 `Stream`.
+ *
+ * @since 2.13
+ */
+public expect interface Streamable<T> {
+    /**
+     * 创建一个能获取 [T] 的 [Flow].
+     */
+    public fun asFlow(): Flow<T>
+
+    /**
+     * 获取所有 [T] 列表, 将全部 [T] 都加载后再返回.
+     *
+     * @return 此时刻的 [T] 只读列表.
+     */
+    public open suspend fun toList(): List<T>
+}

+ 0 - 172
mirai-core-api/src/jvmBaseMain/kotlin/contact/active/GroupActive.kt

@@ -1,172 +0,0 @@
-/*
- * Copyright 2019-2022 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/dev/LICENSE
- */
-
-@file:JvmBlockingBridge
-
-package net.mamoe.mirai.contact.active
-
-import kotlinx.coroutines.flow.Flow
-import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
-import net.mamoe.mirai.contact.Group
-import net.mamoe.mirai.contact.Member
-import net.mamoe.mirai.data.GroupHonorType
-import net.mamoe.mirai.utils.JavaFriendlyAPI
-import net.mamoe.mirai.utils.NotStableForInheritance
-import java.util.stream.Stream
-
-/**
- * 表示一个群活跃度管理.
- *
- * ## 获取 [GroupActive] 实例
- *
- * 只可以通过 [Group.active] 获取一个群的活跃度管理, 即 [GroupActive] 实例.
- *
- * ### 头衔设置
- *
- * * 通过 [isHonorVisible] 可以获取和设置一个群的荣誉是否显示,
- * * 通过 [isTitleVisible] 可以获取和设置一个群的头衔是否显示,
- * * 通过 [isTemperatureVisible] 可以获取和设置一个群的活跃度是否显示,
- * * 通过 [rankTitles] 可以获取和设置一个群的等级头衔列表 (PC 端显示),
- * * 通过 [temperatureTitles] 可以获取和设置一个群的活跃度头衔列表 (手机端显示)
- *
- * ### 刷新群成员活跃数据
- *
- * 通过 [refresh] 可以刷新 [Member.active] 中的属性 (不包括 honors 和 temperature)
- *
- * ### 活跃度记录
- *
- * 通过 [asFlow] 或 [asStream] 可以获取群活跃度记录*惰性*流,
- * 在从流中收集数据时才会请求服务器获取数据. 通常建议在 Kotlin 使用协程的 [asFlow], 在 Java 使用 [asStream].
- *
- * 若要获取全部活跃度记录, 可使用 [toList].
- *
- * ### 活跃度图表
- *
- * 通过 [queryChart] 可以获取活跃度图表,
- * 包括
- * * 每日总人数 [ActiveChart.members]
- * * 每日活跃人数 [ActiveChart.actives]
- * * 每日申请人数 [ActiveChart.sentences]
- * * 每日入群人数 [ActiveChart.join]
- * * 每日退群人数 [ActiveChart.exit]
- *
- * 通过 [queryHonorHistory] 可以获取群荣耀历史数据,
- * 包括
- * * 当前荣耀持有者 (龙王,壕礼皇冠, 善财福禄寿) [ActiveHonorList.current]
- * * 群荣耀历史记录 [ActiveHonorList.records]
- *
- * @since 2.13
- */
-@NotStableForInheritance
-public actual interface GroupActive {
-
-    /**
-     * 是否在群聊中显示荣誉
-     * @see MemberActive.honors
-     */
-    public actual val isHonorVisible: Boolean
-
-    /**
-     * 设置是否在群聊中显示荣誉
-     * @see MemberActive.honors
-     */
-    public actual suspend fun setHonorVisible(newValue: Boolean)
-
-    /**
-     * 是否在群聊中显示头衔
-     * @see Member.rankTitle
-     * @see Member.temperatureTitle
-     */
-    public actual val isTitleVisible: Boolean
-
-    /**
-     * 设置是否在群聊中显示头衔。操作成功时会同时刷新等级头衔信息。
-     * @see Member.rankTitle
-     * @see Member.temperatureTitle
-     */
-    public actual suspend fun setTitleVisible(newValue: Boolean)
-
-    /**
-     * 是否在群聊中显示活跃度
-     * @see MemberActive.temperature
-     */
-    public actual val isTemperatureVisible: Boolean
-
-    /**
-     * 设置是否在群聊中显示活跃度。操作成功时会同时刷新等级头衔信息。
-     * @see MemberActive.temperature
-     */
-    public actual suspend fun setTemperatureVisible(newValue: Boolean)
-
-    /**
-     * 等级头衔列表,键是等级,值是头衔
-     *
-     * @see Member.rankTitle
-     */
-    public actual val rankTitles: Map<Int, String>
-
-    /**
-     * 设置等级头衔列表,键是等级,值是头衔。操作成功时会同时刷新等级头衔信息。
-     * @see Member.rankTitle
-     */
-    public actual suspend fun setRankTitles(newValue: Map<Int, String>)
-
-    /**
-     * 活跃度头衔列表,键是等级,值是头衔。操作成功时会同时刷新活跃度头衔信息。
-     * @see Member.temperatureTitle
-     */
-    public actual val temperatureTitles: Map<Int, String>
-
-    /**
-     * 设置活跃度头衔列表,键是等级,值是头衔。操作成功时会同时刷新活跃度头衔信息。
-     * @see Member.temperatureTitle
-     */
-    public actual suspend fun setTemperatureTitles(newValue: Map<Int, String>)
-
-    /**
-     * 刷新 [Member.active] 中的属性 (不包括 [honors][MemberActive.honors] 和 [temperature][MemberActive.temperature])
-     * @see Member.active
-     */
-    public actual suspend fun refresh()
-
-    /**
-     * 创建一个能获取该群内所有群活跃度记录的 [Flow]. 在 [Flow] 被使用时才会分页下载 [ActiveRecord].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [ActiveRecord] 和 [Flow] 的[收集][Flow.collect].
-     */
-    public actual fun asFlow(): Flow<ActiveRecord>
-
-    /**
-     * 创建一个能获取该群内所有群活跃度记录的 [Stream]. 在 [Stream] 被使用时才会分页下载 [ActiveRecord].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [ActiveRecord] 和 [Stream] 的[收集][Stream.collect].
-     *
-     * 实现细节: 为了适合 Java 调用, 实现类似为阻塞式的 [asFlow], 因此不建议在 Kotlin 使用. 在 Kotlin 请使用 [asFlow].
-     */
-    @JavaFriendlyAPI
-    public fun asStream(): Stream<ActiveRecord>
-
-    /**
-     * 获取活跃度图表数据
-     */
-    public actual suspend fun queryChart(): ActiveChart
-
-    /**
-     * 获取群荣耀历史数据, 刷新 [Member.active] 中的 [MemberActive.honors]
-     * @see Member.active
-     */
-    @Suppress("INAPPLICABLE_JVM_NAME")
-    @JvmName("queryHonorHistory")
-    public actual suspend fun queryHonorHistory(type: GroupHonorType): ActiveHonorList
-
-    /**
-     * 获取活跃度排行榜,通常是前五十名
-     */
-    public actual suspend fun queryActiveRank(): List<ActiveRankRecord>
-}

+ 0 - 110
mirai-core-api/src/jvmBaseMain/kotlin/contact/announcement/Announcements.kt

@@ -1,110 +0,0 @@
-/*
- * Copyright 2019-2022 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/dev/LICENSE
- */
-
-@file:JvmBlockingBridge
-@file:Suppress("INAPPLICABLE_JVM_NAME")
-
-package net.mamoe.mirai.contact.announcement
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.toList
-import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
-import net.mamoe.mirai.contact.Group
-import net.mamoe.mirai.contact.PermissionDeniedException
-import net.mamoe.mirai.utils.ExternalResource
-import net.mamoe.mirai.utils.NotStableForInheritance
-import java.util.stream.Stream
-
-
-/**
- * 表示一个群的公告列表 (管理器).
- *
- * ## 获取群公告
- *
- * ### 获取 [Announcements] 实例
- *
- * 只可以通过 [Group.announcements] 获取一个群的公告列表, 即 [Announcements] 实例.
- *
- * ### 获取公告列表
- *
- * 通过 [asFlow] 或 [asStream] 可以获取到*惰性*流, 在从流中收集数据时才会请求服务器获取数据. 通常建议在 Kotlin 使用协程的 [asFlow], 在 Java 使用 [asStream].
- *
- * 若要获取全部公告列表, 可使用 [toList].
- *
- * ## 发布群公告
- *
- * 查看 [Announcement]
- *
- * @since 2.7
- */
-@NotStableForInheritance
-public actual interface Announcements {
-    /**
-     * 创建一个能获取该群内所有群公告列表的 [Flow]. 在 [Flow] 被使用时才会分页下载 [OnlineAnnouncement].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [OfflineAnnouncement] 和 [Flow] 的[收集][Flow.collect].
-     */
-    public actual suspend fun asFlow(): Flow<OnlineAnnouncement>
-
-    /**
-     * 创建一个能获取该群内所有群公告列表的 [Stream]. 在 [Stream] 被使用时才会分页下载 [OnlineAnnouncement].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [OfflineAnnouncement] 和 [Stream] 的[收集][Stream.collect].
-     *
-     * 实现细节: 为了适合 Java 调用, 实现类似为阻塞式的 [asFlow], 因此不建议在 Kotlin 使用. 在 Kotlin 请使用 [asFlow].
-     */
-    public fun asStream(): Stream<OnlineAnnouncement>
-
-    /**
-     * 获取所有群公告列表, 将全部 [OnlineAnnouncement] 都下载后再返回.
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取并返回已经成功获取到的 [OfflineAnnouncement] 列表.
-     *
-     * @return 此时刻的群公告只读列表.
-     */
-    public actual suspend fun toList(): List<OnlineAnnouncement> = asFlow().toList()
-
-
-    /**
-     * 删除一条群公告. 需要管理员权限. 使用 [OnlineAnnouncement.delete] 与此方法效果相同.
-     *
-     * @param fid 公告的 [OnlineAnnouncement.fid]
-     * @return 成功返回 `true`, 群公告不存在时返回 `false`
-     *
-     * @throws PermissionDeniedException 当没有权限时抛出
-     * @throws IllegalStateException 当协议异常时抛出
-     *
-     * @see OnlineAnnouncement.delete
-     */
-    public actual suspend fun delete(fid: String): Boolean
-
-    /**
-     * 获取一条群公告.
-     * @param fid 公告的 [OnlineAnnouncement.fid]
-     * @return 返回 `null` 表示不存在该 [fid] 的群公告
-     * @throws IllegalStateException 当协议异常时抛出
-     */
-    public actual suspend fun get(fid: String): OnlineAnnouncement?
-
-    /**
-     * 在该群发布群公告并获得 [OnlineAnnouncement], 需要管理员权限. 发布公告后群内将会出现 "有新公告" 系统提示.
-     * @throws PermissionDeniedException 当没有权限时抛出
-     * @throws IllegalStateException 当协议异常时抛出
-     * @see Announcement.publishTo
-     */
-    public actual suspend fun publish(announcement: Announcement): OnlineAnnouncement
-
-    /**
-     * 上传资源作为群公告图片. 返回值可用于 [AnnouncementParameters.image].
-     *
-     * **注意**: 需要由调用方[关闭][ExternalResource.close] [resource].
-     * @throws IllegalStateException 当协议异常时抛出
-     */
-    public actual suspend fun uploadImage(resource: ExternalResource): AnnouncementImage
-}

+ 50 - 0
mirai-core-api/src/jvmBaseMain/kotlin/utils/Streamable.kt

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019-2022 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/dev/LICENSE
+ */
+
+@file:JvmBlockingBridge
+
+package net.mamoe.mirai.utils
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.toList
+import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
+import net.mamoe.mirai.contact.announcement.Announcement
+import net.mamoe.mirai.contact.announcement.Announcements
+import java.util.stream.Stream
+
+/**
+ * 表示一个可以创建数据流 [Flow] 和 [Stream] 的对象.
+ *
+ * 实现这个接口的对象可以看做为元素 [T] 的集合.
+ * 例如 [Announcements] 可以看作是 [Announcement] 的集合,
+ * 使用 [Announcements.asFlow] 可以获取到包含所有 [Announcement] 列表的 [Flow],
+ * 使用 [Announcements.asStream] 可以获取到包含所有 [Announcement] 列表的 [Stream].
+ *
+ * @since 2.13
+ */
+public actual interface Streamable<T> {
+    /**
+     * 创建一个能获取 [T] 的 [Flow].
+     */
+    public actual fun asFlow(): Flow<T>
+
+    /**
+     * 创建一个能获取该群内所有 [T] 的 [Stream].
+     *
+     * 实现细节: 为了适合 Java 调用, 实现类似为阻塞式的 [asFlow], 因此不建议在 Kotlin 使用. 在 Kotlin 请使用 [asFlow].
+     */
+    public fun asStream(): Stream<T>
+
+    /**
+     * 获取所有 [T] 列表, 将全部 [T] 都加载后再返回.
+     *
+     * @return 此时刻的 [T] 只读列表.
+     */
+    public actual suspend fun toList(): List<T> = asFlow().toList()
+}

+ 0 - 154
mirai-core-api/src/nativeMain/kotlin/contact/active/GroupActive.kt

@@ -1,154 +0,0 @@
-/*
- * Copyright 2019-2022 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/dev/LICENSE
- */
-
-package net.mamoe.mirai.contact.active
-
-import kotlinx.coroutines.flow.Flow
-import net.mamoe.mirai.contact.Group
-import net.mamoe.mirai.contact.Member
-import net.mamoe.mirai.data.GroupHonorType
-import net.mamoe.mirai.utils.NotStableForInheritance
-
-/**
- * 表示一个群活跃度管理.
- *
- * ## 获取 [GroupActive] 实例
- *
- * 只可以通过 [Group.active] 获取一个群的活跃度管理, 即 [GroupActive] 实例.
- *
- * ### 头衔设置
- *
- * * 通过 [isHonorVisible] 可以获取和设置一个群的荣誉是否显示,
- * * 通过 [isTitleVisible] 可以获取和设置一个群的头衔是否显示,
- * * 通过 [isTemperatureVisible] 可以获取和设置一个群的活跃度是否显示,
- * * 通过 [rankTitles] 可以获取和设置一个群的等级头衔列表 (PC 端显示),
- * * 通过 [temperatureTitles] 可以获取和设置一个群的活跃度头衔列表 (手机端显示)
- *
- * ### 刷新群成员活跃数据
- *
- * 通过 [refresh] 可以刷新 [Member.active] 中的属性 (不包括 honors 和 temperature)
- *
- * ### 活跃度记录
- *
- * 通过 [asFlow] 可以获取群活跃度记录*惰性*流.
- *
- * 若要获取全部活跃度记录, 可使用 [toList].
- *
- * ### 活跃度图表
- *
- * 通过 [queryChart] 可以获取活跃度图表,
- * 包括
- * * 每日总人数 [ActiveChart.members]
- * * 每日活跃人数 [ActiveChart.actives]
- * * 每日申请人数 [ActiveChart.sentences]
- * * 每日入群人数 [ActiveChart.join]
- * * 每日退群人数 [ActiveChart.exit]
- *
- * 通过 [queryHonorHistory] 可以获取群荣耀历史数据,
- * 包括
- * * 当前荣耀持有者 (龙王,壕礼皇冠, 善财福禄寿) [ActiveHonorList.current]
- * * 群荣耀历史记录 [ActiveHonorList.records]
- *
- * @since 2.13
- */
-@NotStableForInheritance
-public actual interface GroupActive {
-
-    /**
-     * 是否在群聊中显示荣誉
-     * @see MemberActive.honors
-     */
-    public actual val isHonorVisible: Boolean
-
-    /**
-     * 设置是否在群聊中显示荣誉
-     * @see MemberActive.honors
-     */
-    public actual suspend fun setHonorVisible(newValue: Boolean)
-
-    /**
-     * 是否在群聊中显示头衔
-     * @see Member.rankTitle
-     * @see Member.temperatureTitle
-     */
-    public actual val isTitleVisible: Boolean
-
-    /**
-     * 设置是否在群聊中显示头衔。操作成功时会同时刷新等级头衔信息。
-     * @see Member.rankTitle
-     * @see Member.temperatureTitle
-     */
-    public actual suspend fun setTitleVisible(newValue: Boolean)
-
-    /**
-     * 是否在群聊中显示活跃度
-     * @see MemberActive.temperature
-     */
-    public actual val isTemperatureVisible: Boolean
-
-    /**
-     * 设置是否在群聊中显示活跃度。操作成功时会同时刷新等级头衔信息。
-     * @see MemberActive.temperature
-     */
-    public actual suspend fun setTemperatureVisible(newValue: Boolean)
-
-    /**
-     * 等级头衔列表,键是等级,值是头衔
-     *
-     * @see Member.rankTitle
-     */
-    public actual val rankTitles: Map<Int, String>
-
-    /**
-     * 设置等级头衔列表,键是等级,值是头衔。操作成功时会同时刷新等级头衔信息。
-     * @see Member.rankTitle
-     */
-    public actual suspend fun setRankTitles(newValue: Map<Int, String>)
-
-    /**
-     * 活跃度头衔列表,键是等级,值是头衔。操作成功时会同时刷新活跃度头衔信息。
-     * @see Member.temperatureTitle
-     */
-    public actual val temperatureTitles: Map<Int, String>
-
-    /**
-     * 设置活跃度头衔列表,键是等级,值是头衔。操作成功时会同时刷新活跃度头衔信息。
-     * @see Member.temperatureTitle
-     */
-    public actual suspend fun setTemperatureTitles(newValue: Map<Int, String>)
-
-    /**
-     * 刷新 [Member.active] 中的属性 (不包括 [honors][MemberActive.honors] 和 [temperature][MemberActive.temperature])
-     * @see Member.active
-     */
-    public actual suspend fun refresh()
-
-    /**
-     * 创建一个能获取该群内所有群活跃度记录的 [Flow]. 在 [Flow] 被使用时才会分页下载 [ActiveRecord].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [ActiveRecord] 和 [Flow] 的[收集][Flow.collect].
-     */
-    public actual fun asFlow(): Flow<ActiveRecord>
-
-    /**
-     * 获取活跃度图表数据
-     */
-    public actual suspend fun queryChart(): ActiveChart
-
-    /**
-     * 获取群荣耀历史数据, 刷新 [Member.active] 中的 [MemberActive.honors]
-     * @see Member.active
-     */
-    public actual suspend fun queryHonorHistory(type: GroupHonorType): ActiveHonorList
-
-    /**
-     * 获取活跃度排行榜,通常是前五十名
-     */
-    public actual suspend fun queryActiveRank(): List<ActiveRankRecord>
-}

+ 0 - 95
mirai-core-api/src/nativeMain/kotlin/contact/announcement/Announcements.kt

@@ -1,95 +0,0 @@
-/*
- * Copyright 2019-2022 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/dev/LICENSE
- */
-
-package net.mamoe.mirai.contact.announcement
-
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.toList
-import net.mamoe.mirai.contact.Group
-import net.mamoe.mirai.contact.PermissionDeniedException
-import net.mamoe.mirai.utils.ExternalResource
-import net.mamoe.mirai.utils.NotStableForInheritance
-
-/**
- * 表示一个群的公告列表 (管理器).
- *
- * ## 获取群公告
- *
- * ### 获取 [Announcements] 实例
- *
- * 只可以通过 [Group.announcements] 获取一个群的公告列表, 即 [Announcements] 实例.
- *
- * ### 获取公告列表
- *
- * 通过 [asFlow] 可以获取到*惰性*流, 在从流中收集数据时才会请求服务器获取数据.
- *
- * 若要获取全部公告列表, 可使用 [toList].
- *
- * ## 发布群公告
- *
- * 查看 [Announcement]
- *
- * @since 2.7
- */
-@NotStableForInheritance
-public actual interface Announcements {
-    /**
-     * 创建一个能获取该群内所有群公告列表的 [Flow]. 在 [Flow] 被使用时才会分页下载 [OnlineAnnouncement].
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取, 不影响已经成功获取的 [OfflineAnnouncement] 和 [Flow] 的[收集][Flow.collect].
-     */
-    public actual suspend fun asFlow(): Flow<OnlineAnnouncement>
-
-    /**
-     * 获取所有群公告列表, 将全部 [OnlineAnnouncement] 都下载后再返回.
-     *
-     * 异常不会抛出, 只会记录到网络日志. 当获取发生异常时将会终止获取并返回已经成功获取到的 [OfflineAnnouncement] 列表.
-     *
-     * @return 此时刻的群公告只读列表.
-     */
-    public actual suspend fun toList(): List<OnlineAnnouncement> = asFlow().toList()
-
-
-    /**
-     * 删除一条群公告. 需要管理员权限. 使用 [OnlineAnnouncement.delete] 与此方法效果相同.
-     *
-     * @param fid 公告的 [OnlineAnnouncement.fid]
-     * @return 成功返回 `true`, 群公告不存在时返回 `false`
-     *
-     * @throws PermissionDeniedException 当没有权限时抛出
-     * @throws IllegalStateException 当协议异常时抛出
-     *
-     * @see OnlineAnnouncement.delete
-     */
-    public actual suspend fun delete(fid: String): Boolean
-
-    /**
-     * 获取一条群公告.
-     * @param fid 公告的 [OnlineAnnouncement.fid]
-     * @return 返回 `null` 表示不存在该 [fid] 的群公告
-     * @throws IllegalStateException 当协议异常时抛出
-     */
-    public actual suspend fun get(fid: String): OnlineAnnouncement?
-
-    /**
-     * 在该群发布群公告并获得 [OnlineAnnouncement], 需要管理员权限. 发布公告后群内将会出现 "有新公告" 系统提示.
-     * @throws PermissionDeniedException 当没有权限时抛出
-     * @throws IllegalStateException 当协议异常时抛出
-     * @see Announcement.publishTo
-     */
-    public actual suspend fun publish(announcement: Announcement): OnlineAnnouncement
-
-    /**
-     * 上传资源作为群公告图片. 返回值可用于 [AnnouncementParameters.image].
-     *
-     * **注意**: 需要由调用方[关闭][ExternalResource.close] [resource].
-     * @throws IllegalStateException 当协议异常时抛出
-     */
-    public actual suspend fun uploadImage(resource: ExternalResource): AnnouncementImage
-}

+ 39 - 0
mirai-core-api/src/nativeMain/kotlin/utils/Streamable.kt

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019-2022 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/dev/LICENSE
+ */
+
+package net.mamoe.mirai.utils
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.toList
+import net.mamoe.mirai.contact.announcement.Announcement
+import net.mamoe.mirai.contact.announcement.Announcements
+
+/**
+ * 表示一个可以创建[数据流][Flow]的对象.
+ *
+ * 实现这个接口的对象可以看做为元素 [T] 的集合.
+ * 例如 [Announcements] 可以看作是 [Announcement] 的集合,
+ * 使用 [Announcements.asFlow] 可以获取到包含所有 [Announcement] 列表的 [Flow]
+ * 在 JVM, 还可以使用 `Announcements.asStream` 可以获取到包含所有 [Announcement] 列表的 `Stream`.
+ *
+ * @since 2.13
+ */
+public actual interface Streamable<T> {
+    /**
+     * 创建一个能获取 [T] 的 [Flow].
+     */
+    public actual fun asFlow(): Flow<T>
+
+    /**
+     * 获取所有 [T] 列表, 将全部 [T] 都加载后再返回.
+     *
+     * @return 此时刻的 [T] 只读列表.
+     */
+    public actual suspend fun toList(): List<T> = asFlow().toList()
+}

+ 1 - 1
mirai-core-mock/src/internal/contact/MockAnnouncementsImpl.kt

@@ -35,7 +35,7 @@ internal class MockAnnouncementsImpl(
 ) : MockAnnouncements {
     val announcements = ConcurrentHashMap<String, OnlineAnnouncement>()
 
-    override suspend fun asFlow(): Flow<OnlineAnnouncement> = announcements.values.asFlow()
+    override fun asFlow(): Flow<OnlineAnnouncement> = announcements.values.asFlow()
 
     override fun asStream(): Stream<OnlineAnnouncement> = announcements.values.toList().stream()
 

+ 1 - 3
mirai-core/src/commonMain/kotlin/contact/announcement/AnnouncementsImpl.kt

@@ -7,8 +7,6 @@
  * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
-@file:Suppress("DEPRECATION")
-
 package net.mamoe.mirai.internal.contact.announcement
 
 import io.ktor.client.request.*
@@ -67,7 +65,7 @@ internal abstract class CommonAnnouncementsImpl(
         }.rightOrNull
     }
 
-    override suspend fun asFlow(): Flow<OnlineAnnouncement> {
+    override fun asFlow(): Flow<OnlineAnnouncement> {
         return flow {
             var i = 1
             while (true) {

+ 1 - 1
mirai-core/src/commonMain/kotlin/network/highway/ChunkedFlowSession.kt

@@ -44,5 +44,5 @@ internal class ChunkedFlowSession<T>(
         }
     }
 
-    internal suspend fun asFlow(): Flow<T> = flow { useAll { emit(it) } } // 'single thread' producer
+    internal fun asFlow(): Flow<T> = flow { useAll { emit(it) } } // 'single thread' producer
 }