Him188 6 yıl önce
ebeveyn
işleme
25b3b2b2be

+ 1 - 0
gradle.properties

@@ -2,6 +2,7 @@
 kotlin.code.style=official
 # config
 mirai_version=0.15.0
+mirai_japt_version=1.0.0
 kotlin.incremental.multiplatform=true
 kotlin.parallel.tasks.in.project=true
 # kotlin

+ 1 - 1
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt

@@ -62,7 +62,7 @@ internal class DefaultLoginSolver : LoginSolver() {
             }
         }
         bot.logger.info("请输入 4 位字母验证码. 若要更换验证码, 请直接回车")
-        return readLine()?.takeUnless { it.isEmpty() || it.length != 4 }.also {
+        return readLine()!!.takeUnless { it.isEmpty() || it.length != 4 }.also {
             bot.logger.info("正在提交[$it]中...")
         }
     }

+ 18 - 0
mirai-demos/mirai-demo-java/build.gradle

@@ -0,0 +1,18 @@
+apply plugin: "java"
+apply plugin: "kotlin"
+
+dependencies {
+    implementation files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
+
+    implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
+    implementation project(":mirai-core-qqandroid")
+    implementation project(":mirai-japt")
+}
+
+tasks.withType(JavaCompile) {
+    options.encoding = "UTF-8"
+}
+
+compileJava.options.encoding = 'UTF-8'
+
+compileTestJava.options.encoding = 'UTF-8'

+ 28 - 0
mirai-demos/mirai-demo-java/src/main/java/demo/BlockingTest.java

@@ -0,0 +1,28 @@
+package demo;
+
+import net.mamoe.mirai.japt.BlockingBot;
+import net.mamoe.mirai.japt.BlockingContacts;
+import net.mamoe.mirai.japt.BlockingQQ;
+import net.mamoe.mirai.japt.Events;
+import net.mamoe.mirai.message.GroupMessage;
+
+class BlockingTest {
+
+    public static void main(String[] args) throws InterruptedException {
+        BlockingBot bot = BlockingBot.newInstance(123456, "");
+
+        bot.login();
+
+        bot.getFriendList().forEach(friend -> {
+            System.out.println(friend.getNick());
+        });
+
+        Events.subscribeAlways(GroupMessage.class, (GroupMessage message) -> {
+            final BlockingQQ sender = BlockingContacts.createBlocking(message.getSender());
+
+            sender.sendMessage("Hello");
+        });
+
+        Thread.sleep(999999999);
+    }
+}

+ 8 - 0
mirai-japt/build.gradle.kts

@@ -13,6 +13,12 @@ val serializationVersion: String by rootProject.ext
 val klockVersion: String by rootProject.ext
 val ktorVersion: String by rootProject.ext
 
+description = "Java helper for Mirai"
+
+@Suppress("PropertyName")
+val mirai_japt_version: String by rootProject.ext
+version = mirai_japt_version
+
 kotlin {
     sourceSets {
         all {
@@ -38,6 +44,8 @@ dependencies {
     api(kotlinx("io", kotlinXIoVersion))
     api(kotlinx("coroutines-io", coroutinesIoVersion))
     api(kotlinx("coroutines-core", coroutinesVersion))
+    api(kotlin("stdlib-jdk7", kotlinVersion))
+    api(kotlin("stdlib-jdk8", kotlinVersion))
 }
 
 tasks.withType<JavaCompile>() {

+ 58 - 5
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingContact.java

@@ -1,34 +1,87 @@
 package net.mamoe.mirai.japt;
 
+import net.mamoe.mirai.Bot;
+import net.mamoe.mirai.contact.Contact;
+import net.mamoe.mirai.contact.Member;
+import net.mamoe.mirai.contact.QQ;
+import net.mamoe.mirai.event.events.BeforeImageUploadEvent;
+import net.mamoe.mirai.event.events.EventCancelledException;
+import net.mamoe.mirai.event.events.ImageUploadEvent;
+import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent;
+import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent;
+import net.mamoe.mirai.message.data.Image;
 import net.mamoe.mirai.message.data.Message;
 import net.mamoe.mirai.message.data.MessageChain;
+import net.mamoe.mirai.utils.ExternalImage;
 import org.jetbrains.annotations.NotNull;
 
+/**
+ * 对 {@link Contact} 的阻塞式包装.
+ */
 @SuppressWarnings("unused")
 public interface BlockingContact {
     /**
-     * 这个联系人所属 [Bot]
+     * 这个联系人所属 {@link Bot}
      */
     @NotNull
     BlockingBot getBot();
 
     /**
-     * 可以是 QQ 号码或者群号码 [GroupId].
+     * 可以是 QQ 号码或者群号码.
+     * <p>
+     * 对于 QQ, {@code uin} 与 {@code id} 是相同的意思.
+     * 对于 Group, {@code groupCode} 与 {@code id} 是相同的意思.
      */
     long getId();
 
     /**
      * 向这个对象发送消息.
+     *
+     * @throws EventCancelledException 当发送消息事件被取消
+     * @throws IllegalStateException   发送群消息时若 [Bot] 被禁言抛出
+     * @see FriendMessageSendEvent 发送好友信息事件, cancellable
+     * @see GroupMessageSendEvent  发送群消息事件. cancellable
      */
-    void sendMessage(@NotNull MessageChain messages);
+    // kotlin bug
+    void sendMessage(@NotNull MessageChain messages) throws EventCancelledException, IllegalStateException;
 
     /**
      * 向这个对象发送消息.
+     *
+     * @throws EventCancelledException 当发送消息事件被取消
+     * @throws IllegalStateException   发送群消息时若 [Bot] 被禁言抛出
+     * @see FriendMessageSendEvent 发送好友信息事件, cancellable
+     * @see GroupMessageSendEvent  发送群消息事件. cancellable
      */
-    void sendMessage(@NotNull String message);
+    void sendMessage(@NotNull String message) throws EventCancelledException, IllegalStateException;
 
     /**
      * 向这个对象发送消息.
+     *
+     * @throws EventCancelledException 当发送消息事件被取消
+     * @throws IllegalStateException   发送群消息时若 [Bot] 被禁言抛出
+     * @see FriendMessageSendEvent 发送好友信息事件, cancellable
+     * @see GroupMessageSendEvent  发送群消息事件. cancellable
      */
-    void sendMessage(@NotNull Message message);
+    void sendMessage(@NotNull Message message) throws EventCancelledException, IllegalStateException;
+
+    /**
+     * 上传一个图片以备发送.
+     * 群图片与好友图片在服务器上是通用的, 在 mirai 目前不通用.
+     *
+     * @throws EventCancelledException 当发送消息事件被取消
+     * @see BeforeImageUploadEvent 图片发送前事件, cancellable
+     * @see ImageUploadEvent 图片发送完成事件
+     */
+    Image uploadImage(@NotNull ExternalImage image) throws EventCancelledException;
+
+    /**
+     * 判断 {@code this} 和 {@code other} 是否是相同的类型, 并且 {@link Contact#getId()} 相同.
+     * <p>
+     * 注:
+     * {@link Contact#getId()} 相同的 {@link Member} 和 {@link QQ}, 他们并不 equals.
+     * 因为, {@link Member} 含义为群员, 必属于一个群.
+     * 而 {@link QQ} 含义为一个独立的人, 可以是好友, 也可以是陌生人.
+     */
+    boolean equals(Object other);
 }

+ 15 - 8
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingContacts.java

@@ -8,24 +8,31 @@ import net.mamoe.mirai.japt.internal.BlockingBotImpl;
 import net.mamoe.mirai.japt.internal.BlockingGroupImpl;
 import net.mamoe.mirai.japt.internal.BlockingMemberImpl;
 import net.mamoe.mirai.japt.internal.BlockingQQImpl;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
 
 /**
  * 构造阻塞式的联系人.
  */
 public final class BlockingContacts {
-    public static BlockingQQ createBlocking(QQ qq) {
-        return new BlockingQQImpl(qq);
+    @NotNull
+    public static BlockingQQ createBlocking(@NotNull QQ qq) {
+        return new BlockingQQImpl(Objects.requireNonNull(qq));
     }
 
-    public static BlockingGroup createBlocking(Group group) {
-        return new BlockingGroupImpl(group);
+    @NotNull
+    public static BlockingGroup createBlocking(@NotNull Group group) {
+        return new BlockingGroupImpl(Objects.requireNonNull(group));
     }
 
-    public static BlockingMember createBlocking(Member member) {
-        return new BlockingMemberImpl(member);
+    @NotNull
+    public static BlockingMember createBlocking(@NotNull Member member) {
+        return new BlockingMemberImpl(Objects.requireNonNull(member));
     }
 
-    public static BlockingBot createBlocking(Bot bot) {
-        return new BlockingBotImpl(bot);
+    @NotNull
+    public static BlockingBot createBlocking(@NotNull Bot bot) {
+        return new BlockingBotImpl(Objects.requireNonNull(bot));
     }
 }

+ 19 - 0
mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingQQ.java

@@ -3,13 +3,30 @@ package net.mamoe.mirai.japt;
 import net.mamoe.mirai.data.FriendNameRemark;
 import net.mamoe.mirai.data.PreviousNameList;
 import net.mamoe.mirai.data.Profile;
+import net.mamoe.mirai.utils.MiraiExperimentalAPI;
 import org.jetbrains.annotations.NotNull;
 
 @SuppressWarnings("unused")
 public interface BlockingQQ extends BlockingContact {
+    /**
+     * 获取 QQ 号码
+     *
+     * @return QQ 号码
+     */
+    @Override
+    long getId();
+
+    /**
+     * 获取昵称
+     *
+     * @return 昵称
+     */
+    String getNick();
+
     /**
      * 查询用户资料
      */
+    @MiraiExperimentalAPI(message = "还未支持")
     @NotNull
     Profile queryProfile();
 
@@ -20,12 +37,14 @@ public interface BlockingQQ extends BlockingContact {
      * - 昵称
      * - 共同群内的群名片
      */
+    @MiraiExperimentalAPI(message = "还未支持")
     @NotNull
     PreviousNameList queryPreviousNameList();
 
     /**
      * 查询机器人账号给这个人设置的备注
      */
+    @MiraiExperimentalAPI(message = "还未支持")
     @NotNull
     FriendNameRemark queryRemark();
 }

+ 28 - 0
mirai-japt/src/main/java/net/mamoe/mirai/japt/Events.java

@@ -20,18 +20,46 @@ import org.jetbrains.annotations.NotNull;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
+/**
+ * 事件处理
+ */
 public final class Events {
 
+    /**
+     * 监听一个事件, 当 {@code onEvent} 返回 {@link ListeningStatus#STOPPED} 时停止监听.
+     * 机器人离线后不会停止监听.
+     *
+     * @param eventClass 事件类
+     * @param onEvent    事件处理. 返回 {@link ListeningStatus#LISTENING} 时继续监听.
+     * @param <E>        事件类型
+     * @return 事件监听器. 可调用 {@link Listener#complete()} 或 {@link Listener#completeExceptionally(Throwable)} 让监听正常停止或异常停止.
+     */
     @NotNull
     public static <E extends Event> Listener<E> subscribe(@NotNull Class<E> eventClass, @NotNull Function<E, ListeningStatus> onEvent) {
         return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
     }
 
+    /**
+     * 监听一个事件, 直到手动停止.
+     * 机器人离线后不会停止监听.
+     *
+     * @param eventClass 事件类
+     * @param onEvent    事件处理. 返回 {@link ListeningStatus#LISTENING} 时继续监听.
+     * @param <E>        事件类型
+     * @return 事件监听器. 可调用 {@link Listener#complete()} 或 {@link Listener#completeExceptionally(Throwable)} 让监听正常停止或异常停止.
+     */
     @NotNull
     public static <E extends Event> Listener<E> subscribeAlways(@NotNull Class<E> eventClass, @NotNull Consumer<E> onEvent) {
         return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
     }
 
+    /**
+     * 阻塞地广播一个事件.
+     *
+     * @param event 事件
+     * @param <E>   事件类型
+     * @return {@code event} 本身
+     */
     @NotNull
     public static <E extends Event> E broadcast(@NotNull E event) {
         return EventsImplKt.broadcast(event);

+ 24 - 3
mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt

@@ -14,34 +14,55 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.readBytes
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.BotAccount
+import net.mamoe.mirai.contact.QQ
 import net.mamoe.mirai.data.AddFriendResult
+import net.mamoe.mirai.data.GroupInfo
+import net.mamoe.mirai.data.MemberInfo
 import net.mamoe.mirai.japt.BlockingBot
 import net.mamoe.mirai.japt.BlockingGroup
 import net.mamoe.mirai.japt.BlockingQQ
 import net.mamoe.mirai.message.data.Image
 import net.mamoe.mirai.network.BotNetworkHandler
+import net.mamoe.mirai.utils.MiraiExperimentalAPI
 import net.mamoe.mirai.utils.MiraiInternalAPI
 import net.mamoe.mirai.utils.MiraiLogger
 import net.mamoe.mirai.utils.toList
+import java.io.OutputStream
+import java.util.stream.Stream
+import kotlin.streams.asStream
 
 internal class BlockingBotImpl(private val bot: Bot) : BlockingBot {
     @MiraiInternalAPI
     override fun getAccount(): BotAccount = bot.account
 
     override fun getUin(): Long = bot.uin
+    @MiraiExperimentalAPI
+    override fun getNick(): String = bot.nick
+
     override fun getLogger(): MiraiLogger = bot.logger
+    override fun getSelfQQ(): QQ = bot.selfQQ
+
+    override fun queryGroupMemberList(groupUin: Long, groupCode: Long, ownerId: Long): Stream<MemberInfo> =
+        runBlocking { bot.queryGroupMemberList(groupUin, groupCode, ownerId) }.asStream()
+
     @UseExperimental(MiraiInternalAPI::class)
-    override fun getQQs(): List<BlockingQQ> = bot.qqs.delegate.toList().map { it.blocking() }
+    override fun getFriendList(): List<BlockingQQ> = bot.qqs.delegate.toList().map { it.blocking() }
+
+    override fun getFriend(id: Long): BlockingQQ = bot.getFriend(id).blocking()
+    override fun queryGroupList(): Stream<Long> = runBlocking { bot.queryGroupList() }.asStream()
 
-    override fun getQQ(id: Long): BlockingQQ = bot.getFriend(id).blocking()
     @UseExperimental(MiraiInternalAPI::class)
-    override fun getGroups(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }
+    override fun getGroupList(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }
+
+    override fun queryGroupInfo(code: Long): GroupInfo = runBlocking { bot.queryGroupInfo(code) }
 
     override fun getGroup(id: Long): BlockingGroup = runBlocking { bot.getGroup(id).blocking() }
     override fun getNetwork(): BotNetworkHandler = bot.network
     override fun login() = runBlocking { bot.login() }
     override fun downloadAsByteArray(image: Image): ByteArray = bot.run { runBlocking { image.download().readBytes() } }
     override fun download(image: Image): ByteReadPacket = bot.run { runBlocking { image.download() } }
+    override fun download(image: Image, outputStream: OutputStream) = bot.run { runBlocking { image.downloadTo(outputStream) } }
+
     override fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult = runBlocking { bot.addFriend(id, message, remark) }
     override fun approveFriendAddRequest(id: Long, remark: String?) = runBlocking { bot.approveFriendAddRequest(id, remark) }
     override fun dispose(throwable: Throwable?) = bot.close(throwable)

+ 0 - 14
mirai-japt/src/test/kotlin/BlockingTest.java

@@ -1,14 +0,0 @@
-public class BlockingTest {
-
-
-    public static void main(String[] args) {
-        //Bot bot = new Bot(new BotAccount(123456, ""), EmptyCoroutineContext.INSTANCE);
-        //if (bot.getNetwork().login() != LoginResult.) {
-        //    throw IllegalStateException("Login failed")
-        //}
-        //bot.getContacts().getGroups();
-
-        //var qq = BlockingContacts.createBlocking(bot.getContacts().getQQ(123L))
-        //println(createBlocking.queryRemark())
-    }
-}

+ 4 - 1
settings.gradle

@@ -21,6 +21,8 @@ pluginManagement {
 
 rootProject.name = 'mirai'
 
+include(':mirai-demos')
+
 try {
     def keyProps = new Properties()
     def keyFile = file("local.properties")
@@ -46,7 +48,7 @@ include(':mirai-console')
 include(':mirai-api-http')
 include(':mirai-demos:mirai-demo-1')
 include(':mirai-demos:mirai-demo-gentleman')
-include(':mirai-demos')
+include(':mirai-demos:mirai-demo-java')
 include(':mirai-plugins')
 include(':mirai-plugins:image-sender')
 
@@ -67,6 +69,7 @@ if (versionPos==-1){
 
 project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1')
 project(':mirai-demos:mirai-demo-gentleman').projectDir = file('mirai-demos/mirai-demo-gentleman')
+project(':mirai-demos:mirai-demo-java').projectDir = file('mirai-demos/mirai-demo-java')
 project(':mirai-plugins:image-sender').projectDir = file('mirai-plugins/image-sender')
 
 enableFeaturePreview('GRADLE_METADATA')