diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java index a2a1556c0..81ba8639c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java @@ -2,22 +2,25 @@ package net.mamoe.mirai; import lombok.Getter; import net.mamoe.mirai.event.MiraiEventManager; -import net.mamoe.mirai.event.events.server.ServerDisableEvent; -import net.mamoe.mirai.event.events.server.ServerEnableEvent; +import net.mamoe.mirai.event.events.server.ServerDisabledEvent; +import net.mamoe.mirai.event.events.server.ServerEnabledEvent; import net.mamoe.mirai.network.packet.login.LoginState; import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.MiraiLogger; import net.mamoe.mirai.utils.config.MiraiConfig; import net.mamoe.mirai.utils.config.MiraiConfigSection; -import net.mamoe.mirai.utils.setting.MiraiSetting; import net.mamoe.mirai.utils.setting.MiraiSettingListSection; import net.mamoe.mirai.utils.setting.MiraiSettingMapSection; +import net.mamoe.mirai.utils.setting.MiraiSettings; import java.io.File; import java.io.IOException; import java.util.Scanner; +/** + * @author NaturalHG + */ public class MiraiServer { private static MiraiServer instance; @@ -25,10 +28,8 @@ public class MiraiServer { return instance; } - //mirai version private final static String MIRAI_VERSION = "1.0.0"; - //qq version private final static String QQ_VERSION = "4.9.0"; @@ -46,30 +47,30 @@ public class MiraiServer { @Getter MiraiLogger logger; - MiraiSetting setting; + MiraiSettings settings; MiraiConfig qqs; - protected MiraiServer() { + MiraiServer() { instance = this; - this.onLoad(); - this.onEnable(); + this.onLoaded(); + this.onEnabled(); } private boolean enabled; - protected void shutdown() { + void shutdown() { if (this.enabled) { getLogger().info("About to shutdown Mirai"); - this.getEventManager().broadcastEvent(new ServerDisableEvent()); + this.eventManager.broadcastEventAsync(new ServerDisabledEvent()); getLogger().info("Data have been saved"); } } - private void onLoad() { + private void onLoaded() { this.parentFolder = new File(System.getProperty("user.dir")); this.unix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS"); @@ -86,7 +87,7 @@ public class MiraiServer { if (!setting.exists()) { this.initSetting(setting); } else { - this.setting = new MiraiSetting(setting); + this.settings = new MiraiSettings(setting); } File qqs = new File(this.parentFolder + "/QQ.yml"); @@ -114,27 +115,6 @@ public class MiraiServer { }); */ - getLogger().info("ready to connect"); - - - this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { - try { - Robot robot = new Robot(section); - robot.network.tryLogin$mirai_core((robot1, state) -> { - if (state == LoginState.SUCCEED) { - Robot.instances.add(robot); - } else { - robot.close(); - } - return null; - }); - - } catch (Throwable e) { - e.printStackTrace(); - getLogger().error("Could not load QQ robots config!"); - System.exit(1); - } - }); } private void initSetting(File setting) { @@ -147,21 +127,21 @@ public class MiraiServer { } catch (IOException e) { e.printStackTrace(); } - this.setting = new MiraiSetting(setting); - MiraiSettingMapSection network = this.setting.getMapSection("network"); + this.settings = new MiraiSettings(setting); + MiraiSettingMapSection network = this.settings.getMapSection("network"); network.set("enable_proxy", "not supporting yet"); - MiraiSettingListSection proxy = this.setting.getListSection("proxy"); + MiraiSettingListSection proxy = this.settings.getListSection("proxy"); proxy.add("1.2.3.4:95"); proxy.add("1.2.3.4:100"); - MiraiSettingMapSection worker = this.setting.getMapSection("worker"); + MiraiSettingMapSection worker = this.settings.getMapSection("worker"); worker.set("core_task_pool_worker_amount", 5); - MiraiSettingMapSection plugin = this.setting.getMapSection("plugin"); + MiraiSettingMapSection plugin = this.settings.getMapSection("plugin"); plugin.set("debug", false); - this.setting.save(); + this.settings.save(); getLogger().info("initialized; changing can be made in setting file: " + setting.toString()); } @@ -187,11 +167,35 @@ public class MiraiServer { getLogger().info("QQ account initialized; changing can be made in Config file: " + qqConfig.toString()); } - private void onEnable() { - this.eventManager.broadcastEvent(new ServerEnableEvent()); + private void onEnabled() { this.enabled = true; + this.eventManager.broadcastEventAsync(new ServerEnabledEvent()); getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai"); getLogger().info("Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION); + + getLogger().info("Initializing [Robot]s"); + + this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { + getLogger().info("Initializing [Robot] " + section.getString("account")); + try { + Robot robot = new Robot(section); + var state = robot.network.tryLogin$mirai_core().get(); + //robot.network.tryLogin$mirai_core().whenComplete((state, e) -> { + if (state == LoginState.SUCCEED) { + Robot.instances.add(robot); + getLogger().info(" Succeed"); + } else { + getLogger().error(" Failed with error " + state); + robot.close(); + } + // }).get(); + + } catch (Throwable e) { + e.printStackTrace(); + getLogger().error("Could not load QQ robots config!"); + System.exit(1); + } + }); } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java index 7d25a04f0..d4e711deb 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java @@ -13,6 +13,21 @@ import java.io.Closeable; import java.util.*; /** + * Mirai 的机器人. 一个机器人实例登录一个 QQ 账号. + * Mirai 为多账号设计, 可同时维护多个机器人账号. + *
+ * {@link Robot} 由 2 个模块组成. + * {@linkplain ContactSystem 联系人管理}: 可通过 {@link Robot#contacts} 访问 + * {@linkplain RobotNetworkHandler 网络处理器}: 可通过 {@link Robot#network} 访问 + *
+ * 另外地, 若你需要得到机器人的 QQ 账号, 请访问 {@link Robot#account} + * 若你需要得到服务器上所有机器人列表, 请访问 {@link Robot#instances} + * + * @author Him188moe + * @author NatrualHG + * @see net.mamoe.mirai.contact.Contact + * + *

* Robot that is the base of the whole program. * It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}. */ diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt index 2b8fb792d..af009045e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt @@ -5,8 +5,11 @@ import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.defaults.At /** + * QQ 账号. + * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Robot]. + * * A QQ instance helps you to receive message from or send message to. - * Notice that one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same. + * Notice that, one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same. * * @author Him188moe */ @@ -21,6 +24,8 @@ class QQ(robot: Robot, number: Long) : Contact(robot, number) { /** * At(@) this account. + * + * @return an instance of [Message]. */ fun at(): At { return At(this) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java new file mode 100644 index 000000000..583f0dc2a --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java @@ -0,0 +1,27 @@ +package net.mamoe.mirai.event; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * 实现这个接口的事件可以被异步执行或阻塞执行 + * + * @author Him188moe + * @see AsyncEventKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 + */ +public interface AsyncEvent { + + default CompletableFuture broadcastAsync() { + return MiraiEventManager.getInstance().broadcastEventAsync(this); + } + + @SuppressWarnings("unchecked") + default CompletableFuture broadcastEventAsync(Consumer callback) { + return MiraiEventManager.getInstance().broadcastEventAsync((E) this, callback); + } + + @SuppressWarnings("unchecked") + default CompletableFuture broadcastEventAsync(Runnable callback) { + return MiraiEventManager.getInstance().broadcastEventAsync((E) this, callback); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt new file mode 100644 index 000000000..32490d42a --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt @@ -0,0 +1,14 @@ +@file:JvmName("AsyncEventKt") + +package net.mamoe.mirai.event + +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer + +fun E.broadcastAsync(callback: Consumer): CompletableFuture { + return MiraiEventManager.getInstance().broadcastEventAsync(this, callback) +} + +fun E.broadcastAsync(callback: Runnable): CompletableFuture { + return MiraiEventManager.getInstance().broadcastEventAsync(this, callback) +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/Cancellable.java b/mirai-core/src/main/java/net/mamoe/mirai/event/Cancellable.java similarity index 79% rename from mirai-core/src/main/java/net/mamoe/mirai/event/events/Cancellable.java rename to mirai-core/src/main/java/net/mamoe/mirai/event/Cancellable.java index 59167fda0..e12d0cb9b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/Cancellable.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/Cancellable.java @@ -1,4 +1,4 @@ -package net.mamoe.mirai.event.events; +package net.mamoe.mirai.event; /** * @author NaturalHG diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java new file mode 100644 index 000000000..efa532ff0 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java @@ -0,0 +1,35 @@ +package net.mamoe.mirai.event; + +import net.mamoe.mirai.utils.EventException; + +/** + * @author NatrualHG + * @see AsyncEvent + */ +public abstract class MiraiEvent { + + private boolean cancelled; + + public boolean isCancelled() { + if (!(this instanceof Cancellable)) { + return false; + } + return this.cancelled; + } + + public void cancel() { + cancel(true); + } + + public void cancel(boolean value) { + if (!(this instanceof Cancellable)) { + throw new EventException("Event is not Cancellable"); + } + this.cancelled = value; + } + + public final MiraiEvent broadcast() { + MiraiEventManager.getInstance().broadcastEvent(this); + return this; + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java index c8088be6e..d46deb7d8 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java @@ -2,20 +2,21 @@ package net.mamoe.mirai.event; import lombok.Getter; import lombok.Setter; -import net.mamoe.mirai.event.events.Cancellable; -import net.mamoe.mirai.event.events.MiraiEvent; import java.io.Closeable; import java.util.function.Consumer; import java.util.function.Predicate; +/** + * @author NatrualHG + */ public class MiraiEventHook implements Closeable { @Getter Class eventClass; @Getter - private volatile Consumer handler; + protected volatile Consumer handler; @Getter private volatile int priority = 0; @@ -31,7 +32,7 @@ public class MiraiEventHook implements Closeable { * return true -> this hook need to be removed */ @Getter - private Predicate valid; + protected Predicate validChecker; public MiraiEventHook(Class eventClass) { this(eventClass,null); @@ -58,26 +59,26 @@ public class MiraiEventHook implements Closeable { } - private MiraiEventHook setValid(Predicate valid) { - this.valid = valid; + private MiraiEventHook setValidChecker(Predicate validChecker) { + this.validChecker = validChecker; return this; } public MiraiEventHook setValidUntil(Predicate valid) { - return this.setValid(valid); + return this.setValidChecker(valid); } public MiraiEventHook setValidWhile(Predicate valid) { - return this.setValid(valid.negate()); + return this.setValidChecker(valid.negate()); } @SuppressWarnings("unchecked") public boolean accept(MiraiEvent event) { if(!(event instanceof Cancellable && event.isCancelled() && this.isIgnoreCancelled())){ - this.getHandler().accept((T) event); + this.getHandler().accept((T) event); } - return this.valid == null || this.valid.test((T) event); + return this.validChecker == null || this.validChecker.test((T) event); } /** @@ -103,6 +104,6 @@ public class MiraiEventHook implements Closeable { @Override public void close(){ this.handler = null; - this.valid = null; + this.validChecker = null; } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt new file mode 100644 index 000000000..4a072a2be --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt @@ -0,0 +1,31 @@ +package net.mamoe.mirai.event + +import java.util.function.Consumer +import java.util.function.Predicate + +/** + * @author Him188moe + */ +class MiraiEventHookKt(eventClass: Class) : MiraiEventHook(eventClass) { + fun onEvent(handler: (E) -> Unit) { + this@MiraiEventHookKt.handler = Consumer(handler) + } + + fun validChecker(predicate: (E) -> Boolean) { + this@MiraiEventHookKt.validChecker = Predicate(predicate) + } +} + + +/** + * Kotlin 风格回调 + * 你的代码可以这样(并且 validChecker 是可选的): + * + * event.hook { + * onEvent {} + * validChecker {} + * } + */ +fun E.hook(handler: MiraiEventHookKt.() -> Unit): MiraiEventHookKt { + return MiraiEventHookKt(this.javaClass).apply(handler) +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt new file mode 100644 index 000000000..d4441bb62 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt @@ -0,0 +1,8 @@ +@file:JvmName("MiraiEventKt") + +package net.mamoe.mirai.event + +fun E.broadcast(): E { + MiraiEventManager.getInstance().broadcastEvent(this as MiraiEvent) + return this +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java index d93ba6684..90622b1e2 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java @@ -1,21 +1,25 @@ package net.mamoe.mirai.event; -import net.mamoe.mirai.MiraiServer; -import net.mamoe.mirai.event.events.MiraiEvent; - import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; +/** + * 线程安全的事件管理器. + * + * @author NaturalHG + * @see MiraiEventManagerKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 + */ public class MiraiEventManager { MiraiEventManager() { } public static MiraiEventManager getInstance() { - return EventManager.INSTANCE; + return EventManager.INSTANCE;//实例来自 kotlin 的 singleton } private final ReentrantReadWriteLock hooksLock = new ReentrantReadWriteLock(); @@ -115,23 +119,40 @@ public class MiraiEventManager { } - public void asyncBroadcastEvent(MiraiEvent event) { - this.asyncBroadcastEvent(event, a -> { - }); - } + public CompletableFuture broadcastEventAsync(E event) { + Objects.requireNonNull(event); + if (!(event instanceof MiraiEvent)) { + throw new IllegalArgumentException("event must be instanceof MiraiEvent"); + } - public void asyncBroadcastEvent(D event, Consumer callback) { - MiraiServer.getInstance().getTaskManager().ansycTask(() -> { - MiraiEventManager.this.broadcastEvent(event); + CompletableFuture future = new CompletableFuture<>(); + future.completeAsync(() -> { + MiraiEventManager.this.broadcastEvent((MiraiEvent) event); return event; - }, callback); + }); + return future; + } + + public CompletableFuture broadcastEventAsync(E event, Consumer callback) { + Objects.requireNonNull(event); + Objects.requireNonNull(callback); + if (!(event instanceof MiraiEvent)) { + throw new IllegalArgumentException("event must be instanceof MiraiEvent"); + } + + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((a, b) -> callback.accept(event)); + future.completeAsync(() -> { + MiraiEventManager.this.broadcastEvent((MiraiEvent) event); + return event; + }); + return future; } - public void asyncBroadcastEvent(D event, Runnable callback) { - asyncBroadcastEvent(event, t -> callback.run()); + public CompletableFuture broadcastEventAsync(D event, Runnable callback) { + return broadcastEventAsync(event, t -> callback.run()); } - } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt similarity index 63% rename from mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt rename to mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt index 42e6765f0..e3cd769a1 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt @@ -1,33 +1,59 @@ +@file:JvmName("MiraiEventManagerKt") + package net.mamoe.mirai.event -import net.mamoe.mirai.event.events.MiraiEvent import kotlin.reflect.KClass -object EventManager : MiraiEventManager() -typealias MiraiEventManagerKt = EventManager -typealias EventMgr = EventManager +/** + * [MiraiEventManager] 的 kotlin 简易化实现. + * 若要 hook 一个事件, 你可以: + * FriendMessageEvent::class.hookOnce {} + * FriendMessageEvent::class.hookAlways {} + * + * @author Him188moe + */ +object EventManager : MiraiEventManager() + +/** + * 每次事件触发时都会调用 hook + */ fun , E : MiraiEvent> C.hookAlways(hook: (E) -> Unit) { MiraiEventManager.getInstance().hookAlways(MiraiEventHook(this, hook)) } +/** + * 当下一次事件触发时调用 hook + */ fun , E : MiraiEvent> C.hookOnce(hook: (E) -> Unit) { MiraiEventManager.getInstance().hookOnce(MiraiEventHook(this, hook)) } +/** + * 每次事件触发时都会调用 hook, 直到 hook 返回 false 时停止 hook + */ fun , E : MiraiEvent> C.hookWhile(hook: (E) -> Boolean) { - MiraiEventManager.getInstance().hookAlways(MiraiEventHookSimple(this, hook)) + MiraiEventManager.getInstance().hookAlways(MiraiEventHookSimple(this, hook)) } +/** + * 每次事件触发时都会调用 hook + */ fun , E : MiraiEvent> C.hookAlways(hook: (E) -> Unit) { this.java.hookAlways(hook) } +/** + * 当下一次事件触发时调用 hook + */ fun , E : MiraiEvent> C.hookOnce(hook: (E) -> Unit) { this.java.hookOnce(hook) } +/** + * 每次事件触发时都会调用 hook, 直到 hook 返回 false 时停止 hook + */ fun , E : MiraiEvent> C.hookWhile(hook: (E) -> Boolean) { this.java.hookWhile(hook) } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java deleted file mode 100644 index a8509e7f3..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.mamoe.mirai.event.events; - -import net.mamoe.mirai.event.MiraiEventManager; -import net.mamoe.mirai.utils.EventException; - -import java.util.function.Consumer; - -public abstract class MiraiEvent { - - private boolean cancelled; - - public boolean isCancelled() { - if (!(this instanceof Cancellable)) { - return false; - } - return this.cancelled; - } - - public void cancel() { - cancel(true); - } - - public void cancel(boolean value) { - if (!(this instanceof Cancellable)) { - throw new EventException("Event is not Cancellable"); - } - this.cancelled = value; - } - - protected String eventName; - - public String getEventName() { - if (this.eventName == null) { - return this.getClass().getSimpleName(); - } - return this.eventName; - } - - public final MiraiEvent broadcast() { - MiraiEventManager.getInstance().broadcastEvent(this); - return this; - } - - @SuppressWarnings("unchecked") - public final void asyncBroadcast(Consumer callback) { - MiraiEventManager.getInstance().asyncBroadcastEvent((D) this, callback); - } - - @SuppressWarnings("unchecked") - public final void asyncBroadcast(Runnable callback) { - MiraiEventManager.getInstance().asyncBroadcastEvent((D) this, callback); - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java new file mode 100644 index 000000000..2996d08ee --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java @@ -0,0 +1,14 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.event.Cancellable; +import net.mamoe.mirai.network.packet.ClientPacket; +import org.jetbrains.annotations.NotNull; + +/** + * @author Him188moe + */ +public final class BeforePacketSendEvent extends ClientPacketEvent implements Cancellable { + public BeforePacketSendEvent(@NotNull ClientPacket packet) { + super(packet); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java new file mode 100644 index 000000000..e25920e95 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java @@ -0,0 +1,18 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.network.packet.ClientPacket; +import org.jetbrains.annotations.NotNull; + +/** + * @author Him188moe + */ +public abstract class ClientPacketEvent extends PacketEvent { + public ClientPacketEvent(@NotNull ClientPacket packet) { + super(packet); + } + + @Override + public ClientPacket getPacket() { + return (ClientPacket) super.getPacket(); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java index 119f87933..08d4b6a79 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java @@ -1,7 +1,10 @@ package net.mamoe.mirai.event.events.network; -import net.mamoe.mirai.event.events.MiraiEvent; +import net.mamoe.mirai.event.MiraiEvent; import net.mamoe.mirai.network.packet.Packet; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; /** * @author Him188moe @@ -9,8 +12,8 @@ import net.mamoe.mirai.network.packet.Packet; public abstract class PacketEvent extends MiraiEvent { private final Packet packet; - public PacketEvent(Packet packet) { - this.packet = packet; + public PacketEvent(@NotNull Packet packet) { + this.packet = Objects.requireNonNull(packet); } public Packet getPacket() { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java deleted file mode 100644 index 77b697050..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.mamoe.mirai.event.events.network; - -/** - * @author Him188moe - */ -public class PacketReceivedEvent { -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java index 77fa219ea..79a302b46 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java @@ -1,12 +1,16 @@ package net.mamoe.mirai.event.events.network; -import net.mamoe.mirai.event.events.Cancellable; +import net.mamoe.mirai.event.Cancellable; import net.mamoe.mirai.network.packet.ServerPacket; +import net.mamoe.mirai.network.packet.ServerVerificationCodePacket; /** + * 服务器接到某数据包时触发这个事件. + * 注意, 当接收到数据包的加密包(如 {@link ServerVerificationCodePacket.Encrypted})也会触发这个事件, 随后才会 + * * @author Him188moe */ -public class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable { +public final class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable { public ServerPacketReceivedEvent(ServerPacket packet) { super(packet); } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java index ab410af4a..70d85ed78 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java @@ -1,7 +1,7 @@ package net.mamoe.mirai.event.events.robot; import net.mamoe.mirai.Robot; -import net.mamoe.mirai.event.events.MiraiEvent; +import net.mamoe.mirai.event.MiraiEvent; import org.jetbrains.annotations.NotNull; import java.util.Objects; diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt index 737c47d58..9b452b1fd 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt @@ -1,7 +1,7 @@ package net.mamoe.mirai.event.events.robot import net.mamoe.mirai.Robot -import net.mamoe.mirai.event.events.MiraiEvent +import net.mamoe.mirai.event.MiraiEvent /** * @author Him188moe @@ -16,4 +16,3 @@ class RobotMessageReceivedEvent(val robot: Robot, val type: Type, val message: S GROUP } } - diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java index 15151ea91..a49d5f213 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java @@ -7,5 +7,4 @@ public final class RobotLoginSucceedEvent extends RobotEvent { public RobotLoginSucceedEvent(Robot robot) { super(robot); } - } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java deleted file mode 100644 index dd0be1c57..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.mamoe.mirai.event.events.server; - -import net.mamoe.mirai.event.events.MiraiEvent; - -public final class ServerDisableEvent extends MiraiEvent { - -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java new file mode 100644 index 000000000..294498f1d --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java @@ -0,0 +1,8 @@ +package net.mamoe.mirai.event.events.server; + +import net.mamoe.mirai.event.AsyncEvent; +import net.mamoe.mirai.event.MiraiEvent; + +public final class ServerDisabledEvent extends MiraiEvent implements AsyncEvent { + +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java deleted file mode 100644 index 18aeefccf..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.mamoe.mirai.event.events.server; - -import net.mamoe.mirai.event.events.MiraiEvent; - -public final class ServerEnableEvent extends MiraiEvent { - - -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java new file mode 100644 index 000000000..83b4772b9 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java @@ -0,0 +1,9 @@ +package net.mamoe.mirai.event.events.server; + +import net.mamoe.mirai.event.AsyncEvent; +import net.mamoe.mirai.event.MiraiEvent; + +public final class ServerEnabledEvent extends MiraiEvent implements AsyncEvent { + + +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java index e56f328b6..16954515c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java @@ -1,7 +1,9 @@ package net.mamoe.mirai.message; +import net.mamoe.mirai.contact.Contact; import net.mamoe.mirai.contact.QQ; import net.mamoe.mirai.message.defaults.At; +import net.mamoe.mirai.message.defaults.Image; import net.mamoe.mirai.message.defaults.MessageChain; import net.mamoe.mirai.message.defaults.PlainText; import org.jetbrains.annotations.NotNull; @@ -11,7 +13,12 @@ import java.io.File; import java.util.Objects; /** + * 可发送的或从服务器接收的消息. + * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 {@linkplain PlainText 纯文本}, {@linkplain Image 图片} 等. + * * @author Him188moe + * @see Contact#sendMessage(Message) 发送这个消息 + * @see MessageKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 */ public abstract class Message { @Override @@ -38,7 +45,7 @@ public abstract class Message { return new MessageChain(this, Objects.requireNonNull(tail)); } - public Message concat(String tail) { + public final Message concat(String tail) { return concat(new PlainText(tail)); } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt index 6ae5be4b9..0257cbf57 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt @@ -1,3 +1,5 @@ +@file:JvmName("MessageKt") + package net.mamoe.mirai.message import net.mamoe.mirai.message.defaults.PlainText @@ -12,4 +14,7 @@ infix operator fun Message.plus(another: Message): Message = this.concat(another */ infix operator fun Message.plus(another: String): Message = this.concat(another) +/** + * 连接 [String] 与 [Message] + */ infix fun String.concat(another: Message): Message = PlainText(this).concat(another) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java index d552e53c4..dbae4f45a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java @@ -7,6 +7,8 @@ import org.jetbrains.annotations.NotNull; import java.util.Objects; /** + * At 一个人的消息. + * * @author Him188moe */ public final class At extends Message { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 22081cc11..52f5e056b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -1,3 +1,5 @@ +@file:JvmMultifileClass +@file:JvmName("RobotNetworkHandler") package net.mamoe.mirai.network import net.mamoe.mirai.Robot @@ -8,6 +10,7 @@ import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent import net.mamoe.mirai.event.hookWhile import net.mamoe.mirai.message.Message +import net.mamoe.mirai.network.RobotNetworkHandler.* import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket @@ -19,17 +22,33 @@ import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress import java.util.* +import java.util.concurrent.CompletableFuture import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException import kotlin.reflect.KClass + /** + * Mirai 的网络处理器, 它处理所有数据包([Packet])的发送和接收. + * [RobotNetworkHandler] 是全程异步和线程安全的. + * + * [RobotNetworkHandler] 由 2 个模块构成: + * - [SocketHandler]: 处理数据包底层的发送([ByteArray]) + * - [PacketHandler]: 制作 [Packet] 并传递给 [SocketHandler] 继续处理; 分析来自服务器的数据包并处理 + * + * 其中, [PacketHandler] 由 4 个子模块构成: + * - [DebugHandler] 输出 [Packet.toString] + * - [LoginHandler] 处理 touch/login/verification code 相关 + * - [MessageHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket]) + * - [ActionHandler] 处理动作相关(踢人/加入群/好友列表等) + * * A RobotNetworkHandler is used to connect with Tencent servers. * * @author Him188moe */ @Suppress("EXPERIMENTAL_API_USAGE")//to simplify code -internal class RobotNetworkHandler(private val robot: Robot) : Closeable { +class RobotNetworkHandler(private val robot: Robot) : Closeable { private val socketHandler: SocketHandler = SocketHandler() val debugHandler = DebugHandler() @@ -44,9 +63,6 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ActionHandler::class to actionHandler ) - private var closed: Boolean = false - - /** * Not async */ @@ -65,30 +81,49 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { //private | internal + internal fun tryLogin(): CompletableFuture = this.tryLogin(500, TimeUnit.MILLISECONDS) + + /** * 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook]. * 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCEED] 调用 [loginHandler] + * + * @param connectingTimeout 连接每个服务器的 timeout */ - internal fun tryLogin(loginHook: (Robot.(LoginState) -> Unit)? = null) { + internal fun tryLogin(connectingTimeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS): CompletableFuture { val ipQueue: LinkedList = LinkedList(Protocol.SERVER_IP) - fun login(): Boolean { + val future = CompletableFuture() + + fun login() { val ip = ipQueue.poll() - return if (ip != null) { - this@RobotNetworkHandler.socketHandler.touch(ip) { state -> - if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) { - login() - } else { - if (loginHook != null) { - robot.loginHook(state) + if (ip != null) { + // val future = this@RobotNetworkHandler.socketHandler.touch(ip) + + this@RobotNetworkHandler.socketHandler.touch(ip).runCatching { + this@runCatching.get(connectingTimeout, unit).let { state -> + if (state == LoginState.UNKNOWN) { + login() + } else { + future.complete(state) } } + }.onFailure { + when (it) { + is TimeoutException -> login() + else -> throw it + } } - true - } else false + } else { + future.complete(LoginState.UNKNOWN)//所有服务器均返回 UNKNOWN + } } login() + return future } + /** + * 分配收到的数据包 + */ @ExperimentalUnsignedTypes internal fun distributePacket(packet: ServerPacket) { packet.decode() @@ -112,14 +147,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { restartSocket() } - private var loginHook: ((LoginState) -> Unit)? = null - internal var loginState: LoginState? = null - set(value) { - field = value - if (value != null) { - loginHook?.invoke(value) - } - } + internal var loginFuture: CompletableFuture? = null private fun restartSocket() { socket?.close() @@ -151,17 +179,14 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { /** * Start network and touch the server */ - internal fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + internal fun touch(serverAddress: String): CompletableFuture { MiraiLogger.info("Connecting server: $serverAddress") + this.loginFuture = CompletableFuture() + socketHandler.serverIP = serverAddress - if (loginHook != null) { - this.loginHook = loginHook - } sendPacket(ClientTouchPacket(robot.account.qqNumber, socketHandler.serverIP)) - waitForPacket(ServerTouchResponsePacket::class, 100) { - MiraiLogger.error(" Timeout") - loginHook?.invoke(LoginState.TIMEOUT) - } + + return this.loginFuture!! } /** @@ -209,8 +234,12 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { override fun close() { this.socket?.close() - this.loginState = null - this.loginHook = null + if (this.loginFuture != null) { + if (!this.loginFuture!!.isDone) { + this.loginFuture!!.cancel(true) + } + this.loginFuture = null + } } } @@ -286,8 +315,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerLoginResponseFailedPacket -> { - socketHandler.loginState = packet.loginState - MiraiLogger error "Login failed: " + packet.loginState.toString() + socketHandler.loginFuture!!.complete(packet.loginState) return } @@ -309,8 +337,6 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerVerificationCodeTransmissionPacket -> { - socketHandler.loginState = LoginState.VERIFICATION_CODE - this.verificationCodeSequence++ this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN @@ -391,7 +417,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerLoginSuccessPacket -> { - socketHandler.loginState = LoginState.SUCCEED + socketHandler.loginFuture!!.complete(LoginState.SUCCEED) sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey)) } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index 395b92e56..4e54a750b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -46,8 +46,8 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } return ServerLoginResponseFailedPacket(when (bytes.size) { - 319 -> LoginState.WRONG_PASSWORD - 135 -> LoginState.RETYPE_PASSWORD + 319, 135 -> LoginState.WRONG_PASSWORD + //135 -> LoginState.RETYPE_PASSWORD 279 -> LoginState.BLOCKED 263 -> LoginState.UNKNOWN_QQ_NUMBER 551, 487 -> LoginState.DEVICE_LOCK diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index 5f4b6bdae..3abf7a2f2 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -4,7 +4,6 @@ import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.utils.* import java.io.DataInputStream - /** * 客户端请求验证码图片数据的第几部分 */ diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt index c2168c03c..482c057a9 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt @@ -4,20 +4,43 @@ package net.mamoe.mirai.network.packet.login * @author Him188moe */ enum class LoginState { + /** + * 登录成功 + */ SUCCEED, + /** + * 密码错误 + */ WRONG_PASSWORD, - // UNKNOWN,//? 要再次发送某数据包 - RETYPE_PASSWORD,//similar to [WRONG_PASSWORD] - BLOCKED,//你的帐号存在被盗风险,已进入保护模式 - UNKNOWN_QQ_NUMBER,//你输入的帐号不存在 - DEVICE_LOCK,//设备锁 - TAKEN_BACK,//被回收 + /** + * 被冻结 + */ + BLOCKED, - VERIFICATION_CODE,//需要验证码 + /** + * QQ 号码输入有误 + */ + UNKNOWN_QQ_NUMBER, + /** + * 账号开启了设备锁. 暂不支持设备锁登录 + */ + DEVICE_LOCK, + /** + * 账号被回收 + */ + TAKEN_BACK, + + /** + * 需要验证码登录 + */ + VERIFICATION_CODE, + + /** + * 未知. 更换服务器或等几分钟再登录可能解决. + */ UNKNOWN, - TIMEOUT, } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java b/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java index 085ee1aab..8bec23692 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java @@ -1,4 +1,14 @@ package net.mamoe.mirai.plugin; -public class MiraiPluginBase { +import net.mamoe.mirai.Robot; + +/** + * 插件基类. + *

+ * 插件属于整个 Mirai, 而不是属于单个 {@link Robot}. + * + * @see net.mamoe.mirai.event.MiraiEventManager + * @see net.mamoe.mirai.event.MiraiEventManagerKt + */ +public abstract class MiraiPluginBase { } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java index 1f623387d..4e950374b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java @@ -2,7 +2,7 @@ package net.mamoe.mirai.task; import net.mamoe.mirai.event.MiraiEventHook; -import net.mamoe.mirai.event.events.server.ServerDisableEvent; +import net.mamoe.mirai.event.events.server.ServerDisabledEvent; import java.util.concurrent.Callable; import java.util.concurrent.Future; @@ -24,7 +24,7 @@ public final class MiraiTaskManager { this.pool = new MiraiThreadPool(); MiraiEventHook - .onEvent(ServerDisableEvent.class) + .onEvent(ServerDisabledEvent.class) .handler(a -> this.pool.close()) .mount(); diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSettings.java similarity index 83% rename from mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java rename to mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSettings.java index 851cdd862..7eaa08cb7 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSettings.java @@ -1,5 +1,6 @@ package net.mamoe.mirai.utils.setting; +import net.mamoe.mirai.plugin.MiraiPluginBase; import org.ini4j.Config; import org.ini4j.Ini; @@ -15,7 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; * Only supports INI format
* Supports {@link Map} and {@link List} */ -public class MiraiSetting { +public class MiraiSettings { private File file; @@ -23,14 +24,21 @@ public class MiraiSetting { private volatile Map cacheSection = new ConcurrentHashMap<>(); - public MiraiSetting(File file){ + public MiraiSettings(MiraiPluginBase pluginBase, String filename) { + // TODO: 2019/9/6 每个插件独立文件夹存放 + this(new File(filename)); + } + + public MiraiSettings(File file) { if(!file.getName().contains(".")){ - file = new File(file.getParent() + file.getName() + ".ini"); + file = new File(file.getPath() + ".ini"); } this.file = file; try { if(file.exists()){ - file.createNewFile(); + if (!file.createNewFile()) { + throw new RuntimeException("cannot create config file " + file); + } } Config config = new Config(); config.setMultiSection(true); diff --git a/mirai-core/src/test/java/BadQQFilter.kt b/mirai-core/src/test/java/BadQQFilter.kt index 22114508e..7cac454e1 100644 --- a/mirai-core/src/test/java/BadQQFilter.kt +++ b/mirai-core/src/test/java/BadQQFilter.kt @@ -107,14 +107,16 @@ fun main() { qqList.split("\n").forEach { GlobalScope.launch { val strings = it.split("----") - Robot(RobotAccount(strings[0].toLong(), strings[1].let { password -> + val robot = Robot(RobotAccount(strings[0].toLong(), strings[1].let { password -> if (password.endsWith(".")) { return@let password.substring(0, password.length - 1) } return@let password - }), listOf()).network.tryLogin { state -> + }), listOf()) + + robot.network.tryLogin().whenComplete { state, _ -> if (!(state == LoginState.BLOCKED || state == LoginState.DEVICE_LOCK || state == LoginState.WRONG_PASSWORD)) { - goodRobotList.add(this) + goodRobotList.add(robot) } } }