diff --git a/pom.xml b/pom.xml index 802b66b..45adce3 100644 --- a/pom.xml +++ b/pom.xml @@ -31,9 +31,9 @@ 9+181-r4173-1 1.6.0 native-mt - 1.3.1 - 1.1.17 - 1.1.6 + 1.3.2 + 1.1.18 + 1.2.2 1.0.2 1.1.0 diff --git a/src/main/java/top/focess/qq/FocessQQ.java b/src/main/java/top/focess/qq/FocessQQ.java index cc61fd1..ce5d8bd 100755 --- a/src/main/java/top/focess/qq/FocessQQ.java +++ b/src/main/java/top/focess/qq/FocessQQ.java @@ -55,8 +55,6 @@ import top.focess.qq.core.plugin.PluginCoreClassLoader; import top.focess.qq.core.util.FocessSecurityManager; import top.focess.qq.core.util.MethodCaller; -import top.focess.scheduler.FocessScheduler; -import top.focess.scheduler.Scheduler; import top.focess.scheduler.Task; import top.focess.util.Pair; import top.focess.util.option.Option; @@ -73,7 +71,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.text.SimpleDateFormat; -import java.time.Duration; import java.util.*; import java.util.concurrent.Future; import java.util.zip.GZIPOutputStream; @@ -107,7 +104,6 @@ public class FocessQQ { * The Focess Logger */ private static final FocessLogger LOGGER = new FocessLogger(); - private static final Scheduler SCHEDULER = new FocessScheduler("FocessQQ"); private static final Scanner SCANNER = new Scanner(System.in); private static final Thread CONSOLE_INPUT_THREAD = new Thread(() -> { @@ -561,12 +557,6 @@ public static void exit() { return; isStopped = true; } - SCHEDULER.run(() -> { - try { - getLogger().fatalLang("fatal-exit-failed"); - } catch (final Exception ignored) {} - System.exit(0); - }, Duration.ofSeconds(5), "force-exit"); Runtime.getRuntime().removeShutdownHook(SHUTDOWN_HOOK); // need to check if Exit is called by Initialization if (MAIN_PLUGIN != null && MAIN_PLUGIN.isEnabled()) @@ -578,7 +568,6 @@ public static void exit() { getUdpSocket().close(); // make sure scheduler is stopped at the end Schedulers.closeAll(); - SCHEDULER.close(); if (!saved) { saveLogFile(); saved = true; @@ -586,14 +575,15 @@ public static void exit() { CONSOLE_INPUT_THREAD.interrupt(); Thread thread = new Thread(() -> { try { - Thread.sleep(10000); + Thread.sleep(5000); } catch (InterruptedException ignored) { } - System.err.println("Force Shutdown"); + System.out.println("Force Shutdown"); System.exit(0); }); thread.setDaemon(true); thread.start(); + System.out.println("Wait for 5000ms to shut down."); } private static void saveLogFile() { diff --git a/src/main/java/top/focess/qq/api/bot/BotManager.java b/src/main/java/top/focess/qq/api/bot/BotManager.java index 60dc14a..599e0b7 100644 --- a/src/main/java/top/focess/qq/api/bot/BotManager.java +++ b/src/main/java/top/focess/qq/api/bot/BotManager.java @@ -34,7 +34,7 @@ public interface BotManager { */ @NotNull default Future login(final long id, final String password, final Plugin plugin) { - return this.login(id, password, plugin, BotProtocol.ANDROID_PAD); + return this.login(id, password, plugin, BotProtocol.MACOS); } /** @@ -66,7 +66,7 @@ default Future login(final long id, final String password, final Plugin plu */ @NotNull default Bot loginDirectly(final long id, final String password, final Plugin plugin) throws BotLoginException { - return this.loginDirectly(id, password, plugin, BotProtocol.ANDROID_PAD); + return this.loginDirectly(id, password, plugin, BotProtocol.MACOS); } /** diff --git a/src/main/java/top/focess/qq/api/scheduler/Schedulers.java b/src/main/java/top/focess/qq/api/scheduler/Schedulers.java index 81e589e..981ca51 100644 --- a/src/main/java/top/focess/qq/api/scheduler/Schedulers.java +++ b/src/main/java/top/focess/qq/api/scheduler/Schedulers.java @@ -69,7 +69,6 @@ public static Scheduler newThreadPoolScheduler(@NotNull final Plugin plugin, fin Permission.checkPermission(Permission.SCHEDULER); final ThreadPoolScheduler scheduler = new ThreadPoolScheduler(plugin.getName(),poolSize); scheduler.setThreadUncaughtExceptionHandler((t, e) -> FocessQQ.getLogger().thrLang("exception-thread-pool-scheduler-thread-uncaught", e, t.getName())); - scheduler.setThreadCatchExceptionHandler((t, e) -> FocessQQ.getLogger().thrLang("exception-thread-pool-scheduler-thread", e)); return new AScheduler(plugin, scheduler); } @@ -91,7 +90,6 @@ public static Scheduler newThreadPoolScheduler(@NotNull final Plugin plugin, fin Permission.checkPermission(Permission.SCHEDULER); final ThreadPoolScheduler scheduler = new ThreadPoolScheduler(poolSize, immediate, name); scheduler.setThreadUncaughtExceptionHandler((t, e) -> FocessQQ.getLogger().thrLang("exception-thread-pool-scheduler-thread-uncaught", e, t.getName())); - scheduler.setThreadCatchExceptionHandler((t, e) -> FocessQQ.getLogger().thrLang("exception-thread-pool-scheduler-thread", e)); return new AScheduler(plugin,scheduler); } diff --git a/src/main/java/top/focess/qq/api/util/session/Session.java b/src/main/java/top/focess/qq/api/util/session/Session.java index eb5e630..4bc47e9 100644 --- a/src/main/java/top/focess/qq/api/util/session/Session.java +++ b/src/main/java/top/focess/qq/api/util/session/Session.java @@ -29,7 +29,10 @@ public Session(@Nullable final Map values) { @Override public SessionSection createSection(final String key) { final Map values = Maps.newHashMap(); - this.set(key, values); + final Plugin plugin = PluginCoreClassLoader.getPluginByClass(MethodCaller.getCallerClass()); + if (plugin != null) + SectionMap.super.set(plugin.getName() + ":" + key, values); + else SectionMap.super.set(key, values); return new SessionSection(this, values); } @@ -40,7 +43,11 @@ public Map getValues() { @Override public SectionMap getSection(final String key) { - final Object value = this.get(key); + Object value; + final Plugin plugin = PluginCoreClassLoader.getPluginByClass(MethodCaller.getCallerClass()); + if (plugin != null) + value = SectionMap.super.get(plugin.getName() + ":" + key); + else value = SectionMap.super.get(key); if (value == null) this.containsSection(key); if (value instanceof Map) @@ -50,7 +57,10 @@ public SectionMap getSection(final String key) { @Override public boolean containsSection(final String key) { - return this.get(key) instanceof Map; + final Plugin plugin = PluginCoreClassLoader.getPluginByClass(MethodCaller.getCallerClass()); + if (plugin != null) + return SectionMap.super.get(plugin.getName() + ":" + key) instanceof Map; + else return SectionMap.super.get(key) instanceof Map; } @Override diff --git a/src/main/java/top/focess/qq/core/bot/mirai/MiraiBotManager.java b/src/main/java/top/focess/qq/core/bot/mirai/MiraiBotManager.java index 9a58e95..25c8f80 100644 --- a/src/main/java/top/focess/qq/core/bot/mirai/MiraiBotManager.java +++ b/src/main/java/top/focess/qq/core/bot/mirai/MiraiBotManager.java @@ -3,11 +3,17 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import kotlin.coroutines.Continuation; +import kotlin.coroutines.CoroutineContext; +import kotlin.coroutines.EmptyCoroutineContext; import net.mamoe.mirai.BotFactory; +import net.mamoe.mirai.auth.BotAuthorization; +import net.mamoe.mirai.auth.QRCodeLoginListener; import net.mamoe.mirai.contact.OtherClient; import net.mamoe.mirai.event.Listener; import net.mamoe.mirai.event.events.*; import net.mamoe.mirai.utils.BotConfiguration; +import net.mamoe.mirai.utils.DeviceVerificationRequests; +import net.mamoe.mirai.utils.DeviceVerificationResult; import net.mamoe.mirai.utils.LoginSolver; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -144,7 +150,7 @@ public Object onSolvePicCaptcha(@NotNull final net.mamoe.mirai.Bot bot, final by } FocessQQ.getLogger().infoLang("input-captcha-code"); try { - return IOHandler.getConsoleIoHandler().inputMessage(); + return IOHandler.getConsoleIoHandler().inputMessage().toString(); } catch (final InputTimeoutException e) { return null; } @@ -155,10 +161,10 @@ public Object onSolvePicCaptcha(@NotNull final net.mamoe.mirai.Bot bot, final by public Object onSolveSliderCaptcha(@NotNull final net.mamoe.mirai.Bot bot, @NotNull final String s, @NotNull final Continuation continuation) { FocessQQ.getLogger().info(s); try { - IOHandler.getConsoleIoHandler().inputMessage(); + return IOHandler.getConsoleIoHandler().inputMessage().toString(); } catch (final InputTimeoutException ignored) { + return null; } - return null; } @Nullable @@ -166,13 +172,83 @@ public Object onSolveSliderCaptcha(@NotNull final net.mamoe.mirai.Bot bot, @NotN public Object onSolveUnsafeDeviceLoginVerify(@NotNull final net.mamoe.mirai.Bot bot, @NotNull final String s, @NotNull final Continuation continuation) { FocessQQ.getLogger().info(s); try { - IOHandler.getConsoleIoHandler().inputMessage(); + return IOHandler.getConsoleIoHandler().inputMessage().toString(); } catch (final InputTimeoutException ignored) { + return null; + } + } + + @Override + public @NotNull Object onSolveDeviceVerification(@NotNull net.mamoe.mirai.Bot bot, @NotNull DeviceVerificationRequests requests, @NotNull Continuation continuation) { + if (requests.getPreferSms()) { + FocessQQ.getLogger().info(requests.getSms().getCountryCode() + " " + requests.getSms().getPhoneNumber()); + try { + IOHandler.getConsoleIoHandler().inputMessage(); + } catch (final InputTimeoutException ignored) { + } + + Object lock = new Object(); + requests.getSms().requestSms(new Continuation<>() { + @Override + public @NotNull CoroutineContext getContext() { + return EmptyCoroutineContext.INSTANCE; + } + + @Override + public void resumeWith(@NotNull Object result) { + synchronized (lock) { + lock.notify(); + } + } + }); + synchronized (lock) { + try { + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + String code; + try { + code = IOHandler.getConsoleIoHandler().inputMessage().toString(); + } catch (final InputTimeoutException ignored) { + code = ""; + } + return requests.getSms().solved(code); + } else { + FocessQQ.getLogger().info(requests.getFallback().getUrl()); + try { + IOHandler.getConsoleIoHandler().inputMessage(); + } catch (final InputTimeoutException ignored) { + } + return requests.getFallback().solved(); } - return null; + } + + @NotNull + @Override + public QRCodeLoginListener createQRCodeLoginListener(@NotNull net.mamoe.mirai.Bot bot) { + return new QRCodeLoginListener() { + @Override + public void onStateChanged(@NotNull net.mamoe.mirai.Bot bot, @NotNull QRCodeLoginListener.State state) { + FocessQQ.getLogger().infoLang("bot-login-qrcode-state", id, state.name()); + } + + @Override + public void onFetchQRCode(@NotNull net.mamoe.mirai.Bot bot, @NotNull byte[] bytes) { + System.out.println("????????"); + try { + final FileImageOutputStream outputStream = new FileImageOutputStream(new File("qrcode.jpg")); + outputStream.write(bytes); + outputStream.close(); + } catch (final IOException e) { + FocessQQ.getLogger().thrLang("exception-load-qrcode-picture", e); + } + } + }; } }); - final net.mamoe.mirai.Bot bot = BotFactory.INSTANCE.newBot(id, password, configuration); + final net.mamoe.mirai.Bot bot = BotFactory.INSTANCE.newBot(id, password.equalsIgnoreCase("qr") ? BotAuthorization.byQRCode() : BotAuthorization.byPassword(password), configuration); try { bot.login(); } catch (final Exception e) { diff --git a/src/main/java/top/focess/qq/core/commands/PermissionCommand.java b/src/main/java/top/focess/qq/core/commands/PermissionCommand.java index 8dadfec..0eeaf2d 100644 --- a/src/main/java/top/focess/qq/core/commands/PermissionCommand.java +++ b/src/main/java/top/focess/qq/core/commands/PermissionCommand.java @@ -24,7 +24,7 @@ public void init() { this.setExecutorPermission(i -> i.isAdministrator() || i.isConsole()); this.addExecutor((sender,data,ioHandler)->{ Plugin plugin = data.get(Plugin.class); - if (plugin.getPluginDescription().getPermissions().size() == 0) + if (plugin.getPluginDescription().getPermissions().isEmpty()) ioHandler.outputLang("permission-command-no-permission",plugin.getName()); else { StringBuilder stringBuilder = new StringBuilder(); diff --git a/src/main/java/top/focess/qq/core/scheduler/AScheduler.java b/src/main/java/top/focess/qq/core/scheduler/AScheduler.java index 29ff9f9..e2319cd 100644 --- a/src/main/java/top/focess/qq/core/scheduler/AScheduler.java +++ b/src/main/java/top/focess/qq/core/scheduler/AScheduler.java @@ -9,7 +9,6 @@ import top.focess.qq.core.permission.Permission; import top.focess.qq.core.permission.PermissionEnv; import top.focess.scheduler.Callback; -import top.focess.scheduler.CatchExceptionHandler; import top.focess.scheduler.Scheduler; import top.focess.scheduler.Task; @@ -33,7 +32,6 @@ public AScheduler(final Plugin plugin, final Scheduler scheduler) { this.plugin = plugin; this.scheduler = scheduler; this.scheduler.setUncaughtExceptionHandler((t, e) -> FocessQQ.getLogger().thrLang("exception-scheduler-uncaught", e, this.getName())); - this.scheduler.setCatchExceptionHandler((t, e) -> FocessQQ.getLogger().thrLang("exception-scheduler", e, this.getName())); PLUGIN_SCHEDULER_MAP.compute(plugin, (k, v) -> { if (v == null) v = Lists.newCopyOnWriteArrayList(); @@ -123,16 +121,6 @@ public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { return this.scheduler.getUncaughtExceptionHandler(); } - @Override - public @Nullable CatchExceptionHandler getCatchExceptionHandler() { - return this.scheduler.getCatchExceptionHandler(); - } - - @Override - public void setCatchExceptionHandler(final CatchExceptionHandler catchExceptionHandler) { - this.scheduler.setCatchExceptionHandler(catchExceptionHandler); - } - @Override public @UnmodifiableView List getRemainingTasks() { return this.scheduler.getRemainingTasks(); diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml index c781d4c..0fce2cc 100644 --- a/src/main/resources/lang.yml +++ b/src/main/resources/lang.yml @@ -47,6 +47,7 @@ exception-load-class: Load class exception exception-load-plugin: Load plugin exception exception-load-plugin-file: Load plugin file exception exception-load-captcha-picture: Load captcha picture exception +exception-load-qrcode-picture: Load qrcode picture exception exception-reload-plugin: Reload plugin exception exception-load-default-plugin: Load default plugin exception exception-unload-default-plugin: Unload default plugin exception @@ -157,7 +158,7 @@ friend-command-send-success: Send message to friend %d successfully debug-command-debug-output-status: "Debug Output Status: %b" pause-command-pause-mode-status: "Pause Mode Status: %b" plugin-description-not-found: File plugin.yml not found -unknown-command: Unknown command %s +unknown-command: "Unknown command: %s" command-exec: "%s exec: %s" input-account-username: Please input account username input-account-password: Please input account password @@ -217,4 +218,5 @@ debug-cancel-event: "Cancel event: %s to %s" permission-command-no-permission: "The plugin %s does not have permissions" permission-command-list: "The plugin %s has the following permissions:%s" permission-command-set-success: "The plugin %s set the permission %s successfully" -permission-command-set-failed: "The plugin %s set the permission %s failed, it may already have the permission" \ No newline at end of file +permission-command-set-failed: "The plugin %s set the permission %s failed, it may already have the permission" +bot-login-qrcode-state: "Bot %d login qrcode state: %s" \ No newline at end of file diff --git a/src/test/java/top/focess/qq/test/TestUtil.java b/src/test/java/top/focess/qq/test/TestUtil.java index 33f3005..3959c96 100644 --- a/src/test/java/top/focess/qq/test/TestUtil.java +++ b/src/test/java/top/focess/qq/test/TestUtil.java @@ -26,9 +26,9 @@ import java.lang.reflect.Field; import java.time.Duration; import java.util.List; +import java.util.PriorityQueue; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -230,7 +230,7 @@ void testScheduler4() throws Exception { field1.setAccessible(true); Field field2 = ComparableTask.class.getDeclaredField("task"); field2.setAccessible(true); - PriorityBlockingQueue tasks2 = (PriorityBlockingQueue) field.get(scheduler); + PriorityQueue tasks2 = (PriorityQueue) field.get(scheduler); List tasks = Lists.newArrayList(); for (int i = 0;i<5;i++) { int finalI = i;