discord-jda / JDA

Java wrapper for the popular chat & VOIP service: Discord https://discord.com
Apache License 2.0
4.34k stars 735 forks source link

only sending an empty String for a MessageAction doesn't do anything #1366

Closed Andre601 closed 4 years ago

Andre601 commented 4 years ago

General Troubleshooting

Bug Report

When only sending an empty String (TextChannel#sendMessage("").queue();) does JDA handle it like normal without any errors or similar, while Discord doesn't send/display any message whatsoever on the client's side.

Expected Behavior

JDA shouldn't allow the sending of an empty String as the only content and instead give a warning or even an exception.

Code Example or Reproduction Steps

public class MessageListener extends ListenerAdabter {

    public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) {
        // Prevents spam.
        if(event.getAuthor().isBot())
            return;

        // Send an empty String as the only content.
        event.getChannel().sendMessage("").queue();
    }
}

Code for JDABuilder or DefaultShardManagerBuilder Used

N/A

Exception or Error

N/A

sebm253 commented 4 years ago

Can't repro this on 4.2.0_189:

MinnDevelopment commented 4 years ago

https://github.com/DV8FromTheWorld/JDA/blob/3a9fcd0ecc88f988ac81eb2c18527283a83f12d1/src/main/java/net/dv8tion/jda/api/entities/MessageChannel.java#L342

Andre601 commented 4 years ago

Could this be related to executing stuff on a callback?

I execute a void which handles responses through the success consumer of the queue method and also have a method which either returns a String from a config file, or an empty string when the path is invalid or the file doesn't exits...

It strangely always happened when the path was invalid. No exception in terminal and the message doesn't display on the client, so maybe the terminal "eats" the exception (Although it usually shouldn't).

Or perhaps this is caused by another lib (In my case probs JDA Utilities)? I have to investigate this...

MinnDevelopment commented 4 years ago

Closing since I can't reproduce an issue and the code already handles empty strings:

https://github.com/DV8FromTheWorld/JDA/blob/3a9fcd0ecc88f988ac81eb2c18527283a83f12d1/src/main/java/net/dv8tion/jda/api/entities/MessageChannel.java#L342

https://github.com/DV8FromTheWorld/JDA/blob/3a9fcd0ecc88f988ac81eb2c18527283a83f12d1/src/main/java/net/dv8tion/jda/internal/requests/restaction/MessageActionImpl.java#L555

https://github.com/DV8FromTheWorld/JDA/blob/3a9fcd0ecc88f988ac81eb2c18527283a83f12d1/src/main/java/net/dv8tion/jda/internal/requests/restaction/MessageActionImpl.java#L127

It's most likely an issue on your end which just doesn't handle the exception.

Andre601 commented 4 years ago

Looking at the code I use do I also see no reason why the exception is not shown in the terminal.

The method used:

    private void handleEvent(Message message, Member author, Member target){
        Guild guild = message.getGuild();
        // getQueueString returns "authorId:guildId"
        queue.put(bot.getMessageUtil().getQueueString(author), target.getId());

        EventWaiter waiter = bot.getWaiter();
        waiter.waitForEvent(
                GuildMessageReactionAddEvent.class,
                event -> {
                    MessageReaction.ReactionEmote emote = event.getReactionEmote();
                    if(!emote.isEmote())
                        return false;

                    if(!emote.getId().equals(Emotes.ACCEPT.getId()) && !emote.getId().equals(Emotes.CANCEL.getId()))
                        return false;

                    if(event.getUser().isBot())
                        return false;

                    if(!event.getMember().equals(target))
                        return false;

                    return event.getMessageId().equals(message.getId());
                },
                event -> {
                    // This code in here executes fine and as expected.
                },
                1, TimeUnit.MINUTES,
                () -> {
                    TextChannel channel = message.getTextChannel();
                    message.delete().queue(null, ignore(UNKNOWN_MESSAGE));
                    queue.invalidate(bot.getMessageUtil().getQueueString(author));

                    channel.sendMessage(MarkdownSanitizer.escape(
                            bot.getMsg(
                                    guild.getId(),
                                    "purr.fun.hug.request.timedout", // This line is a invalid path
                                    author.getAsMention(),
                                    target.getEffectiveName()
                            )
                    )).queue();
                }
        );
    }

The getMsg(String, String, ...) method is a shortcut to the FileManager's getString method:

    public String getString(String name, String path){
        File file = files.get(name);

        if(file == null)
            return "";

        try{
            JsonReader reader = new JsonReader(new FileReader(file));
            JsonElement json = JsonParser.parseReader(reader);

            for(String key : path.split("\\.")){
                if(!json.isJsonObject())
                    break;

                json = json.getAsJsonObject().get(key);
            }

            if(json == null || json.isJsonNull())
                return "";

            return json.getAsString();
        }catch(FileNotFoundException ex){
            logger.warn("Could not find file " + name + ".json", ex);
            return "";
        }
    }

As you can see would the method return an empty String when the file doesn't exist, or the path is in some way invalid. So theoretically should JDA throw an error, which is strangely doesn't. The terminal itself is set to normal level. No debug, no ommiting of stacktraces or similar.

And as mentioned before does the handleEvent void get called in the success consumer of another queue method, which shouldn't affect this, right?

MinnDevelopment commented 4 years ago

The timeout runnable seems to run in a ScheduledExecutorService which, by default, ignores all exceptions being thrown. You can use Thread.setDefaultUncaughtExceptionHandler to handle this.