Even more fixes

Actually made the channel data return a Mono and used that
Used the read only config stuff
#93
This commit is contained in:
Norbi Peti 2019-05-04 03:11:03 +02:00
parent 4881f6bdd2
commit b68456e6f4
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
9 changed files with 98 additions and 70 deletions

View file

@ -4,7 +4,11 @@ import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.IHaveConfig;
import discord4j.core.object.entity.*;
import buttondevteam.lib.architecture.ReadOnlyConfigData;
import discord4j.core.object.entity.Guild;
import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.entity.Role;
import discord4j.core.object.util.Snowflake;
import discord4j.core.spec.EmbedCreateSpec;
import lombok.val;
@ -56,43 +60,36 @@ public final class DPUtils {
return DiscordPlugin.plugin.getLogger();
}
public static ConfigData<MessageChannel> channelData(IHaveConfig config, String key, long defID) {
return config.getDataPrimDef(key, defID, id -> {
Channel ch = DiscordPlugin.dc.getChannelById(Snowflake.of((long) id)).onErrorResume(e -> {
getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage());
return Mono.empty();
}).block();
if (ch instanceof MessageChannel)
return (MessageChannel) ch;
else
return null;
}, ch -> ch.getId().asLong()); //We can afford to search for the channel in the cache once (instead of using mainServer)
public static ReadOnlyConfigData<Mono<MessageChannel>> channelData(IHaveConfig config, String key, long defID) {
return config.getReadOnlyDataPrimDef(key, defID, id -> getMessageChannel(key, Snowflake.of((Long) id)), ch -> defID); //We can afford to search for the channel in the cache once (instead of using mainServer)
}
public static ConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName) {
public static ReadOnlyConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName) {
return roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer));
}
/**
* Needs to be a {@link ConfigData} for checking if it's set
*/
public static ConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName, Mono<Guild> guild) {
return config.getDataPrimDef(key, defName, name -> {
public static ReadOnlyConfigData<Mono<Role>> roleData(IHaveConfig config, String key, String defName, Mono<Guild> guild) {
return config.getReadOnlyDataPrimDef(key, defName, name -> {
if (!(name instanceof String)) return Mono.empty();
return guild.flatMapMany(Guild::getRoles).filter(r -> r.getName().equals(name)).last();
}, r -> defName);
}
public static ConfigData<Snowflake> snowflakeData(IHaveConfig config, String key, long defID) {
return config.getDataPrimDef(key, defID, id -> Snowflake.of((long) id), Snowflake::asLong);
}
/**
* Mentions the <b>bot channel</b>. Useful for help texts.
*
* @return The string for mentioning the channel
*/
public static String botmention() {
Channel channel;
if (DiscordPlugin.plugin == null
|| (channel = DiscordPlugin.plugin.CommandChannel().get()) == null) return "#bot";
return channel.getMention();
if (DiscordPlugin.plugin == null) return "#bot";
return channelMention(DiscordPlugin.plugin.CommandChannel().get());
}
/**
@ -104,14 +101,14 @@ public final class DPUtils {
*/
public static boolean disableIfConfigError(@Nullable Component<DiscordPlugin> component, ConfigData<?>... configs) {
for (val config : configs) {
if (config.get() == null) {
Object v = config.get();
//noinspection ConstantConditions
if (v == null || (v instanceof Mono<?> && !((Mono<?>) v).hasElement().block())) {
String path = null;
try {
if (component != null)
Component.setComponentEnabled(component, false);
val f = ConfigData.class.getDeclaredField("path");
f.setAccessible(true); //Hacking my own plugin
path = (String) f.get(config);
path = config.getPath();
} catch (Exception e) {
TBMCCoreAPI.SendException("Failed to disable component after config error!", e);
}
@ -137,4 +134,15 @@ public final class DPUtils {
return "<@!" + userId.asString() + ">";
}
public static String channelMention(Snowflake channelId) {
return "<#" + channelId.asString() + ">";
}
public static Mono<MessageChannel> getMessageChannel(String key, Snowflake id) {
return DiscordPlugin.dc.getChannelById(id).onErrorResume(e -> {
getLogger().warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage());
return Mono.empty();
}).filter(ch -> ch instanceof MessageChannel).cast(MessageChannel.class);
}
}

View file

@ -24,7 +24,6 @@ import discord4j.core.DiscordClientBuilder;
import discord4j.core.event.domain.guild.GuildCreateEvent;
import discord4j.core.event.domain.lifecycle.ReadyEvent;
import discord4j.core.object.entity.Guild;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.entity.Role;
import discord4j.core.object.presence.Activity;
import discord4j.core.object.presence.Presence;
@ -68,8 +67,8 @@ public class DiscordPlugin extends ButtonPlugin {
return getIConfig().getDataPrimDef("mainServer", 219529124321034241L, id -> dc.getGuildById(Snowflake.of((long) id)).block(), g -> g.getId().asLong());
}
public ConfigData<MessageChannel> CommandChannel() {
return DPUtils.channelData(getIConfig(), "commandChannel", 239519012529111040L);
public ConfigData<Snowflake> CommandChannel() {
return DPUtils.snowflakeData(getIConfig(), "commandChannel", 239519012529111040L);
}
public ConfigData<Mono<Role>> ModRole() {
@ -210,7 +209,9 @@ public class DiscordPlugin extends ButtonPlugin {
@Override
public void pluginPreDisable() {
if (ChromaBot.getInstance() == null) return; //Failed to load
System.out.println("Disable start");
MCChatUtils.forCustomAndAllMCChat(ch -> ch.createEmbed(ecs -> {
System.out.println("Sending message to " + ch.getMention());
if (DiscordMCCommand.resetting)
ecs.setColor(Color.ORANGE).setTitle("Discord plugin restarting");
else
@ -225,12 +226,16 @@ public class DiscordPlugin extends ButtonPlugin {
+ "kicked the hell out.") //TODO: Make configurable
: ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled
}).block(), ChannelconBroadcast.RESTART, false);
System.out.println("Updating player list");
ChromaBot.getInstance().updatePlayerList();
System.out.println("Done");
}
@Override
public void pluginDisable() {
System.out.println("Actual disable start (logout)");
MCChatPrivate.logoutAll();
System.out.println("Config setup");
getConfig().set("serverup", false);
if (ChromaBot.getInstance() == null) return; //Failed to load
@ -238,7 +243,9 @@ public class DiscordPlugin extends ButtonPlugin {
try {
SafeMode = true; // Stop interacting with Discord
ChromaBot.delete();
System.out.println("Updating presence...");
dc.updatePresence(Presence.idle(Activity.playing("Chromacraft"))).block(); //No longer using the same account for testing
System.out.println("Logging out...");
dc.logout().block();
//Configs are emptied so channels and servers are fetched again
} catch (Exception e) {

View file

@ -6,6 +6,7 @@ import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ReadOnlyConfigData;
import buttondevteam.lib.player.ChromaGamerBase;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@ -16,19 +17,22 @@ import discord4j.core.object.entity.MessageChannel;
import lombok.val;
import org.bukkit.configuration.file.YamlConfiguration;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.io.File;
import java.util.Objects;
public class AnnouncerModule extends Component<DiscordPlugin> {
/**
* Channel to post new posts.
*/
public ConfigData<MessageChannel> channel() {
public ReadOnlyConfigData<Mono<MessageChannel>> channel() {
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
}
public ConfigData<MessageChannel> modChannel() {
/**
* Channel where distinguished (moderator) posts go.
*/
public ReadOnlyConfigData<Mono<MessageChannel>> modChannel() {
return DPUtils.channelData(getConfig(), "modChannel", 239519012529111040L);
}
@ -56,8 +60,7 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
stop = false; //If not the first time
val keepPinned = keepPinned().get();
if (keepPinned == 0) return;
val channel = channel().get();
Flux<Message> msgs = channel.getPinnedMessages();
Flux<Message> msgs = channel().get().flatMapMany(MessageChannel::getPinnedMessages);
msgs.subscribe(Message::unpin);
val yc = YamlConfiguration.loadConfiguration(new File("plugins/DiscordPlugin", "config.yml")); //Name change
if (lastannouncementtime().get() == 0) //Load old data
@ -118,9 +121,11 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
}
}
if (msgsb.length() > 0)
Objects.requireNonNull(channel().get().createMessage(msgsb.toString()).block()).pin().block();
channel().get().flatMap(ch -> ch.createMessage(msgsb.toString()))
.flatMap(Message::pin).subscribe();
if (modmsgsb.length() > 0)
modChannel().get().createMessage(modmsgsb.toString()).block();
modChannel().get().flatMap(ch -> ch.createMessage(modmsgsb.toString()))
.flatMap(Message::pin).subscribe();
if (lastannouncementtime().get() != lastanntime)
lastannouncementtime().set(lastanntime); // If sending succeeded
} catch (Exception e) {

View file

@ -7,6 +7,7 @@ import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.TBMCExceptionEvent;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ReadOnlyConfigData;
import discord4j.core.object.entity.Guild;
import discord4j.core.object.entity.GuildChannel;
import discord4j.core.object.entity.MessageChannel;
@ -49,7 +50,7 @@ public class ExceptionListenerModule extends Component<DiscordPlugin> implements
private static void SendException(Throwable e, String sourcemessage) {
if (instance == null) return;
try {
MessageChannel channel = getChannel();
Mono<MessageChannel> channel = getChannel();
assert channel != null;
Mono<Role> coderRole;
if (channel instanceof GuildChannel)
@ -69,7 +70,7 @@ public class ExceptionListenerModule extends Component<DiscordPlugin> implements
stackTrace = stackTrace.substring(0, 1999 - sb.length());
sb.append(stackTrace).append("\n");
sb.append("```");
return channel.createMessage(sb.toString());
return channel.flatMap(ch -> ch.createMessage(sb.toString()));
}).subscribe();
} catch (Exception ex) {
ex.printStackTrace();
@ -78,12 +79,12 @@ public class ExceptionListenerModule extends Component<DiscordPlugin> implements
private static ExceptionListenerModule instance;
public static MessageChannel getChannel() {
public static Mono<MessageChannel> getChannel() {
if (instance != null) return instance.channel().get();
return null;
return Mono.empty();
}
private ConfigData<MessageChannel> channel() {
private ReadOnlyConfigData<Mono<MessageChannel>> channel() {
return DPUtils.channelData(getConfig(), "channel", 239519012529111040L);
}

View file

@ -6,6 +6,7 @@ import buttondevteam.discordplugin.DiscordPlugin;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ReadOnlyConfigData;
import com.google.common.collect.Lists;
import discord4j.core.event.domain.PresenceUpdateEvent;
import discord4j.core.object.entity.*;
@ -120,34 +121,33 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
}
private ConfigData<MessageChannel> fullHouseChannel() {
private ReadOnlyConfigData<Mono<MessageChannel>> fullHouseChannel() {
return DPUtils.channelData(getConfig(), "fullHouseChannel", 219626707458457603L);
}
private static long lasttime = 0;
@SuppressWarnings("ConstantConditions")
public static void handleFullHouse(PresenceUpdateEvent event) {
val fm = ComponentManager.getIfEnabled(FunModule.class);
if (fm == null) return;
val channel = fm.fullHouseChannel().get();
if (channel == null) return;
if (!(channel instanceof GuildChannel)) return;
val devrole = fm.fullHouseDevRole(((GuildChannel) channel).getGuild()).get();
if (devrole == null) return;
if (event.getOld().map(p -> p.getStatus().equals(Status.OFFLINE)).orElse(false)
&& !event.getCurrent().getStatus().equals(Status.OFFLINE)
&& event.getMember().flatMap(m -> devrole.flatMap(dr -> m.getRoles()
.any(r -> r.getId().asLong() == dr.getId().asLong()))).block()
&& event.getGuild().flatMap(g -> devrole.flatMapMany(dr -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(dr.getId()))))
.flatMap(Member::getPresence).all(pr -> !pr.getStatus().equals(Status.OFFLINE))).block()
&& lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime())
&& Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 == 0) {
channel.createMessage(mcs -> mcs.setContent("Full house!").setEmbed(ecs ->
ecs.setImage(
"https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
)).subscribe();
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime());
}
if (Calendar.getInstance().get(Calendar.DAY_OF_MONTH) % 5 != 0) return;
fm.fullHouseChannel().get()
.filter(ch -> ch instanceof GuildChannel)
.flatMap(channel -> fm.fullHouseDevRole(((GuildChannel) channel).getGuild()).get()
.filter(role -> event.getOld().map(p -> p.getStatus().equals(Status.OFFLINE)).orElse(false))
.filter(role -> !event.getCurrent().getStatus().equals(Status.OFFLINE))
.filterWhen(devrole -> event.getMember().flatMap(m -> m.getRoles()
.any(r -> r.getId().asLong() == devrole.getId().asLong())))
.filterWhen(devrole ->
event.getGuild().flatMapMany(g -> g.getMembers().filter(m -> m.getRoleIds().stream().anyMatch(s -> s.equals(devrole.getId()))))
.flatMap(Member::getPresence).all(pr -> !pr.getStatus().equals(Status.OFFLINE)))
.filter(devrole -> lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime())) //This should stay so it checks this last
.flatMap(devrole -> {
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime());
return channel.createMessage(mcs -> mcs.setContent("Full house!").setEmbed(ecs ->
ecs.setImage(
"https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
));
})).subscribe();
}
}

View file

@ -27,7 +27,7 @@ public class CommandListener {
if (!mentionedonly) { //mentionedonly conditions are in CommonListeners
if (!(channel instanceof PrivateChannel)
&& !(content.charAt(0) == DiscordPlugin.getPrefix()
&& channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().getId().asString()))) //
&& channel.getId().asString().equals(DiscordPlugin.plugin.CommandChannel().get().asString()))) //
return false;
channel.type().subscribe(); // Fun
}

View file

@ -40,7 +40,7 @@ public class CommonListeners {
try {
boolean handled = false;
val commandChannel = DiscordPlugin.plugin.CommandChannel().get();
if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.getId().asLong()) //If mentioned, that's higher than chat
if ((commandChannel != null && event.getMessage().getChannelId().asLong() == commandChannel.asLong()) //If mentioned, that's higher than chat
|| event.getMessage().getContent().orElse("").contains("channelcon")) //Only 'channelcon' is allowed in other channels
handled = CommandListener.runCommand(event.getMessage(), true); //#bot is handled here
if (handled) return;

View file

@ -17,6 +17,7 @@ import com.vdurmont.emoji.EmojiParser;
import discord4j.core.event.domain.message.MessageCreateEvent;
import discord4j.core.object.Embed;
import discord4j.core.object.entity.*;
import discord4j.core.object.util.Snowflake;
import discord4j.core.spec.EmbedCreateSpec;
import lombok.val;
import org.bukkit.Bukkit;
@ -110,17 +111,17 @@ public class MCChatListener implements Listener {
};
// Checks if the given channel is different than where the message was sent from
// Or if it was from MC
Predicate<MessageChannel> isdifferentchannel = ch -> !(e.getSender() instanceof DiscordSenderBase)
|| ((DiscordSenderBase) e.getSender()).getChannel().getId().asLong() != ch.getId().asLong();
Predicate<Snowflake> isdifferentchannel = id -> !(e.getSender() instanceof DiscordSenderBase)
|| ((DiscordSenderBase) e.getSender()).getChannel().getId().asLong() != id.asLong();
if (e.getChannel().isGlobal()
&& (e.isFromCommand() || isdifferentchannel.test(module.chatChannel().get())))
doit.accept(MCChatUtils.lastmsgdata == null
? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannel().get(), null)
? MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono().block(), null)
: MCChatUtils.lastmsgdata);
for (MCChatUtils.LastMsgData data : MCChatPrivate.lastmsgPerUser) {
if ((e.isFromCommand() || isdifferentchannel.test(data.channel))
if ((e.isFromCommand() || isdifferentchannel.test(data.channel.getId()))
&& e.shouldSendTo(MCChatUtils.getSender(data.channel.getId(), data.user)))
doit.accept(data);
}
@ -128,7 +129,7 @@ public class MCChatListener implements Listener {
val iterator = MCChatCustom.lastmsgCustom.iterator();
while (iterator.hasNext()) {
val lmd = iterator.next();
if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel)) //Test if msg is from Discord
if ((e.isFromCommand() || isdifferentchannel.test(lmd.channel.getId())) //Test if msg is from Discord
&& e.getChannel().ID.equals(lmd.mcchannel.ID) //If it's from a command, the command msg has been deleted, so we need to send it
&& e.getGroupID().equals(lmd.groupID)) { //Check if this is the group we want to test - #58
if (e.shouldSendTo(lmd.dcp)) //Check original user's permissions
@ -222,7 +223,7 @@ public class MCChatListener implements Listener {
val author = ev.getMessage().getAuthor();
final boolean hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage().getChannelId());
val channel = ev.getMessage().getChannel().block();
if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().getId().asLong()
if (ev.getMessage().getChannelId().asLong() != module.chatChannel().get().asLong()
&& !(channel instanceof PrivateChannel
&& author.map(u -> MCChatPrivate.isMinecraftChatEnabled(u.getId().asString())).orElse(false)
&& !hasCustomChat))

View file

@ -8,12 +8,14 @@ import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.architecture.ReadOnlyConfigData;
import com.google.common.collect.Lists;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.util.Snowflake;
import lombok.Getter;
import lombok.val;
import org.bukkit.Bukkit;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Objects;
@ -42,14 +44,18 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
/**
* The channel to use as the public Minecraft chat - everything public gets broadcasted here
*/
public ConfigData<MessageChannel> chatChannel() {
return DPUtils.channelData(getConfig(), "chatChannel", 239519012529111040L);
public ConfigData<Snowflake> chatChannel() {
return DPUtils.snowflakeData(getConfig(), "chatChannel", 239519012529111040L);
}
public Mono<MessageChannel> chatChannelMono() {
return DPUtils.getMessageChannel(chatChannel().getPath(), chatChannel().get());
}
/**
* The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute
*/
public ConfigData<MessageChannel> modlogChannel() {
public ReadOnlyConfigData<Mono<MessageChannel>> modlogChannel() {
return DPUtils.channelData(getConfig(), "modlogChannel", 283840717275791360L);
}