mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2025-01-31 23:12:15 +01:00
Improve lifecycle
This commit is contained in:
parent
56c1baa830
commit
56cb74815c
@ -38,8 +38,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The DiscordSRV API.
|
||||
@ -156,7 +155,6 @@ public interface DiscordSRVApi {
|
||||
* <p>
|
||||
* JDA is an external library and comes with its own versioning and deprecation policies, using DiscordSRV's own APIs where possible is recommended.
|
||||
* DiscordSRV will upgrade JDA as needed, including breaking changes and major version upgrades.
|
||||
*
|
||||
* <a href="https://github.com/DV8FromTheWorld/JDA#deprecation-policy">JDA's deprecation policy</a>
|
||||
*
|
||||
* @see #discordAPI() discordAPI() for the first party api
|
||||
@ -271,50 +269,6 @@ public interface DiscordSRVApi {
|
||||
|
||||
}
|
||||
|
||||
enum ReloadFlag {
|
||||
CONFIG(false),
|
||||
LINKED_ACCOUNT_PROVIDER(false),
|
||||
STORAGE(true),
|
||||
DISCORD_CONNECTION(DiscordSRVApi::isReady),
|
||||
MODULES(false),
|
||||
DISCORD_COMMANDS(false),
|
||||
|
||||
// Bukkit only
|
||||
TRANSLATIONS(false)
|
||||
|
||||
;
|
||||
|
||||
public static final Set<ReloadFlag> ALL = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(values())));
|
||||
public static final Set<ReloadFlag> DEFAULT_FLAGS = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(CONFIG, MODULES)));
|
||||
|
||||
private final Predicate<DiscordSRVApi> requiresConfirm;
|
||||
|
||||
ReloadFlag(boolean requiresConfirm) {
|
||||
this(__ -> requiresConfirm);
|
||||
}
|
||||
|
||||
ReloadFlag(Predicate<DiscordSRVApi> requiresConfirm) {
|
||||
this.requiresConfirm = requiresConfirm;
|
||||
}
|
||||
|
||||
public boolean requiresConfirm(DiscordSRVApi discordSRV) {
|
||||
return requiresConfirm.test(discordSRV);
|
||||
}
|
||||
}
|
||||
|
||||
interface ReloadResult {
|
||||
|
||||
ReloadResult RESTART_REQUIRED = DefaultConstants.RESTART_REQUIRED;
|
||||
|
||||
String name();
|
||||
|
||||
enum DefaultConstants implements ReloadResult {
|
||||
|
||||
RESTART_REQUIRED
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@SuppressWarnings("unused") // API, Reflection
|
||||
final class InstanceHolder {
|
||||
|
@ -23,8 +23,8 @@
|
||||
|
||||
package com.discordsrv.api.events.lifecycle;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.events.Event;
|
||||
import com.discordsrv.api.reload.ReloadFlag;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@ -33,17 +33,17 @@ import java.util.Set;
|
||||
*/
|
||||
public class DiscordSRVReloadedEvent implements Event {
|
||||
|
||||
private final Set<DiscordSRVApi.ReloadFlag> flags;
|
||||
private final Set<ReloadFlag> flags;
|
||||
|
||||
public DiscordSRVReloadedEvent(Set<DiscordSRVApi.ReloadFlag> flags) {
|
||||
public DiscordSRVReloadedEvent(Set<ReloadFlag> flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of DiscordSRV systems that were reloaded.
|
||||
* @return an unmodifiable set of {@link com.discordsrv.api.DiscordSRVApi.ReloadFlag}s
|
||||
* @return an unmodifiable set of {@link ReloadFlag}s
|
||||
*/
|
||||
public Set<DiscordSRVApi.ReloadFlag> flags() {
|
||||
public Set<ReloadFlag> flags() {
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import com.discordsrv.api.discord.connection.details.DiscordMemberCachePolicy;
|
||||
import com.discordsrv.api.eventbus.EventListener;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.discord.message.AbstractDiscordMessageEvent;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import net.dv8tion.jda.api.events.GenericEvent;
|
||||
import net.dv8tion.jda.api.events.guild.member.GenericGuildMemberEvent;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
@ -161,5 +162,5 @@ public interface Module {
|
||||
* Called by DiscordSRV to reload this module. This is called when the module is enabled as well.
|
||||
* @param resultConsumer a consumer to supply results to, if any apply
|
||||
*/
|
||||
default void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {}
|
||||
default void reload(Consumer<ReloadResult> resultConsumer) {}
|
||||
}
|
||||
|
62
api/src/main/java/com/discordsrv/api/reload/ReloadFlag.java
Normal file
62
api/src/main/java/com/discordsrv/api/reload/ReloadFlag.java
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.discordsrv.api.reload;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public enum ReloadFlag {
|
||||
CONFIG(false),
|
||||
LINKED_ACCOUNT_PROVIDER(false),
|
||||
STORAGE(true),
|
||||
DISCORD_CONNECTION(DiscordSRVApi::isReady),
|
||||
DISCORD_COMMANDS(false),
|
||||
|
||||
// Bukkit only
|
||||
TRANSLATIONS(false);
|
||||
|
||||
public static final Set<ReloadFlag> ALL = Collections.unmodifiableSet(
|
||||
new LinkedHashSet<>(Arrays.asList(values())));
|
||||
public static final Set<ReloadFlag> DEFAULT_FLAGS = Collections.unmodifiableSet(
|
||||
new LinkedHashSet<>(Collections.singletonList(CONFIG)));
|
||||
|
||||
private final Predicate<DiscordSRVApi> requiresConfirm;
|
||||
|
||||
ReloadFlag(boolean requiresConfirm) {
|
||||
this(__ -> requiresConfirm);
|
||||
}
|
||||
|
||||
ReloadFlag(Predicate<DiscordSRVApi> requiresConfirm) {
|
||||
this.requiresConfirm = requiresConfirm;
|
||||
}
|
||||
|
||||
public boolean requiresConfirm(DiscordSRVApi discordSRV) {
|
||||
return requiresConfirm.test(discordSRV);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.discordsrv.api.reload;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public enum ReloadResult {
|
||||
|
||||
RESTART_REQUIRED,
|
||||
|
||||
@ApiStatus.Internal
|
||||
ERROR,
|
||||
@ApiStatus.Internal
|
||||
DEFAULT_BOT_TOKEN,
|
||||
@ApiStatus.Internal
|
||||
DISCORD_CONNECTION_RELOAD_REQUIRED,
|
||||
@ApiStatus.Internal
|
||||
SECURITY_FAILED,
|
||||
@ApiStatus.Internal
|
||||
STORAGE_CONNECTION_FAILED,
|
||||
@ApiStatus.Internal
|
||||
DISCORD_CONNECTION_FAILED,
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
package com.discordsrv.bukkit;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.reload.ReloadFlag;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.bukkit.ban.BukkitBanModule;
|
||||
import com.discordsrv.bukkit.command.game.BukkitGameCommandExecutionHelper;
|
||||
import com.discordsrv.bukkit.command.game.handler.AbstractBukkitCommandHandler;
|
||||
@ -226,7 +228,7 @@ public class BukkitDiscordSRV extends AbstractDiscordSRV<DiscordSRVBukkitBootstr
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReloadResult> reload(Set<ReloadFlag> flags, boolean initial) throws Throwable {
|
||||
protected List<ReloadResult> reload(Set<ReloadFlag> flags, boolean initial) throws Throwable {
|
||||
List<ReloadResult> results = super.reload(flags, initial);
|
||||
|
||||
if (flags.contains(ReloadFlag.TRANSLATIONS)) {
|
||||
|
@ -71,7 +71,7 @@ public class DiscordSRVBukkitBootstrap extends BukkitBootstrap implements IBoots
|
||||
lifecycleManager.loadAndEnable(() -> this.discordSRV = new BukkitDiscordSRV(this));
|
||||
if (discordSRV == null) return;
|
||||
|
||||
discordSRV.scheduler().runOnMainThreadLaterInTicks(() -> discordSRV.invokeServerStarted(), 1);
|
||||
discordSRV.scheduler().runOnMainThreadLaterInTicks(() -> discordSRV.runServerStarted(), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,10 +23,11 @@ import com.discordsrv.api.events.lifecycle.DiscordSRVReadyEvent;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVReloadedEvent;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.api.module.Module;
|
||||
import com.discordsrv.api.reload.ReloadFlag;
|
||||
import com.discordsrv.common.abstraction.bootstrap.IBootstrap;
|
||||
import com.discordsrv.common.command.discord.DiscordCommandModule;
|
||||
import com.discordsrv.common.command.game.GameCommandModule;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.reload.ReloadResults;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.config.configurate.manager.ConnectionConfigManager;
|
||||
import com.discordsrv.common.config.configurate.manager.MainConfigManager;
|
||||
import com.discordsrv.common.config.configurate.manager.MessagesConfigManager;
|
||||
@ -55,6 +56,7 @@ import com.discordsrv.common.core.storage.StorageType;
|
||||
import com.discordsrv.common.core.storage.impl.MemoryStorage;
|
||||
import com.discordsrv.common.discord.api.DiscordAPIEventModule;
|
||||
import com.discordsrv.common.discord.api.DiscordAPIImpl;
|
||||
import com.discordsrv.common.discord.connection.DiscordConnectionManager;
|
||||
import com.discordsrv.common.discord.connection.details.DiscordConnectionDetailsImpl;
|
||||
import com.discordsrv.common.discord.connection.jda.JDAConnectionManager;
|
||||
import com.discordsrv.common.exception.StorageException;
|
||||
@ -90,10 +92,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.JDAInfo;
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.Dispatcher;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.MustBeInvokedByOverriders;
|
||||
@ -136,6 +135,7 @@ public abstract class AbstractDiscordSRV<
|
||||
private final AtomicReference<Status> status = new AtomicReference<>(Status.INITIALIZED);
|
||||
private final AtomicReference<Boolean> beenReady = new AtomicReference<>(false);
|
||||
private boolean serverStarted = false;
|
||||
private final Object reloadLock = new Object();
|
||||
|
||||
// DiscordSRVApi
|
||||
private EventBusImpl eventBus;
|
||||
@ -543,37 +543,72 @@ public abstract class AbstractDiscordSRV<
|
||||
|
||||
// Lifecycle
|
||||
|
||||
public boolean isServerStarted() {
|
||||
return serverStarted;
|
||||
}
|
||||
|
||||
public ZonedDateTime getInitializeTime() {
|
||||
return initializeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run blocking when plugin/mod is triggered for enabling.
|
||||
*/
|
||||
@Override
|
||||
public final void runEnable() {
|
||||
try {
|
||||
this.enable();
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to enable", t);
|
||||
logger().error("Failed to enable", t);
|
||||
setStatus(Status.FAILED_TO_START);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be manually triggered for {@link DiscordSRV.ServerType#SERVER}, automatically triggered in {@link #enable()} for {@link DiscordSRV.ServerType#PROXY}.
|
||||
* @return a future running on the {@link #scheduler()}
|
||||
*/
|
||||
public final CompletableFuture<Void> runServerStarted() {
|
||||
return scheduler().execute(() -> {
|
||||
if (status().isShutdown()) {
|
||||
// Already shutdown/shutting down, don't bother
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.serverStarted();
|
||||
} catch (Throwable t) {
|
||||
if (status().isShutdown() && t instanceof NoClassDefFoundError) {
|
||||
// Already shutdown, ignore errors for classes that already got unloaded
|
||||
return;
|
||||
}
|
||||
logger().error("Failed to start", t);
|
||||
setStatus(Status.FAILED_TO_START);
|
||||
|
||||
disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a reload of DiscordSRV.
|
||||
* @param flags the targets to reload
|
||||
* @return the results of the reload
|
||||
*/
|
||||
@Override
|
||||
public final CompletableFuture<Void> invokeDisable() {
|
||||
return scheduler().execute(this::disable);
|
||||
public final List<ReloadResult> runReload(Set<ReloadFlag> flags) {
|
||||
try {
|
||||
synchronized (reloadLock) {
|
||||
return reload(flags, false);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("Failed to reload", e);
|
||||
return Collections.singletonList(ReloadResult.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<ReloadResult> runReload(Set<ReloadFlag> flags, boolean silent) {
|
||||
try {
|
||||
return reload(flags, silent);
|
||||
} catch (Throwable e) {
|
||||
if (silent) {
|
||||
throw new RuntimeException(e);
|
||||
} else {
|
||||
logger.error("Failed to reload", e);
|
||||
}
|
||||
return Collections.singletonList(ReloadResults.FAILED);
|
||||
}
|
||||
public final CompletableFuture<Void> runDisable() {
|
||||
return scheduler().execute(this::disable);
|
||||
}
|
||||
|
||||
@MustBeInvokedByOverriders
|
||||
@ -643,41 +678,16 @@ public abstract class AbstractDiscordSRV<
|
||||
}
|
||||
|
||||
// Initial load
|
||||
try {
|
||||
runReload(ReloadFlag.ALL, true);
|
||||
} catch (RuntimeException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
reload(ReloadFlag.ALL, true);
|
||||
|
||||
if (serverType() == ServerType.PROXY) {
|
||||
invokeServerStarted().get();
|
||||
runServerStarted().get();
|
||||
}
|
||||
|
||||
// Register PlayerProvider listeners
|
||||
playerProvider().subscribe();
|
||||
}
|
||||
|
||||
public final CompletableFuture<Void> invokeServerStarted() {
|
||||
return scheduler().supply(() -> {
|
||||
if (status().isShutdown()) {
|
||||
// Already shutdown/shutting down, don't bother
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
this.serverStarted();
|
||||
} catch (Throwable t) {
|
||||
if (status().isShutdown() && t instanceof NoClassDefFoundError) {
|
||||
// Already shutdown, ignore errors for classes that already got unloaded
|
||||
return null;
|
||||
}
|
||||
setStatus(Status.FAILED_TO_START);
|
||||
disable();
|
||||
logger().error("Failed to start", t);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@MustBeInvokedByOverriders
|
||||
protected void serverStarted() {
|
||||
serverStarted = true;
|
||||
@ -688,50 +698,8 @@ public abstract class AbstractDiscordSRV<
|
||||
Optional.ofNullable(getModule(PresenceUpdaterModule.class)).ifPresent(PresenceUpdaterModule::serverStarted);
|
||||
}
|
||||
|
||||
public boolean isServerStarted() {
|
||||
return serverStarted;
|
||||
}
|
||||
|
||||
private StorageType getStorageType() {
|
||||
String backend = connectionConfig().storage.backend;
|
||||
switch (backend.toLowerCase(Locale.ROOT)) {
|
||||
case "h2": return StorageType.H2;
|
||||
case "mysql": return StorageType.MYSQL;
|
||||
case "mariadb": return StorageType.MARIADB;
|
||||
}
|
||||
if (backend.equals(MemoryStorage.IDENTIFIER)) {
|
||||
return StorageType.MEMORY;
|
||||
}
|
||||
throw new StorageException("Unknown storage backend \"" + backend + "\"");
|
||||
}
|
||||
|
||||
@MustBeInvokedByOverriders
|
||||
protected void disable() {
|
||||
Status status = this.status.get();
|
||||
if (status == Status.INITIALIZED || status.isShutdown()) {
|
||||
// Hasn't started or already shutting down/shutdown
|
||||
return;
|
||||
}
|
||||
this.status.set(Status.SHUTTING_DOWN);
|
||||
|
||||
// Unregister PlayerProvider listeners
|
||||
playerProvider().unsubscribe();
|
||||
|
||||
eventBus().publish(new DiscordSRVShuttingDownEvent());
|
||||
eventBus().shutdown();
|
||||
try {
|
||||
if (storage != null) {
|
||||
storage.close();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger().error("Failed to close storage connection", t);
|
||||
}
|
||||
temporaryLocalData.save();
|
||||
this.status.set(Status.SHUTDOWN);
|
||||
}
|
||||
|
||||
@MustBeInvokedByOverriders
|
||||
public List<ReloadResult> reload(Set<ReloadFlag> flags, boolean initial) throws Throwable {
|
||||
protected List<ReloadResult> reload(Set<ReloadFlag> flags, boolean initial) throws Throwable {
|
||||
if (!initial) {
|
||||
logger().info("Reloading DiscordSRV...");
|
||||
}
|
||||
@ -767,7 +735,7 @@ public abstract class AbstractDiscordSRV<
|
||||
logger().info("");
|
||||
}
|
||||
discordConnectionManager.invalidToken(true);
|
||||
results.add(ReloadResults.DEFAULT_BOT_TOKEN);
|
||||
results.add(ReloadResult.DEFAULT_BOT_TOKEN);
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -776,13 +744,13 @@ public abstract class AbstractDiscordSRV<
|
||||
if (updateConfig.security.enabled) {
|
||||
if (updateChecker.isSecurityFailed()) {
|
||||
// Security has already failed
|
||||
return Collections.singletonList(ReloadResults.SECURITY_FAILED);
|
||||
return Collections.singletonList(ReloadResult.SECURITY_FAILED);
|
||||
}
|
||||
|
||||
if (initial && !updateChecker.check(true)) {
|
||||
// Security failed cancel startup & shutdown
|
||||
invokeDisable();
|
||||
return Collections.singletonList(ReloadResults.SECURITY_FAILED);
|
||||
runDisable();
|
||||
return Collections.singletonList(ReloadResult.SECURITY_FAILED);
|
||||
}
|
||||
} else if (initial) {
|
||||
// Not using security, run update check off thread
|
||||
@ -824,7 +792,7 @@ public abstract class AbstractDiscordSRV<
|
||||
if (initial) {
|
||||
setStatus(Status.FAILED_TO_START);
|
||||
}
|
||||
return Collections.singletonList(ReloadResults.STORAGE_CONNECTION_FAILED);
|
||||
return Collections.singletonList(ReloadResult.STORAGE_CONNECTION_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,7 +822,7 @@ public abstract class AbstractDiscordSRV<
|
||||
break;
|
||||
default: {
|
||||
linkProvider = null;
|
||||
logger().error("Unknown linked account provider: \"" + provider + "\", linked accounts will not be used");
|
||||
logger().error("Unknown linked account provider: \"" + provider + "\", linked accounts will be disabled");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -865,35 +833,20 @@ public abstract class AbstractDiscordSRV<
|
||||
}
|
||||
|
||||
if (flags.contains(ReloadFlag.DISCORD_CONNECTION)) {
|
||||
try {
|
||||
if (discordConnectionManager.instance() != null) {
|
||||
discordConnectionManager.reconnect().get();
|
||||
} else {
|
||||
discordConnectionManager.connect().get();
|
||||
// Shutdown will not fail even if not connected
|
||||
discordConnectionManager.shutdown(DiscordConnectionManager.DEFAULT_SHUTDOWN_TIMEOUT);
|
||||
|
||||
discordConnectionManager.connect();
|
||||
if (!initial) {
|
||||
waitForStatus(Status.CONNECTED, 20, TimeUnit.SECONDS);
|
||||
if (status() != Status.CONNECTED) {
|
||||
return Collections.singletonList(ReloadResult.DISCORD_CONNECTION_FAILED);
|
||||
}
|
||||
if (!initial) {
|
||||
waitForStatus(Status.CONNECTED, 20, TimeUnit.SECONDS);
|
||||
if (status() != Status.CONNECTED) {
|
||||
return Collections.singletonList(ReloadResults.DISCORD_CONNECTION_FAILED);
|
||||
}
|
||||
} else {
|
||||
JDA jda = jda();
|
||||
if (jda != null) {
|
||||
try {
|
||||
jda.awaitReady();
|
||||
} catch (IllegalStateException ignored) {
|
||||
// JDA shutdown -> don't continue
|
||||
return Collections.singletonList(ReloadResults.DISCORD_CONNECTION_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
// Modules are reloaded upon DiscordSRV being ready, thus not needed at initial
|
||||
if (!initial && flags.contains(ReloadFlag.MODULES)) {
|
||||
if (!initial && flags.contains(ReloadFlag.CONFIG)) {
|
||||
results.addAll(moduleManager.reload());
|
||||
}
|
||||
|
||||
@ -907,7 +860,56 @@ public abstract class AbstractDiscordSRV<
|
||||
logger().info("Reload complete.");
|
||||
}
|
||||
|
||||
results.add(ReloadResults.SUCCESS);
|
||||
return results;
|
||||
}
|
||||
|
||||
private StorageType getStorageType() {
|
||||
String backend = connectionConfig().storage.backend;
|
||||
switch (backend.toLowerCase(Locale.ROOT)) {
|
||||
case "h2": return StorageType.H2;
|
||||
case "mysql": return StorageType.MYSQL;
|
||||
case "mariadb": return StorageType.MARIADB;
|
||||
}
|
||||
if (backend.equals(MemoryStorage.IDENTIFIER)) {
|
||||
return StorageType.MEMORY;
|
||||
}
|
||||
throw new StorageException("Unknown storage backend \"" + backend + "\"");
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource") //
|
||||
@MustBeInvokedByOverriders
|
||||
protected void disable() {
|
||||
Status status = this.status.get();
|
||||
if (status == Status.INITIALIZED || status.isShutdown()) {
|
||||
// Hasn't started or already shutting down/shutdown
|
||||
return;
|
||||
}
|
||||
this.status.set(Status.SHUTTING_DOWN);
|
||||
|
||||
// Unregister PlayerProvider listeners
|
||||
playerProvider().unsubscribe();
|
||||
|
||||
eventBus().publish(new DiscordSRVShuttingDownEvent());
|
||||
eventBus().shutdown();
|
||||
|
||||
// Shutdown OkHttp
|
||||
httpClient.dispatcher().executorService().shutdownNow();
|
||||
httpClient.connectionPool().evictAll();
|
||||
try {
|
||||
Cache cache = httpClient.cache();
|
||||
if (cache != null) {
|
||||
cache.close();
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
try {
|
||||
if (storage != null) {
|
||||
storage.close();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger().error("Failed to close storage connection", t);
|
||||
}
|
||||
temporaryLocalData.save();
|
||||
this.status.set(Status.SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package com.discordsrv.common;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.module.Module;
|
||||
import com.discordsrv.api.reload.ReloadFlag;
|
||||
import com.discordsrv.api.placeholder.format.PlainPlaceholderFormat;
|
||||
import com.discordsrv.common.abstraction.bootstrap.IBootstrap;
|
||||
import com.discordsrv.common.abstraction.player.IPlayer;
|
||||
@ -28,6 +29,7 @@ import com.discordsrv.common.abstraction.plugin.PluginManager;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper;
|
||||
import com.discordsrv.common.command.game.abstraction.handler.ICommandHandler;
|
||||
import com.discordsrv.common.command.game.abstraction.sender.ICommandSender;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.config.configurate.manager.ConnectionConfigManager;
|
||||
import com.discordsrv.common.config.configurate.manager.MainConfigManager;
|
||||
import com.discordsrv.common.config.configurate.manager.MessagesConfigManager;
|
||||
@ -174,8 +176,8 @@ public interface DiscordSRV extends DiscordSRVApi {
|
||||
|
||||
// Lifecycle
|
||||
void runEnable();
|
||||
List<ReloadResult> runReload(Set<ReloadFlag> flags, boolean silent);
|
||||
CompletableFuture<Void> invokeDisable();
|
||||
List<ReloadResult> runReload(Set<ReloadFlag> flags);
|
||||
CompletableFuture<Void> runDisable();
|
||||
boolean isServerStarted();
|
||||
ZonedDateTime getInitializeTime();
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package com.discordsrv.common.abstraction.bootstrap;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.reload.ReloadFlag;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.core.dependency.DependencyLoader;
|
||||
import com.discordsrv.common.core.logging.Logger;
|
||||
@ -44,7 +44,7 @@ public class LifecycleManager {
|
||||
private final Logger logger;
|
||||
private final ExecutorService taskPool;
|
||||
private final DependencyLoader dependencyLoader;
|
||||
private final CompletableFuture<?> completableFuture;
|
||||
private final CompletableFuture<?> dependencyLoadFuture;
|
||||
|
||||
public LifecycleManager(
|
||||
Logger logger,
|
||||
@ -66,19 +66,26 @@ public class LifecycleManager {
|
||||
classpathAppender,
|
||||
resourcePaths.toArray(new String[0])
|
||||
);
|
||||
this.completableFuture = dependencyLoader.download();
|
||||
this.completableFuture.whenComplete((v, t) -> taskPool.shutdownNow());
|
||||
this.dependencyLoadFuture = dependencyLoader.download();
|
||||
this.dependencyLoadFuture.whenComplete((v, t) -> taskPool.shutdownNow());
|
||||
}
|
||||
|
||||
public void loadAndEnable(Supplier<DiscordSRV> discordSRVSupplier) {
|
||||
if (relocateAndLoad()) {
|
||||
discordSRVSupplier.get().runEnable();
|
||||
if (!relocateAndLoad()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DiscordSRV discordSRV = discordSRVSupplier.get();
|
||||
if (discordSRV == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
discordSRV.runEnable();
|
||||
}
|
||||
|
||||
private boolean relocateAndLoad() {
|
||||
try {
|
||||
completableFuture.get();
|
||||
dependencyLoadFuture.get();
|
||||
dependencyLoader.relocateAndLoad(false).get();
|
||||
return true;
|
||||
} catch (InterruptedException ignored) {
|
||||
@ -93,12 +100,12 @@ public class LifecycleManager {
|
||||
if (discordSRV == null) {
|
||||
return;
|
||||
}
|
||||
discordSRV.runReload(DiscordSRVApi.ReloadFlag.DEFAULT_FLAGS, false);
|
||||
discordSRV.runReload(ReloadFlag.DEFAULT_FLAGS);
|
||||
}
|
||||
|
||||
public void disable(DiscordSRV discordSRV) {
|
||||
if (!completableFuture.isDone()) {
|
||||
completableFuture.cancel(true);
|
||||
if (!dependencyLoadFuture.isDone()) {
|
||||
dependencyLoadFuture.cancel(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -107,7 +114,7 @@ public class LifecycleManager {
|
||||
}
|
||||
|
||||
try {
|
||||
discordSRV.invokeDisable().get(/*15, TimeUnit.SECONDS*/);
|
||||
discordSRV.runDisable().get(/*15, TimeUnit.SECONDS*/);
|
||||
} catch (InterruptedException/* | TimeoutException*/ e) {
|
||||
logger.warning("Timed out/interrupted shutting down DiscordSRV");
|
||||
} catch (ExecutionException e) {
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
package com.discordsrv.common.abstraction.sync;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.abstraction.player.IPlayer;
|
||||
import com.discordsrv.common.abstraction.sync.cause.GenericSyncCauses;
|
||||
@ -100,7 +100,7 @@ public abstract class AbstractSyncModule<
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
synchronized (syncs) {
|
||||
syncs.values().forEach(future -> {
|
||||
if (future != null) {
|
||||
|
@ -19,11 +19,12 @@
|
||||
package com.discordsrv.common.command.game;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.commands.LinkOtherCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.command.GameCommand;
|
||||
import com.discordsrv.common.command.game.commands.DiscordSRVGameCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.handler.ICommandHandler;
|
||||
import com.discordsrv.common.command.game.commands.DiscordSRVGameCommand;
|
||||
import com.discordsrv.common.config.main.GameCommandConfig;
|
||||
import com.discordsrv.common.core.module.type.AbstractModule;
|
||||
|
||||
@ -46,7 +47,7 @@ public class GameCommandModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
GameCommandConfig config = discordSRV.config().gameCommand;
|
||||
if (config == null) {
|
||||
return;
|
||||
|
@ -18,7 +18,8 @@
|
||||
|
||||
package com.discordsrv.common.command.game.commands.subcommand.reload;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.reload.ReloadFlag;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.abstraction.player.IPlayer;
|
||||
import com.discordsrv.common.command.game.abstraction.command.GameCommand;
|
||||
@ -65,9 +66,9 @@ public class ReloadCommand implements GameCommandExecutor, GameCommandSuggester
|
||||
@Override
|
||||
public void execute(ICommandSender sender, GameCommandArguments arguments, String label) {
|
||||
AtomicBoolean dangerousFlags = new AtomicBoolean(false);
|
||||
Set<DiscordSRV.ReloadFlag> flags = getFlagsFromArguments(sender, arguments, dangerousFlags);
|
||||
Set<ReloadFlag> flags = getFlagsFromArguments(sender, arguments, dangerousFlags);
|
||||
if (flags == null) {
|
||||
flags = DiscordSRV.ReloadFlag.DEFAULT_FLAGS;
|
||||
flags = ReloadFlag.DEFAULT_FLAGS;
|
||||
}
|
||||
|
||||
if (dangerousFlags.get()) {
|
||||
@ -80,50 +81,64 @@ public class ReloadCommand implements GameCommandExecutor, GameCommandSuggester
|
||||
return;
|
||||
}
|
||||
|
||||
List<DiscordSRVApi.ReloadResult> results = discordSRV.runReload(flags, false);
|
||||
for (DiscordSRV.ReloadResult result : results) {
|
||||
String res = result.name();
|
||||
if (res.equals(ReloadResults.FAILED.name())) {
|
||||
sender.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("Reload failed.", NamedTextColor.DARK_RED, TextDecoration.BOLD))
|
||||
.append(Component.text("Please check the server console/log for more details."))
|
||||
);
|
||||
} else if (res.equals(ReloadResults.SECURITY_FAILED.name())) {
|
||||
sender.sendMessage(Component.text(
|
||||
"DiscordSRV is disabled due to a security check failure. "
|
||||
+ "Please check console for more details", NamedTextColor.DARK_RED));
|
||||
} else if (res.equals(ReloadResults.SUCCESS.name())) {
|
||||
sender.sendMessage(Component.text("Reload successful", NamedTextColor.GRAY));
|
||||
} else if (res.equals(ReloadResults.RESTART_REQUIRED.name())) {
|
||||
sender.sendMessage(Component.text("Some changes require a server restart"));
|
||||
} else if (res.equals(ReloadResults.STORAGE_CONNECTION_FAILED.name())) {
|
||||
sender.sendMessage(Component.text("Storage connection failed, please check console for details.", NamedTextColor.RED));
|
||||
} else if (res.equals(ReloadResults.DISCORD_CONNECTION_FAILED.name())) {
|
||||
sender.sendMessage(Component.text("Discord connection failed, please check console for details.", NamedTextColor.RED));
|
||||
} else if (res.equals(ReloadResults.DISCORD_CONNECTION_RELOAD_REQUIRED.name())) {
|
||||
String command = "discordsrv reload " + DiscordSRVApi.ReloadFlag.DISCORD_CONNECTION.name().toLowerCase(Locale.ROOT) + " -confirm";
|
||||
Component child;
|
||||
if (sender instanceof IPlayer) {
|
||||
child = Component.text("[Click to reload Discord connection]", NamedTextColor.DARK_RED)
|
||||
.clickEvent(ClickEvent.runCommand("/" + command))
|
||||
.hoverEvent(HoverEvent.showText(Component.text("/" + command)));
|
||||
} else {
|
||||
child = Component.text("Run ", NamedTextColor.DARK_RED)
|
||||
.append(Component.text(command, NamedTextColor.GRAY))
|
||||
.append(Component.text(" to reload the Discord connection"));
|
||||
List<ReloadResult> results = discordSRV.runReload(flags);
|
||||
if (results.isEmpty()) {
|
||||
sender.sendMessage(Component.text("Reload successful", NamedTextColor.GRAY));
|
||||
return;
|
||||
}
|
||||
for (ReloadResult result : results) {
|
||||
switch (result) {
|
||||
case ERROR: {
|
||||
sender.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("Reload failed.", NamedTextColor.DARK_RED, TextDecoration.BOLD))
|
||||
.append(Component.text("Please check the server console/log for more details."))
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SECURITY_FAILED: {
|
||||
sender.sendMessage(Component.text(
|
||||
"DiscordSRV is disabled due to a security check failure. "
|
||||
+ "Please check console for more details", NamedTextColor.DARK_RED));
|
||||
break;
|
||||
}
|
||||
case RESTART_REQUIRED: {
|
||||
sender.sendMessage(Component.text("Some changes require a server restart"));
|
||||
break;
|
||||
}
|
||||
case STORAGE_CONNECTION_FAILED: {
|
||||
sender.sendMessage(Component.text("Storage connection failed, please check console for details.", NamedTextColor.RED));
|
||||
break;
|
||||
}
|
||||
case DISCORD_CONNECTION_FAILED: {
|
||||
sender.sendMessage(Component.text("Discord connection failed, please check console for details.", NamedTextColor.RED));
|
||||
break;
|
||||
}
|
||||
case DISCORD_CONNECTION_RELOAD_REQUIRED: {
|
||||
String command = "discordsrv reload " + ReloadFlag.DISCORD_CONNECTION.name().toLowerCase(Locale.ROOT) + " -confirm";
|
||||
Component child;
|
||||
if (sender instanceof IPlayer) {
|
||||
child = Component.text("[Click to reload Discord connection]", NamedTextColor.DARK_RED)
|
||||
.clickEvent(ClickEvent.runCommand("/" + command))
|
||||
.hoverEvent(HoverEvent.showText(Component.text("/" + command)));
|
||||
} else {
|
||||
child = Component.text("Run ", NamedTextColor.DARK_RED)
|
||||
.append(Component.text(command, NamedTextColor.GRAY))
|
||||
.append(Component.text(" to reload the Discord connection"));
|
||||
}
|
||||
|
||||
sender.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("Some changes require a Discord connection reload. ", NamedTextColor.GRAY))
|
||||
.append(child)
|
||||
);
|
||||
sender.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("Some changes require a Discord connection reload. ", NamedTextColor.GRAY))
|
||||
.append(child)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<DiscordSRV.ReloadFlag> getFlagsFromArguments(ICommandSender sender, GameCommandArguments arguments, AtomicBoolean dangerousFlags) {
|
||||
private Set<ReloadFlag> getFlagsFromArguments(ICommandSender sender, GameCommandArguments arguments, AtomicBoolean dangerousFlags) {
|
||||
String argument = null;
|
||||
try {
|
||||
argument = arguments.get("flags", String.class);
|
||||
@ -136,16 +151,16 @@ public class ReloadCommand implements GameCommandExecutor, GameCommandSuggester
|
||||
List<String> parts = new ArrayList<>(Arrays.asList(argument.split(" ")));
|
||||
boolean confirm = parts.remove("-confirm");
|
||||
|
||||
Set<DiscordSRV.ReloadFlag> flags = new LinkedHashSet<>();
|
||||
Set<ReloadFlag> flags = new LinkedHashSet<>();
|
||||
if (discordSRV.status().isStartupError()) {
|
||||
// If startup error, use all flags
|
||||
parts.clear();
|
||||
flags.addAll(DiscordSRVApi.ReloadFlag.ALL);
|
||||
flags.addAll(ReloadFlag.ALL);
|
||||
}
|
||||
|
||||
for (String part : parts) {
|
||||
try {
|
||||
DiscordSRV.ReloadFlag flag = DiscordSRV.ReloadFlag.valueOf(part.toUpperCase(Locale.ROOT));
|
||||
ReloadFlag flag = ReloadFlag.valueOf(part.toUpperCase(Locale.ROOT));
|
||||
if (flag.requiresConfirm(discordSRV) && !confirm) {
|
||||
dangerousFlags.set(true);
|
||||
sender.sendMessage(
|
||||
@ -175,7 +190,7 @@ public class ReloadCommand implements GameCommandExecutor, GameCommandSuggester
|
||||
String last = currentInput.substring(lastSpace);
|
||||
String beforeLastSpace = currentInput.substring(0, lastSpace);
|
||||
|
||||
List<String> options = DiscordSRV.ReloadFlag.ALL.stream()
|
||||
List<String> options = ReloadFlag.ALL.stream()
|
||||
.map(flag -> flag.name().toLowerCase(Locale.ROOT))
|
||||
.filter(flag -> flag.startsWith(last))
|
||||
.collect(Collectors.toList());
|
||||
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.command.game.commands.subcommand.reload;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
|
||||
public enum ReloadResults implements DiscordSRVApi.ReloadResult {
|
||||
FAILED,
|
||||
DEFAULT_BOT_TOKEN,
|
||||
SUCCESS,
|
||||
SECURITY_FAILED,
|
||||
STORAGE_CONNECTION_FAILED,
|
||||
DISCORD_CONNECTION_RELOAD_REQUIRED,
|
||||
DISCORD_CONNECTION_FAILED
|
||||
}
|
@ -18,7 +18,6 @@
|
||||
|
||||
package com.discordsrv.common.core.module;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordCacheFlag;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordMemberCachePolicy;
|
||||
@ -27,8 +26,8 @@ import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVReadyEvent;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.api.module.Module;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.reload.ReloadResults;
|
||||
import com.discordsrv.common.core.logging.Logger;
|
||||
import com.discordsrv.common.core.logging.NamedLogger;
|
||||
import com.discordsrv.common.core.module.type.AbstractModule;
|
||||
@ -163,7 +162,7 @@ public class ModuleManager {
|
||||
logger.debug(module.getClass().getName() + " unregistered");
|
||||
}
|
||||
|
||||
private List<DiscordSRVApi.ReloadResult> enable(AbstractModule<?> module) {
|
||||
private List<ReloadResult> enable(AbstractModule<?> module) {
|
||||
try {
|
||||
if (module.enableModule()) {
|
||||
logger.debug(module + " enabled");
|
||||
@ -176,8 +175,8 @@ public class ModuleManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<DiscordSRVApi.ReloadResult> reload(AbstractModule<?> module) {
|
||||
List<DiscordSRVApi.ReloadResult> reloadResults = new ArrayList<>();
|
||||
private List<ReloadResult> reload(AbstractModule<?> module) {
|
||||
List<ReloadResult> reloadResults = new ArrayList<>();
|
||||
try {
|
||||
module.reload(result -> {
|
||||
if (result == null) {
|
||||
@ -225,7 +224,7 @@ public class ModuleManager {
|
||||
}
|
||||
}
|
||||
|
||||
public List<DiscordSRVApi.ReloadResult> reload() {
|
||||
public List<ReloadResult> reload() {
|
||||
return reloadAndEnableModules(true);
|
||||
}
|
||||
|
||||
@ -233,19 +232,19 @@ public class ModuleManager {
|
||||
reloadAndEnableModules(false);
|
||||
}
|
||||
|
||||
private synchronized List<DiscordSRV.ReloadResult> reloadAndEnableModules(boolean reload) {
|
||||
private synchronized List<ReloadResult> reloadAndEnableModules(boolean reload) {
|
||||
boolean isReady = discordSRV.isReady();
|
||||
logger().debug((reload ? "Reloading" : "Enabling") + " modules (DiscordSRV ready = " + isReady + ")");
|
||||
|
||||
Set<DiscordSRVApi.ReloadResult> reloadResults = new HashSet<>();
|
||||
Set<ReloadResult> reloadResults = new HashSet<>();
|
||||
for (Module module : modules) {
|
||||
reloadResults.addAll(enableOrDisableAsNeeded(getAbstract(module), isReady, reload));
|
||||
}
|
||||
|
||||
List<DiscordSRVApi.ReloadResult> results = new ArrayList<>();
|
||||
List<ReloadResult> results = new ArrayList<>();
|
||||
|
||||
List<DiscordSRV.ReloadResult> validResults = Arrays.asList(DiscordSRVApi.ReloadResult.DefaultConstants.values());
|
||||
for (DiscordSRVApi.ReloadResult reloadResult : reloadResults) {
|
||||
List<ReloadResult> validResults = Arrays.asList(ReloadResult.values());
|
||||
for (ReloadResult reloadResult : reloadResults) {
|
||||
if (validResults.contains(reloadResult)) {
|
||||
results.add(reloadResult);
|
||||
}
|
||||
@ -254,7 +253,7 @@ public class ModuleManager {
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<DiscordSRVApi.ReloadResult> enableOrDisableAsNeeded(AbstractModule<?> module, boolean isReady, boolean mayReload) {
|
||||
private List<ReloadResult> enableOrDisableAsNeeded(AbstractModule<?> module, boolean isReady, boolean mayReload) {
|
||||
boolean canBeEnabled = isReady || module.canEnableBeforeReady();
|
||||
if (!canBeEnabled) {
|
||||
return Collections.emptyList();
|
||||
@ -282,14 +281,14 @@ public class ModuleManager {
|
||||
}
|
||||
}
|
||||
|
||||
List<DiscordSRVApi.ReloadResult> reloadResults = new ArrayList<>();
|
||||
List<ReloadResult> reloadResults = new ArrayList<>();
|
||||
if (fail) {
|
||||
reloadResults.add(ReloadResults.DISCORD_CONNECTION_RELOAD_REQUIRED);
|
||||
reloadResults.add(ReloadResult.DISCORD_CONNECTION_RELOAD_REQUIRED);
|
||||
}
|
||||
|
||||
// Enable the module if reload passed
|
||||
if (!fail) {
|
||||
List<DiscordSRVApi.ReloadResult> results = enable(module);
|
||||
List<ReloadResult> results = enable(module);
|
||||
if (results != null) {
|
||||
reloadResults.addAll(results);
|
||||
} else if (mayReload) {
|
||||
|
@ -18,11 +18,11 @@
|
||||
|
||||
package com.discordsrv.common.core.module.type;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordCacheFlag;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordMemberCachePolicy;
|
||||
import com.discordsrv.api.module.Module;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.core.logging.NamedLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -79,7 +79,7 @@ public class ModuleDelegate extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
module.reload(resultConsumer);
|
||||
}
|
||||
|
||||
|
@ -21,15 +21,12 @@ package com.discordsrv.common.discord.connection;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public interface DiscordConnectionManager {
|
||||
|
||||
/**
|
||||
* The default amount of milliseconds to wait for shutdown before ending without completing rate limited requests.
|
||||
*/
|
||||
long DEFAULT_SHUTDOWN_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
|
||||
int DEFAULT_SHUTDOWN_TIMEOUT = 10;
|
||||
|
||||
/**
|
||||
* Gets the instance.
|
||||
@ -40,33 +37,16 @@ public interface DiscordConnectionManager {
|
||||
|
||||
/**
|
||||
* Attempts to connect to Discord.
|
||||
* @return a {@link CompletableFuture}
|
||||
*/
|
||||
CompletableFuture<Void> connect();
|
||||
|
||||
/**
|
||||
* Shuts down the Discord connection and connects again.
|
||||
* @return a {@link CompletableFuture}
|
||||
*/
|
||||
CompletableFuture<Void> reconnect();
|
||||
|
||||
/**
|
||||
* Shuts down the Discord connection after waiting for queued requests to complete. Blocks until shutdown is completed.
|
||||
* @return a {@link CompletableFuture}
|
||||
* @see #DEFAULT_SHUTDOWN_TIMEOUT
|
||||
*/
|
||||
default CompletableFuture<Void> shutdown() {
|
||||
return shutdown(DEFAULT_SHUTDOWN_TIMEOUT);
|
||||
}
|
||||
void connect();
|
||||
|
||||
/**
|
||||
* Shuts down the Discord connection after waiting for queued requests to complete.
|
||||
* Waits the provided amount of milliseconds before running {@link #shutdownNow()}.
|
||||
*
|
||||
* @param timeoutMillis the maximum amount of milliseconds to wait for shut down
|
||||
* @return a {@link CompletableFuture}
|
||||
* @param timeoutSeconds the maximum amount of seconds to wait for JDA to shut down
|
||||
*/
|
||||
CompletableFuture<Void> shutdown(long timeoutMillis);
|
||||
void shutdown(int timeoutSeconds);
|
||||
|
||||
/**
|
||||
* Shuts down the Discord connection without waiting for queued requests to be completed.
|
||||
|
@ -85,7 +85,6 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
private ScheduledExecutorService rateLimitSchedulerPool;
|
||||
private ExecutorService rateLimitElasticPool;
|
||||
|
||||
private CompletableFuture<Void> connectionFuture;
|
||||
private JDA instance;
|
||||
|
||||
// Currently used intents & cache flags
|
||||
@ -286,20 +285,11 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
//
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> connect() {
|
||||
if (connectionFuture != null && !connectionFuture.isDone()) {
|
||||
throw new IllegalStateException("Already connecting");
|
||||
} else if (instance != null && instance.getStatus() != JDA.Status.SHUTDOWN) {
|
||||
public void connect() {
|
||||
if (instance != null && instance.getStatus() != JDA.Status.SHUTDOWN) {
|
||||
throw new IllegalStateException("Cannot reconnect, still active");
|
||||
}
|
||||
|
||||
this.connectInternal();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
// TODO: investigate why this is broken
|
||||
//return connectionFuture = discordSRV.scheduler().execute(this::connectInternal);
|
||||
}
|
||||
|
||||
private void connectInternal() {
|
||||
BotConfig botConfig = discordSRV.connectionConfig().bot;
|
||||
String token = botConfig.token;
|
||||
boolean defaultToken = false;
|
||||
@ -412,8 +402,8 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
// Our own (named) threads
|
||||
jdaBuilder.setCallbackPool(discordSRV.scheduler().forkJoinPool());
|
||||
jdaBuilder.setGatewayPool(gatewayPool);
|
||||
jdaBuilder.setRateLimitScheduler(rateLimitSchedulerPool, true);
|
||||
jdaBuilder.setRateLimitElastic(rateLimitElasticPool);
|
||||
jdaBuilder.setRateLimitScheduler(rateLimitSchedulerPool);
|
||||
jdaBuilder.setRateLimitElastic(rateLimitElasticPool, true);
|
||||
jdaBuilder.setHttpClient(discordSRV.httpClient());
|
||||
|
||||
WebSocketFactory webSocketFactory = new WebSocketFactory();
|
||||
@ -428,27 +418,13 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> reconnect() {
|
||||
return discordSRV.scheduler().execute(() -> {
|
||||
shutdown().join();
|
||||
connect().join();
|
||||
});
|
||||
}
|
||||
|
||||
@Subscribe(priority = EventPriority.LATE)
|
||||
public void onDSRVShuttingDown(DiscordSRVShuttingDownEvent event) {
|
||||
// This has a timeout
|
||||
shutdown().join();
|
||||
shutdown(DEFAULT_SHUTDOWN_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> shutdown(long timeoutMillis) {
|
||||
return discordSRV.scheduler().execute(() -> shutdownInternal(timeoutMillis));
|
||||
}
|
||||
|
||||
@SuppressWarnings("BusyWait")
|
||||
private void shutdownInternal(long timeoutMillis) {
|
||||
@SuppressWarnings("BusyWait") // Known
|
||||
public void shutdown(int timeoutSeconds) {
|
||||
if (instance == null) {
|
||||
shutdownExecutors();
|
||||
return;
|
||||
@ -457,14 +433,16 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
instance.shutdown();
|
||||
|
||||
try {
|
||||
discordSRV.logger().info("Waiting up to " + TimeUnit.MILLISECONDS.toSeconds(timeoutMillis) + " seconds for JDA to shutdown...");
|
||||
discordSRV.logger().info("Waiting up to " + timeoutSeconds + " seconds for JDA to shutdown...");
|
||||
discordSRV.scheduler().run(() -> {
|
||||
try {
|
||||
while (instance != null && !rateLimitSchedulerPool.isShutdown()) {
|
||||
while (instance != null && instance.getStatus() != JDA.Status.SHUTDOWN && !rateLimitElasticPool.isShutdown()) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
} catch (InterruptedException ignored) {}
|
||||
}).get(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException ignored) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}).get(timeoutSeconds, TimeUnit.SECONDS);
|
||||
instance = null;
|
||||
shutdownExecutors();
|
||||
discordSRV.logger().info("JDA shutdown completed.");
|
||||
@ -478,7 +456,9 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
}
|
||||
discordSRV.logger().error("Failed to shutdown JDA", t);
|
||||
}
|
||||
} catch (InterruptedException ignored) {}
|
||||
} catch (InterruptedException ignored) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -495,10 +475,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
if (gatewayPool != null) {
|
||||
gatewayPool.shutdownNow();
|
||||
}
|
||||
if (rateLimitSchedulerPool != null && !rateLimitSchedulerPool.isShutdown()) {
|
||||
if (rateLimitSchedulerPool != null) {
|
||||
rateLimitSchedulerPool.shutdownNow();
|
||||
}
|
||||
if (rateLimitElasticPool != null) {
|
||||
if (rateLimitElasticPool != null && !rateLimitElasticPool.isShutdown()) {
|
||||
rateLimitElasticPool.shutdownNow();
|
||||
}
|
||||
if (failureCallbackFuture != null) {
|
||||
|
@ -18,12 +18,12 @@
|
||||
|
||||
package com.discordsrv.common.feature;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
import com.discordsrv.api.discord.connection.jda.errorresponse.ErrorCallbackContext;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.placeholder.annotation.Placeholder;
|
||||
import com.discordsrv.api.placeholder.format.FormattedText;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.DiscordInviteConfig;
|
||||
import com.discordsrv.common.core.logging.NamedLogger;
|
||||
@ -79,7 +79,7 @@ public class DiscordInviteModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
JDA jda = discordSRV.jda();
|
||||
if (jda == null) {
|
||||
logger().debug("JDA == null");
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
package com.discordsrv.common.feature;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.eventbus.EventPriority;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.PresenceUpdaterConfig;
|
||||
import com.discordsrv.common.core.logging.NamedLogger;
|
||||
@ -70,7 +70,7 @@ public class PresenceUpdaterModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
if (discordSRV.jda() == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
package com.discordsrv.common.feature.channel;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.connection.jda.errorresponse.ErrorCallbackContext;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.TimedUpdaterConfig;
|
||||
import com.discordsrv.common.core.logging.NamedLogger;
|
||||
@ -67,7 +67,7 @@ public class TimedUpdaterModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
futures.forEach(future -> future.cancel(false));
|
||||
futures.clear();
|
||||
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
package com.discordsrv.common.feature.console;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.discord.message.DiscordMessageReceiveEvent;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.ConsoleConfig;
|
||||
import com.discordsrv.common.config.main.generic.DestinationConfig;
|
||||
@ -70,7 +70,7 @@ public class ConsoleModule extends AbstractModule<DiscordSRV> implements LogAppe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
List<ConsoleConfig> configs = discordSRV.config().console;
|
||||
Set<ConsoleConfig> uncheckedConfigs = new LinkedHashSet<>(configs);
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
package com.discordsrv.common.feature.customcommands;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.discord.entity.DiscordUser;
|
||||
import com.discordsrv.api.discord.entity.channel.DiscordChannel;
|
||||
import com.discordsrv.api.discord.entity.guild.DiscordGuildMember;
|
||||
@ -28,6 +27,7 @@ import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.events.discord.interaction.command.AbstractCommandInteractionEvent;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.CustomCommandConfig;
|
||||
import com.discordsrv.common.core.logging.NamedLogger;
|
||||
@ -55,7 +55,7 @@ public class CustomCommandModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
List<CustomCommandConfig> configs = discordSRV.config().customCommands;
|
||||
|
||||
List<LayerCommand> layeredCommands = new ArrayList<>();
|
||||
|
@ -18,9 +18,9 @@
|
||||
|
||||
package com.discordsrv.common.feature.linking.requirelinking;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
import com.discordsrv.api.eventbus.Subscribe;
|
||||
import com.discordsrv.api.events.linking.AccountUnlinkedEvent;
|
||||
import com.discordsrv.api.reload.ReloadResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.abstraction.player.IPlayer;
|
||||
import com.discordsrv.common.config.main.linking.RequiredLinkingConfig;
|
||||
@ -101,7 +101,7 @@ public abstract class RequiredLinkingModule<T extends DiscordSRV> extends Abstra
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
public final void reload(Consumer<ReloadResult> resultConsumer) {
|
||||
List<RequirementType<?>> requirementTypes = new ArrayList<>();
|
||||
|
||||
requirementTypes.add(new DiscordRoleRequirementType(this));
|
||||
|
Loading…
Reference in New Issue
Block a user