Start & stop messages, some bug fixes & cleanup

This commit is contained in:
Vankka 2022-04-01 19:07:14 +03:00
parent 60c7dbfbc0
commit 2b878f1265
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
26 changed files with 378 additions and 120 deletions

View File

@ -30,5 +30,7 @@ public abstract class ProxyDiscordSRV<C extends MainConfig, CC extends Connectio
super.enable(); super.enable();
registerModule(ServerSwitchMessageModule::new); registerModule(ServerSwitchMessageModule::new);
startedMessage();
} }
} }

View File

@ -21,10 +21,11 @@ package com.discordsrv.proxy.config.channels;
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage; import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.common.config.annotation.Untranslated; import com.discordsrv.common.config.annotation.Untranslated;
import com.discordsrv.common.config.main.channels.IMessageConfig;
import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable @ConfigSerializable
public class ServerSwitchMessageConfig { public class ServerSwitchMessageConfig implements IMessageConfig {
public boolean enabled = true; public boolean enabled = true;
@ -40,4 +41,14 @@ public class ServerSwitchMessageConfig {
.setColor(0x5555FF) .setColor(0x5555FF)
.build() .build()
); );
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
} }

View File

@ -19,7 +19,6 @@
package com.discordsrv.proxy.modules; package com.discordsrv.proxy.modules;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.api.event.bus.EventPriority; import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe; import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.message.forward.game.ServerSwitchMessageForwardedEvent; import com.discordsrv.api.event.events.message.forward.game.ServerSwitchMessageForwardedEvent;
@ -27,7 +26,6 @@ import com.discordsrv.api.event.events.message.receive.game.ServerSwitchMessageR
import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault; import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule; import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule;
import com.discordsrv.proxy.config.channels.ServerSwitchMessageConfig; import com.discordsrv.proxy.config.channels.ServerSwitchMessageConfig;
import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig; import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig;
@ -35,7 +33,7 @@ import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig;
public class ServerSwitchMessageModule extends AbstractGameMessageModule<ServerSwitchMessageConfig> { public class ServerSwitchMessageModule extends AbstractGameMessageModule<ServerSwitchMessageConfig> {
public ServerSwitchMessageModule(DiscordSRV discordSRV) { public ServerSwitchMessageModule(DiscordSRV discordSRV) {
super(discordSRV, new NamedLogger(discordSRV, "SERVER_SWITCH")); super(discordSRV, "SERVER_SWITCH_MESSAGES");
} }
@Subscribe(priority = EventPriority.LAST) @Subscribe(priority = EventPriority.LAST)
@ -53,16 +51,6 @@ public class ServerSwitchMessageModule extends AbstractGameMessageModule<ServerS
return channelConfig.map(cfg -> ((ProxyBaseChannelConfig) cfg).serverSwitchMessages); return channelConfig.map(cfg -> ((ProxyBaseChannelConfig) cfg).serverSwitchMessages);
} }
@Override
public boolean isEnabled(OrDefault<ServerSwitchMessageConfig> config) {
return config.get(cfg -> cfg.enabled, false);
}
@Override
public SendableDiscordMessage.Builder getFormat(OrDefault<ServerSwitchMessageConfig> config) {
return config.get(cfg -> cfg.format);
}
@Override @Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) { public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {
discordSRV.eventBus().publish(new ServerSwitchMessageForwardedEvent(cluster)); discordSRV.eventBus().publish(new ServerSwitchMessageForwardedEvent(cluster));

View File

@ -45,11 +45,16 @@ public abstract class ServerDiscordSRV<C extends MainConfig, CC extends Connecti
} }
public final CompletableFuture<Void> invokeServerStarted() { public final CompletableFuture<Void> invokeServerStarted() {
return invokeLifecycle(this::serverStarted, "Failed to enable", true); return invokeLifecycle(() -> {
if (status().isShutdown()) {
return;
}
this.serverStarted();
});
} }
@OverridingMethodsMustInvokeSuper @OverridingMethodsMustInvokeSuper
protected void serverStarted() { protected void serverStarted() {
startedMessage();
} }
} }

View File

@ -21,11 +21,12 @@ package com.discordsrv.common.server.config.channels;
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage; import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.common.config.annotation.Untranslated; import com.discordsrv.common.config.annotation.Untranslated;
import com.discordsrv.common.config.main.channels.IMessageConfig;
import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import org.spongepowered.configurate.objectmapping.meta.Comment; import org.spongepowered.configurate.objectmapping.meta.Comment;
@ConfigSerializable @ConfigSerializable
public class DeathMessageConfig { public class DeathMessageConfig implements IMessageConfig {
@Comment("Enable death message forwarding") @Comment("Enable death message forwarding")
public boolean enabled = true; public boolean enabled = true;
@ -38,4 +39,14 @@ public class DeathMessageConfig {
.setColor(1) .setColor(1)
.build() .build()
); );
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
} }

View File

@ -19,7 +19,6 @@
package com.discordsrv.common.server.modules; package com.discordsrv.common.server.modules;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.api.event.bus.EventPriority; import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe; import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.message.forward.game.DeathMessageForwardedEvent; import com.discordsrv.api.event.events.message.forward.game.DeathMessageForwardedEvent;
@ -27,7 +26,6 @@ import com.discordsrv.api.event.events.message.receive.game.DeathMessageReceiveE
import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault; import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule; import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule;
import com.discordsrv.common.server.config.channels.DeathMessageConfig; import com.discordsrv.common.server.config.channels.DeathMessageConfig;
import com.discordsrv.common.server.config.channels.base.ServerBaseChannelConfig; import com.discordsrv.common.server.config.channels.base.ServerBaseChannelConfig;
@ -35,7 +33,7 @@ import com.discordsrv.common.server.config.channels.base.ServerBaseChannelConfig
public class DeathMessageModule extends AbstractGameMessageModule<DeathMessageConfig> { public class DeathMessageModule extends AbstractGameMessageModule<DeathMessageConfig> {
public DeathMessageModule(DiscordSRV discordSRV) { public DeathMessageModule(DiscordSRV discordSRV) {
super(discordSRV, new NamedLogger(discordSRV, "DEATH")); super(discordSRV, "DEATH_MESSAGES");
} }
@Subscribe(priority = EventPriority.LAST) @Subscribe(priority = EventPriority.LAST)
@ -53,16 +51,6 @@ public class DeathMessageModule extends AbstractGameMessageModule<DeathMessageCo
return channelConfig.map(cfg -> ((ServerBaseChannelConfig) cfg).deathMessages); return channelConfig.map(cfg -> ((ServerBaseChannelConfig) cfg).deathMessages);
} }
@Override
public boolean isEnabled(OrDefault<DeathMessageConfig> config) {
return config.get(cfg -> cfg.enabled, true);
}
@Override
public SendableDiscordMessage.Builder getFormat(OrDefault<DeathMessageConfig> config) {
return config.get(cfg -> cfg.format);
}
@Override @Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) { public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {
discordSRV.eventBus().publish(new DeathMessageForwardedEvent(cluster)); discordSRV.eventBus().publish(new DeathMessageForwardedEvent(cluster));

View File

@ -19,7 +19,6 @@
package com.discordsrv.common; package com.discordsrv.common;
import com.discordsrv.api.discord.connection.DiscordConnectionDetails; import com.discordsrv.api.discord.connection.DiscordConnectionDetails;
import com.discordsrv.api.event.bus.EventBus;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVConnectedEvent; import com.discordsrv.api.event.events.lifecycle.DiscordSRVConnectedEvent;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReadyEvent; import com.discordsrv.api.event.events.lifecycle.DiscordSRVReadyEvent;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadedEvent; import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadedEvent;
@ -58,6 +57,8 @@ import com.discordsrv.common.messageforwarding.discord.DiscordChatMessageModule;
import com.discordsrv.common.messageforwarding.discord.DiscordMessageMirroringModule; import com.discordsrv.common.messageforwarding.discord.DiscordMessageMirroringModule;
import com.discordsrv.common.messageforwarding.game.JoinMessageModule; import com.discordsrv.common.messageforwarding.game.JoinMessageModule;
import com.discordsrv.common.messageforwarding.game.LeaveMessageModule; import com.discordsrv.common.messageforwarding.game.LeaveMessageModule;
import com.discordsrv.common.messageforwarding.game.StartMessageModule;
import com.discordsrv.common.messageforwarding.game.StopMessageModule;
import com.discordsrv.common.module.ModuleManager; import com.discordsrv.common.module.ModuleManager;
import com.discordsrv.common.module.type.AbstractModule; import com.discordsrv.common.module.type.AbstractModule;
import com.discordsrv.common.placeholder.ComponentResultStringifier; import com.discordsrv.common.placeholder.ComponentResultStringifier;
@ -100,9 +101,10 @@ import java.util.jar.Manifest;
public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends ConnectionConfig> implements DiscordSRV { public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends ConnectionConfig> implements DiscordSRV {
private final AtomicReference<Status> status = new AtomicReference<>(Status.INITIALIZED); private final AtomicReference<Status> status = new AtomicReference<>(Status.INITIALIZED);
private CompletableFuture<Void> enableFuture;
// DiscordSRVApi // DiscordSRVApi
private EventBus eventBus; private EventBusImpl eventBus;
private ProfileManager profileManager; private ProfileManager profileManager;
private PlaceholderServiceImpl placeholderService; private PlaceholderServiceImpl placeholderService;
private ComponentFactory componentFactory; private ComponentFactory componentFactory;
@ -201,7 +203,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} }
@Override @Override
public @NotNull EventBus eventBus() { public @NotNull EventBusImpl eventBus() {
return eventBus; return eventBus;
} }
@ -274,7 +276,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} }
@Override @Override
public DiscordConnectionManager discordConnectionManager() { public JDAConnectionManager discordConnectionManager() {
return discordConnectionManager; return discordConnectionManager;
} }
@ -384,7 +386,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
// Lifecycle // Lifecycle
protected CompletableFuture<Void> invokeLifecycle(CheckedRunnable runnable, String message, boolean enable) { protected CompletableFuture<Void> invokeLifecycle(CheckedRunnable runnable) {
return invoke(() -> { return invoke(() -> {
try { try {
lifecycleLock.lock(); lifecycleLock.lock();
@ -392,7 +394,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} finally { } finally {
lifecycleLock.unlock(); lifecycleLock.unlock();
} }
}, message, enable); }, "Failed to enable", true);
} }
protected CompletableFuture<Void> invoke(CheckedRunnable runnable, String message, boolean enable) { protected CompletableFuture<Void> invoke(CheckedRunnable runnable, String message, boolean enable) {
@ -406,21 +408,24 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} }
logger().error(message, t); logger().error(message, t);
} }
}, scheduler().executor()); }, scheduler().executorService());
} }
@Override @Override
public final CompletableFuture<Void> invokeEnable() { public final CompletableFuture<Void> invokeEnable() {
return invokeLifecycle(() -> { return enableFuture = invokeLifecycle(() -> {
this.enable(); this.enable();
waitForStatus(Status.CONNECTED); waitForStatus(Status.CONNECTED);
eventBus().publish(new DiscordSRVReadyEvent()); eventBus().publish(new DiscordSRVReadyEvent());
}, "Failed to enable", true); });
} }
@Override @Override
public final CompletableFuture<Void> invokeDisable() { public final CompletableFuture<Void> invokeDisable() {
return invokeLifecycle(this::disable, "Failed to disable", false); if (enableFuture != null && !enableFuture.isDone()) {
enableFuture.cancel(true);
}
return CompletableFuture.runAsync(this::disable, scheduler().executorService());
} }
@Override @Override
@ -469,6 +474,11 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} }
} }
protected final void startedMessage() {
registerModule(StartMessageModule::new);
registerModule(StopMessageModule::new);
}
private StorageType getStorageType() { private StorageType getStorageType() {
String backend = connectionConfig().storage.backend; String backend = connectionConfig().storage.backend;
switch (backend.toLowerCase(Locale.ROOT)) { switch (backend.toLowerCase(Locale.ROOT)) {
@ -487,6 +497,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} }
this.status.set(Status.SHUTTING_DOWN); this.status.set(Status.SHUTTING_DOWN);
eventBus().publish(new DiscordSRVShuttingDownEvent()); eventBus().publish(new DiscordSRVShuttingDownEvent());
eventBus().shutdown();
this.status.set(Status.SHUTDOWN); this.status.set(Status.SHUTDOWN);
} }
@ -574,7 +585,9 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
} else { } else {
discordConnectionManager.connect().get(); discordConnectionManager.connect().get();
} }
waitForStatus(Status.CONNECTED, 20, TimeUnit.SECONDS); if (!initial) {
waitForStatus(Status.CONNECTED, 20, TimeUnit.SECONDS);
}
} catch (ExecutionException e) { } catch (ExecutionException e) {
throw e.getCause(); throw e.getCause();
} }

View File

@ -30,7 +30,7 @@ import com.discordsrv.common.config.manager.MainConfigManager;
import com.discordsrv.common.console.Console; import com.discordsrv.common.console.Console;
import com.discordsrv.common.debug.data.OnlineMode; import com.discordsrv.common.debug.data.OnlineMode;
import com.discordsrv.common.discord.api.DiscordAPIImpl; import com.discordsrv.common.discord.api.DiscordAPIImpl;
import com.discordsrv.common.discord.connection.DiscordConnectionManager; import com.discordsrv.common.discord.connection.jda.JDAConnectionManager;
import com.discordsrv.common.linking.LinkProvider; import com.discordsrv.common.linking.LinkProvider;
import com.discordsrv.common.logging.Logger; import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.logging.impl.DiscordSRVLogger; import com.discordsrv.common.logging.impl.DiscordSRVLogger;
@ -50,7 +50,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -110,7 +111,7 @@ public interface DiscordSRV extends DiscordSRVApi {
ChannelConfigHelper channelConfig(); ChannelConfigHelper channelConfig();
// Internal // Internal
DiscordConnectionManager discordConnectionManager(); JDAConnectionManager discordConnectionManager();
// Modules // Modules
@Nullable @Nullable

View File

@ -0,0 +1,27 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 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.config.main.channels;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
public interface IMessageConfig {
boolean enabled();
SendableDiscordMessage.Builder format();
}

View File

@ -24,7 +24,7 @@ import com.discordsrv.common.config.annotation.Untranslated;
import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable @ConfigSerializable
public class JoinMessageConfig { public class JoinMessageConfig implements IMessageConfig {
public boolean enabled = true; public boolean enabled = true;
@ -36,4 +36,14 @@ public class JoinMessageConfig {
.setColor(0x55FF55) .setColor(0x55FF55)
.build() .build()
); );
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
} }

View File

@ -24,7 +24,7 @@ import com.discordsrv.common.config.annotation.Untranslated;
import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable @ConfigSerializable
public class LeaveMessageConfig { public class LeaveMessageConfig implements IMessageConfig {
public boolean enabled = true; public boolean enabled = true;
@ -36,4 +36,14 @@ public class LeaveMessageConfig {
.setColor(0xFF5555) .setColor(0xFF5555)
.build() .build()
); );
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
} }

View File

@ -28,7 +28,7 @@ import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ConfigSerializable @ConfigSerializable
public class MinecraftToDiscordChatConfig { public class MinecraftToDiscordChatConfig implements IMessageConfig {
@Comment("Is Minecraft to Discord chat forwarding enabled") @Comment("Is Minecraft to Discord chat forwarding enabled")
public boolean enabled = true; public boolean enabled = true;
@ -46,6 +46,16 @@ public class MinecraftToDiscordChatConfig {
@Comment("What mentions should be translated from chat messages to mentions (this does not effect if they will cause a notification or not)") @Comment("What mentions should be translated from chat messages to mentions (this does not effect if they will cause a notification or not)")
public Mentions mentions = new Mentions(); public Mentions mentions = new Mentions();
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
@ConfigSerializable @ConfigSerializable
public static class Mentions { public static class Mentions {

View File

@ -0,0 +1,43 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 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.config.main.channels;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.common.config.annotation.Untranslated;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class StartMessageConfig implements IMessageConfig {
public boolean enabled = true;
@Untranslated(Untranslated.Type.VALUE)
public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder()
.setContent(":arrow_forward: **The server has started**");
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
}

View File

@ -0,0 +1,43 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 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.config.main.channels;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.common.config.annotation.Untranslated;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class StopMessageConfig implements IMessageConfig {
public boolean enabled = true;
@Untranslated(Untranslated.Type.VALUE)
public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder()
.setContent(":pause_button: **The server has stopped**");
@Override
public boolean enabled() {
return enabled;
}
@Override
public SendableDiscordMessage.Builder format() {
return format;
}
}

View File

@ -31,6 +31,8 @@ public class BaseChannelConfig {
public DiscordToMinecraftChatConfig discordToMinecraft = new DiscordToMinecraftChatConfig(); public DiscordToMinecraftChatConfig discordToMinecraft = new DiscordToMinecraftChatConfig();
public JoinMessageConfig joinMessages = new JoinMessageConfig(); public JoinMessageConfig joinMessages = new JoinMessageConfig();
public LeaveMessageConfig leaveMessages = new LeaveMessageConfig(); public LeaveMessageConfig leaveMessages = new LeaveMessageConfig();
public StartMessageConfig startMessage = new StartMessageConfig();
public StopMessageConfig stopMessage = new StopMessageConfig();
@Order(10) @Order(10)
@Comment("Settings for synchronizing messages between the defined Discord channels and threads") @Comment("Settings for synchronizing messages between the defined Discord channels and threads")

View File

@ -159,8 +159,9 @@ public class DiscordAPIImpl implements DiscordAPI {
futures.add(future.handle((threadChannel, t) -> { futures.add(future.handle((threadChannel, t) -> {
if (t != null) { if (t != null) {
discordSRV.logger().error("Failed to deliver message to thread \"" discordSRV.discordConnectionManager().handleRequestFailure(
+ threadConfig.threadName + "\" in channel " + channel, t); "Failed to deliver message to thread \""
+ threadConfig.threadName + "\" in channel " + channel, t);
throw new RuntimeException(); // Just here to fail the future throw new RuntimeException(); // Just here to fail the future
} }

View File

@ -77,6 +77,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
} }
private final DiscordSRV discordSRV; private final DiscordSRV discordSRV;
private final DefaultFailureCallback defaultFailureCallback;
private ScheduledExecutorService gatewayPool; private ScheduledExecutorService gatewayPool;
private ScheduledExecutorService rateLimitPool; private ScheduledExecutorService rateLimitPool;
@ -94,9 +95,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
public JDAConnectionManager(DiscordSRV discordSRV) { public JDAConnectionManager(DiscordSRV discordSRV) {
this.discordSRV = discordSRV; this.discordSRV = discordSRV;
this.defaultFailureCallback = new DefaultFailureCallback(new NamedLogger(discordSRV, "DISCORD_REQUESTS"));
// Set default failure handling // Set default failure handling
RestAction.setDefaultFailure(new DefaultFailureCallback(new NamedLogger(discordSRV, "DISCORD_REQUESTS"))); RestAction.setDefaultFailure(defaultFailureCallback);
// Disable all mentions by default for safety // Disable all mentions by default for safety
AllowedMentions.setDefaultMentions(Collections.emptyList()); AllowedMentions.setDefaultMentions(Collections.emptyList());
@ -211,9 +213,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
throw new IllegalStateException("Cannot reconnect, still active"); throw new IllegalStateException("Cannot reconnect, still active");
} }
CompletableFuture<Void> future = CompletableFuture.runAsync(this::connectInternal, discordSRV.scheduler().executor()); return connectionFuture = CompletableFuture.runAsync(this::connectInternal, discordSRV.scheduler().executor());
connectionFuture = future;
return future;
} }
private void connectInternal() { private void connectInternal() {
@ -306,7 +306,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
try { try {
discordSRV.scheduler().run(() -> { discordSRV.scheduler().run(() -> {
try { try {
while (instance.getStatus() != JDA.Status.SHUTDOWN) { while (instance != null && instance.getStatus() != JDA.Status.SHUTDOWN) {
Thread.sleep(50); Thread.sleep(50);
} }
} catch (InterruptedException ignored) {} } catch (InterruptedException ignored) {}
@ -436,6 +436,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
discordSRV.logger().error("+------------------------------>"); discordSRV.logger().error("+------------------------------>");
} }
public void handleRequestFailure(String context, Throwable cause) {
defaultFailureCallback.accept(context, cause);
}
private class DefaultFailureCallback implements Consumer<Throwable> { private class DefaultFailureCallback implements Consumer<Throwable> {
private final Logger logger; private final Logger logger;
@ -446,6 +450,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
@Override @Override
public void accept(Throwable t) { public void accept(Throwable t) {
accept(null, t);
}
public void accept(String context, Throwable t) {
if ((t instanceof InterruptedIOException || t instanceof InterruptedException) if ((t instanceof InterruptedIOException || t instanceof InterruptedException)
&& discordSRV.status().isShutdown()) { && discordSRV.status().isShutdown()) {
// Ignore interrupted exceptions when DiscordSRV is shutting down or shutdown // Ignore interrupted exceptions when DiscordSRV is shutting down or shutdown
@ -460,7 +468,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
// Log route & retry after on warn & context on debug // Log route & retry after on warn & context on debug
RateLimitedException exception = ((RateLimitedException) t); RateLimitedException exception = ((RateLimitedException) t);
discordSRV.logger().warning("A request on route " + exception.getRateLimitedRoute() discordSRV.logger().warning("A request on route " + exception.getRateLimitedRoute()
+ " was rate-limited for " + exception.getRetryAfter() + "ms"); + " was rate-limited for " + exception.getRetryAfter() + "ms");
logger.debug(exception.getCause()); logger.debug(exception.getCause());
} else if (t instanceof ErrorResponseException) { } else if (t instanceof ErrorResponseException) {
ErrorResponseException exception = (ErrorResponseException) t; ErrorResponseException exception = (ErrorResponseException) t;
@ -471,7 +479,7 @@ public class JDAConnectionManager implements DiscordConnectionManager {
// Run the cause through this method again // Run the cause through this method again
accept(cause); accept(cause);
} else { } else {
logger.error("Failed to complete request for a unknown reason", exception); logger.error((context != null ? context + ": " : "") + "Failed to complete request for a unknown reason", exception);
} }
return; return;
} }
@ -520,8 +528,10 @@ public class JDAConnectionManager implements DiscordConnectionManager {
default: break; default: break;
} }
logger.error("Failed to complete a request: " + response.getMeaning()); logger.error((context != null ? context : "Failed to complete a request") + ": " + response.getMeaning());
logger.debug(exception); logger.debug(exception);
} else {
logger.error(context != null ? context : "Failed to complete a request due to unknown error", t);
} }
} }
} }

View File

@ -39,7 +39,10 @@ import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function; import java.util.function.Function;
@ -65,6 +68,11 @@ public class EventBusImpl implements EventBus {
subscribe(this); subscribe(this);
} }
public void shutdown() {
listeners.clear();
allListeners.clear();
}
@Override @Override
public void subscribe(@NotNull Object eventListener) { public void subscribe(@NotNull Object eventListener) {
if (listeners.containsKey(eventListener)) { if (listeners.containsKey(eventListener)) {

View File

@ -31,11 +31,13 @@ import com.discordsrv.api.placeholder.FormattedText;
import com.discordsrv.api.player.DiscordSRVPlayer; import com.discordsrv.api.player.DiscordSRVPlayer;
import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.component.util.ComponentUtil; import com.discordsrv.common.component.util.ComponentUtil;
import com.discordsrv.common.config.main.channels.IMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.base.IChannelConfig; import com.discordsrv.common.config.main.channels.base.IChannelConfig;
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageClusterImpl; import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageClusterImpl;
import com.discordsrv.common.function.OrDefault; import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.Logger; import com.discordsrv.common.future.util.CompletableFutureUtil;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.module.type.AbstractModule; import com.discordsrv.common.module.type.AbstractModule;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -46,47 +48,46 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
public abstract class AbstractGameMessageModule<T> extends AbstractModule<DiscordSRV> { public abstract class AbstractGameMessageModule<T extends IMessageConfig> extends AbstractModule<DiscordSRV> {
public AbstractGameMessageModule(DiscordSRV discordSRV, Logger logger) { public AbstractGameMessageModule(DiscordSRV discordSRV, String loggerName) {
super(discordSRV, logger); super(discordSRV, new NamedLogger(discordSRV, loggerName));
} }
public abstract OrDefault<T> mapConfig(OrDefault<BaseChannelConfig> channelConfig); public abstract OrDefault<T> mapConfig(OrDefault<BaseChannelConfig> channelConfig);
public abstract boolean isEnabled(OrDefault<T> config);
public abstract SendableDiscordMessage.Builder getFormat(OrDefault<T> config);
public abstract void postClusterToEventBus(ReceivedDiscordMessageCluster cluster); public abstract void postClusterToEventBus(ReceivedDiscordMessageCluster cluster);
public final void process( public final CompletableFuture<?> process(
@NotNull AbstractGameMessageReceiveEvent event, @Nullable AbstractGameMessageReceiveEvent event,
@NotNull DiscordSRVPlayer player, @Nullable DiscordSRVPlayer player,
@Nullable GameChannel channel @Nullable GameChannel channel
) { ) {
if (channel == null) { if (channel == null) {
// Send to all channels due to lack of specified channel // Send to all channels due to lack of specified channel
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (OrDefault<BaseChannelConfig> channelConfig : discordSRV.channelConfig().getAllChannels()) { for (OrDefault<BaseChannelConfig> channelConfig : discordSRV.channelConfig().getAllChannels()) {
forwardToChannel(event, player, channelConfig); futures.add(forwardToChannel(event, player, channelConfig));
} }
return; return CompletableFutureUtil.combine(futures);
} }
OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(channel); OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(channel);
forwardToChannel(event, player, channelConfig); return forwardToChannel(event, player, channelConfig);
} }
private void forwardToChannel( private CompletableFuture<Void> forwardToChannel(
@NotNull AbstractGameMessageReceiveEvent event, @Nullable AbstractGameMessageReceiveEvent event,
@NotNull DiscordSRVPlayer player, @Nullable DiscordSRVPlayer player,
@NotNull OrDefault<BaseChannelConfig> channelConfig @NotNull OrDefault<BaseChannelConfig> channelConfig
) { ) {
OrDefault<T> config = mapConfig(channelConfig); OrDefault<T> config = mapConfig(channelConfig);
if (!isEnabled(config)) { if (!config.get(IMessageConfig::enabled, true)) {
return; return null;
} }
IChannelConfig iChannelConfig = channelConfig.get(cfg -> cfg instanceof IChannelConfig ? (IChannelConfig) cfg : null); IChannelConfig iChannelConfig = channelConfig.get(cfg -> cfg instanceof IChannelConfig ? (IChannelConfig) cfg : null);
if (iChannelConfig == null) { if (iChannelConfig == null) {
return; return null;
} }
List<DiscordMessageChannel> messageChannels = new CopyOnWriteArrayList<>(); List<DiscordMessageChannel> messageChannels = new CopyOnWriteArrayList<>();
@ -108,13 +109,14 @@ public abstract class AbstractGameMessageModule<T> extends AbstractModule<Discor
discordSRV.discordAPI().findOrCreateThreads(iChannelConfig, messageChannels::add, futures); discordSRV.discordAPI().findOrCreateThreads(iChannelConfig, messageChannels::add, futures);
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete((v, t1) -> { return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete((v, t1) -> {
SendableDiscordMessage.Builder format = getFormat(config); SendableDiscordMessage.Builder format = config.get(IMessageConfig::format);
if (format == null) { if (format == null) {
return; return;
} }
String message = convertMessage(config, ComponentUtil.fromAPI(event.getMessage())); Component component = event != null ? ComponentUtil.fromAPI(event.getMessage()) : null;
String message = component != null ? convertMessage(config, component) : null;
Map<CompletableFuture<ReceivedDiscordMessage>, DiscordMessageChannel> messageFutures; Map<CompletableFuture<ReceivedDiscordMessage>, DiscordMessageChannel> messageFutures;
messageFutures = sendMessageToChannels( messageFutures = sendMessageToChannels(
config, format, messageChannels, message, config, format, messageChannels, message,
@ -129,7 +131,11 @@ public abstract class AbstractGameMessageModule<T> extends AbstractModule<Discor
CompletableFuture<ReceivedDiscordMessage> future = entry.getKey(); CompletableFuture<ReceivedDiscordMessage> future = entry.getKey();
if (future.isCompletedExceptionally()) { if (future.isCompletedExceptionally()) {
future.exceptionally(t -> { future.exceptionally(t -> {
discordSRV.logger().error("Failed to deliver a message to the " + entry.getValue() + " channel", t); if (t instanceof CompletionException) {
t = t.getCause();
}
discordSRV.discordConnectionManager().handleRequestFailure(
"Failed to deliver a message to " + entry.getValue(), t);
return null; return null;
}); });
// Ignore ones that failed // Ignore ones that failed
@ -140,7 +146,7 @@ public abstract class AbstractGameMessageModule<T> extends AbstractModule<Discor
messages.add(future.join()); messages.add(future.join());
} }
if (message.isEmpty()) { if (messages.isEmpty()) {
// Nothing was delivered // Nothing was delivered
return; return;
} }

View File

@ -19,7 +19,6 @@
package com.discordsrv.common.messageforwarding.game; package com.discordsrv.common.messageforwarding.game;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.api.event.bus.EventPriority; import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe; import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.message.forward.game.JoinMessageForwardedEvent; import com.discordsrv.api.event.events.message.forward.game.JoinMessageForwardedEvent;
@ -28,12 +27,11 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.JoinMessageConfig; import com.discordsrv.common.config.main.channels.JoinMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault; import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
public class JoinMessageModule extends AbstractGameMessageModule<JoinMessageConfig> { public class JoinMessageModule extends AbstractGameMessageModule<JoinMessageConfig> {
public JoinMessageModule(DiscordSRV discordSRV) { public JoinMessageModule(DiscordSRV discordSRV) {
super(discordSRV, new NamedLogger(discordSRV, "JOIN_MESSAGES")); super(discordSRV, "JOIN_MESSAGES");
} }
@Override @Override
@ -41,16 +39,6 @@ public class JoinMessageModule extends AbstractGameMessageModule<JoinMessageConf
return channelConfig.map(cfg -> cfg.joinMessages); return channelConfig.map(cfg -> cfg.joinMessages);
} }
@Override
public boolean isEnabled(OrDefault<JoinMessageConfig> config) {
return config.get(cfg -> cfg.enabled, true);
}
@Override
public SendableDiscordMessage.Builder getFormat(OrDefault<JoinMessageConfig> config) {
return config.get(cfg -> cfg.format);
}
@Override @Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) { public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {
discordSRV.eventBus().publish(new JoinMessageForwardedEvent(cluster)); discordSRV.eventBus().publish(new JoinMessageForwardedEvent(cluster));

View File

@ -19,7 +19,6 @@
package com.discordsrv.common.messageforwarding.game; package com.discordsrv.common.messageforwarding.game;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster; import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import com.discordsrv.api.event.bus.EventPriority; import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe; import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.message.forward.game.LeaveMessageForwardedEvent; import com.discordsrv.api.event.events.message.forward.game.LeaveMessageForwardedEvent;
@ -28,12 +27,11 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.LeaveMessageConfig; import com.discordsrv.common.config.main.channels.LeaveMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault; import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
public class LeaveMessageModule extends AbstractGameMessageModule<LeaveMessageConfig> { public class LeaveMessageModule extends AbstractGameMessageModule<LeaveMessageConfig> {
public LeaveMessageModule(DiscordSRV discordSRV) { public LeaveMessageModule(DiscordSRV discordSRV) {
super(discordSRV, new NamedLogger(discordSRV, "LEAVE_MESSAGES")); super(discordSRV, "LEAVE_MESSAGES");
} }
@Override @Override
@ -41,16 +39,6 @@ public class LeaveMessageModule extends AbstractGameMessageModule<LeaveMessageCo
return channelConfig.map(cfg -> cfg.leaveMessages); return channelConfig.map(cfg -> cfg.leaveMessages);
} }
@Override
public boolean isEnabled(OrDefault<LeaveMessageConfig> config) {
return config.get(cfg -> cfg.enabled, true);
}
@Override
public SendableDiscordMessage.Builder getFormat(OrDefault<LeaveMessageConfig> config) {
return config.get(cfg -> cfg.format);
}
@Override @Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) { public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {
discordSRV.eventBus().publish(new LeaveMessageForwardedEvent(cluster)); discordSRV.eventBus().publish(new LeaveMessageForwardedEvent(cluster));

View File

@ -37,7 +37,6 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.MinecraftToDiscordChatConfig; import com.discordsrv.common.config.main.channels.MinecraftToDiscordChatConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig; import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault; import com.discordsrv.common.function.OrDefault;
import com.discordsrv.common.logging.NamedLogger;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildChannel; import net.dv8tion.jda.api.entities.GuildChannel;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
@ -66,7 +65,7 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
private final Map<Long, Map<Long, CachedMention>> channelMentions = new ConcurrentHashMap<>(); private final Map<Long, Map<Long, CachedMention>> channelMentions = new ConcurrentHashMap<>();
public MinecraftToDiscordChatModule(DiscordSRV discordSRV) { public MinecraftToDiscordChatModule(DiscordSRV discordSRV) {
super(discordSRV, new NamedLogger(discordSRV, "MINECRAFT_TO_DISCORD")); super(discordSRV, "MINECRAFT_TO_DISCORD");
} }
@Override @Override
@ -91,16 +90,6 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
return channelConfig.map(cfg -> cfg.minecraftToDiscord); return channelConfig.map(cfg -> cfg.minecraftToDiscord);
} }
@Override
public boolean isEnabled(OrDefault<MinecraftToDiscordChatConfig> config) {
return config.get(cfg -> cfg.enabled, true);
}
@Override
public SendableDiscordMessage.Builder getFormat(OrDefault<MinecraftToDiscordChatConfig> config) {
return config.get(cfg -> cfg.format);
}
@Override @Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) { public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {
discordSRV.eventBus().publish(new GameChatMessageForwardedEvent(cluster)); discordSRV.eventBus().publish(new GameChatMessageForwardedEvent(cluster));

View File

@ -0,0 +1,45 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 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.messageforwarding.game;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.StartMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
public class StartMessageModule extends AbstractGameMessageModule<StartMessageConfig> {
public StartMessageModule(DiscordSRV discordSRV) {
super(discordSRV, "START_MESSAGE");
}
@Override
public OrDefault<StartMessageConfig> mapConfig(OrDefault<BaseChannelConfig> channelConfig) {
return channelConfig.map(cfg -> cfg.startMessage);
}
@Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {}
@Override
public void enable() {
process(null, null, null);
}
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 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.messageforwarding.game;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.StopMessageConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.function.OrDefault;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class StopMessageModule extends AbstractGameMessageModule<StopMessageConfig> {
public StopMessageModule(DiscordSRV discordSRV) {
super(discordSRV, "START_MESSAGE");
}
@Override
public OrDefault<StopMessageConfig> mapConfig(OrDefault<BaseChannelConfig> channelConfig) {
return channelConfig.map(cfg -> cfg.stopMessage);
}
@Override
public void postClusterToEventBus(ReceivedDiscordMessageCluster cluster) {}
@Override
public void disable() {
try {
process(null, null, null).get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger().error("Failed to queue stop message to be sent within 5 seconds.");
} catch (InterruptedException | ExecutionException ignored) {}
}
}

View File

@ -118,7 +118,9 @@ public class ModuleManager {
throw new IllegalArgumentException("Cannot unregister a delegate"); throw new IllegalArgumentException("Cannot unregister a delegate");
} }
disable(module); if (getAbstract(module).isHasBeenEnabled()) {
disable(module);
}
this.modules.remove(module); this.modules.remove(module);
this.moduleLookupTable.values().removeIf(mod -> mod == module); this.moduleLookupTable.values().removeIf(mod -> mod == module);

View File

@ -44,6 +44,10 @@ public abstract class AbstractModule<DT extends DiscordSRV> implements Module {
return logger; return logger;
} }
public boolean isHasBeenEnabled() {
return hasBeenEnabled;
}
public final boolean enableModule() { public final boolean enableModule() {
if (hasBeenEnabled || !isEnabled()) { if (hasBeenEnabled || !isEnabled()) {
return false; return false;