Search in sources :

Example 1 with UserException

use of net.robinfriedli.aiode.exceptions.UserException in project aiode by robinfriedli.

the class CommandListener method startCommandExecution.

private void startCommandExecution(String namePrefix, Message message, Guild guild, GuildContext guildContext, Session session, GuildMessageReceivedEvent event) {
    ThreadExecutionQueue queue = executionQueueManager.getForGuild(guild);
    String commandBody = message.getContentDisplay().substring(namePrefix.length()).trim();
    CommandContext commandContext = new CommandContext(event, guildContext, hibernateComponent.getSessionFactory(), spotifyApiBuilder, commandBody);
    ExecutionContext.Current.set(commandContext.fork());
    try {
        Optional<AbstractCommand> commandInstance = commandManager.instantiateCommandForContext(commandContext, session);
        commandInstance.ifPresent(command -> commandManager.runCommand(command, queue));
    } catch (UserException e) {
        EmbedBuilder embedBuilder = e.buildEmbed();
        messageService.sendTemporary(embedBuilder.build(), commandContext.getChannel());
    }
}
Also used : EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) CommandContext(net.robinfriedli.aiode.command.CommandContext) ThreadExecutionQueue(net.robinfriedli.aiode.concurrent.ThreadExecutionQueue) AbstractCommand(net.robinfriedli.aiode.command.AbstractCommand) UserException(net.robinfriedli.aiode.exceptions.UserException)

Example 2 with UserException

use of net.robinfriedli.aiode.exceptions.UserException in project aiode by robinfriedli.

the class LoginCommand method doRun.

@Override
public void doRun() {
    User user = getContext().getUser();
    AuthorizationCodeUriRequest uriRequest = getContext().getSpotifyApi().authorizationCodeUri().show_dialog(true).state(user.getId()).scope("playlist-read-private playlist-read-collaborative user-library-read playlist-modify-private playlist-modify-public").build();
    LoginManager loginManager = Aiode.get().getLoginManager();
    CompletableFuture<Login> pendingLogin = new CompletableFuture<>();
    loginManager.expectLogin(user, pendingLogin);
    String loginUri = uriRequest.execute().toString();
    EmbedBuilder loginLinkBuilder = new EmbedBuilder().setTitle("Spotify login").setDescription(String.format("Click [here](%s) to be redirected to Spotify", loginUri)).setColor(0x1DB954);
    CompletableFuture<Message> futurePrivateMessage = getMessageService().send(loginLinkBuilder.build(), user);
    CompletableFuture<Message> futureNoticeMessage = new CompletableFuture<>();
    try {
        futurePrivateMessage.get();
        EmbedBuilder embedBuilder = new EmbedBuilder();
        embedBuilder.setDescription("I have sent you a login link");
        sendMessage(embedBuilder).thenAccept(futureNoticeMessage::complete);
    } catch (CancellationException | ExecutionException e) {
        loginManager.removePendingLogin(user);
        throw new UserException("I was unable to send you a message. Please adjust your privacy settings to allow direct messages from guild members.");
    } catch (InterruptedException ignored) {
    }
    CompletableFuture<Login> futureLogin = pendingLogin.orTimeout(10, TimeUnit.MINUTES);
    CompletableFutures.handleWhenComplete(futureLogin, (login, throwable) -> {
        futureNoticeMessage.thenAccept(message -> message.delete().queue());
        futurePrivateMessage.thenAccept(message -> message.delete().queue());
        if (login != null) {
            getMessageService().sendSuccess("You have successfully connected your Spotify account and may now search and play tracks from your library", user);
            sendSuccess("User " + getContext().getUser().getName() + " logged in to Spotify");
        }
        if (throwable != null) {
            loginManager.removePendingLogin(user);
            if (throwable instanceof TimeoutException) {
                getMessageService().sendError("Login attempt timed out", user);
            } else {
                getMessageService().sendException("There has been an unexpected error while completing your login, please try again.", getContext().getChannel());
                LoggerFactory.getLogger(getClass()).error("unexpected exception while completing login", throwable);
            }
            setFailed(true);
        }
    }, e -> LoggerFactory.getLogger(getClass()).error("Unexpected error in whenComplete of pending login handler", e));
}
Also used : User(net.dv8tion.jda.api.entities.User) LoginManager(net.robinfriedli.aiode.login.LoginManager) Message(net.dv8tion.jda.api.entities.Message) AuthorizationCodeUriRequest(se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeUriRequest) Login(net.robinfriedli.aiode.login.Login) CompletableFuture(java.util.concurrent.CompletableFuture) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) CancellationException(java.util.concurrent.CancellationException) UserException(net.robinfriedli.aiode.exceptions.UserException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException)

Example 3 with UserException

use of net.robinfriedli.aiode.exceptions.UserException in project aiode by robinfriedli.

the class CommandParser method parse.

public void parse(String input) throws CommandParseException, IllegalEscapeCharacterException, UnclosedQuotationsException {
    chars = input.toCharArray();
    for (; currentPosition < chars.length; currentPosition++) {
        char character = chars[currentPosition];
        Mode previousMode = currentMode;
        try {
            if (isEscaped) {
                if (!checkLegalEscape(character)) {
                    throw new IllegalEscapeCharacterException("Illegal escape character at " + (currentPosition - 1));
                }
                currentMode = currentMode.handleLiteral(character);
                isEscaped = false;
            } else if (isOpenQuotation) {
                if (character == '\\') {
                    isEscaped = true;
                } else if (character == '"') {
                    isOpenQuotation = false;
                } else {
                    currentMode = currentMode.handleLiteral(character);
                }
            } else {
                if (character == '\\') {
                    isEscaped = true;
                } else if (character == '"') {
                    isOpenQuotation = true;
                } else {
                    currentMode = currentMode.handle(character);
                }
            }
            if (currentPosition == chars.length - 1) {
                if (isOpenQuotation) {
                    throw new UnclosedQuotationsException("Unclosed double quotes");
                }
                if (isEscaped) {
                    throw new IllegalEscapeCharacterException("Illegal trailing escape character");
                }
                currentMode.terminate();
            }
        } catch (CommandParseException e) {
            throw e;
        } catch (UserException e) {
            throw new CommandParseException(e.getMessage(), command.getCommandBody(), e, currentPosition);
        }
        // fire mode switch event even if it's a different instance of the same mode
        if (previousMode != currentMode) {
            fireOnModeSwitch(previousMode, currentMode, currentPosition, character);
        }
    }
    fireOnParseFinished();
}
Also used : CommandParseException(net.robinfriedli.aiode.exceptions.CommandParseException) UnclosedQuotationsException(net.robinfriedli.aiode.exceptions.UnclosedQuotationsException) UserException(net.robinfriedli.aiode.exceptions.UserException) IllegalEscapeCharacterException(net.robinfriedli.aiode.exceptions.IllegalEscapeCharacterException)

Example 4 with UserException

use of net.robinfriedli.aiode.exceptions.UserException in project aiode by robinfriedli.

the class AbstractWidget method setupActions.

/**
 * Adds the reactions representing each available action to the message and prepares all actions
 */
public void setupActions(Message message) {
    List<WidgetManager.WidgetActionDefinition> actions = widgetManager.getActionsForWidget(getClass());
    GroovyShell predicateEvaluationShell = new GroovyShell();
    predicateEvaluationShell.setVariable("widget", this);
    MessageChannel channel = message.getChannel();
    if (channel instanceof TextChannel) {
        TextChannel textChannel = (TextChannel) channel;
        Guild guild = textChannel.getGuild();
        Member selfMember = guild.getSelfMember();
        if (!selfMember.hasPermission((TextChannel) channel, Permission.MESSAGE_ADD_REACTION)) {
            throw new UserException("Bot is missing permission to add reactions");
        }
    }
    try {
        CompletableFuture<RuntimeException> futureException = new CompletableFuture<>();
        for (int i = 0; i < actions.size(); i++) {
            WidgetContribution.WidgetActionContribution action = actions.get(i).getImplementation();
            if (action.hasAttribute("displayPredicate")) {
                try {
                    if (!((boolean) predicateEvaluationShell.evaluate(action.getAttribute("displayPredicate").getValue()))) {
                        break;
                    }
                } catch (ClassCastException e) {
                    throw new IllegalStateException(String.format("Groovy script in displayPredicate of action contribution %s did not return a boolean", action), e);
                } catch (Exception e) {
                    throw new IllegalStateException("Exception occurred evaluating displayPredicate of action contribution " + action, e);
                }
            }
            int finalI = i;
            message.addReaction(action.getEmojiUnicode()).queue(aVoid -> {
                if (finalI == actions.size() - 1 && !futureException.isDone()) {
                    futureException.cancel(false);
                }
            }, throwable -> {
                if (throwable instanceof InsufficientPermissionException || throwable instanceof ErrorResponseException) {
                    if (!futureException.isDone()) {
                        futureException.complete((RuntimeException) throwable);
                    }
                } else {
                    logger.warn("Unexpected exception while adding reaction", throwable);
                }
            });
        }
        futureException.thenAccept(e -> {
            MessageService messageService = Aiode.get().getMessageService();
            if (e instanceof InsufficientPermissionException) {
                messageService.sendError("Bot is missing permission: " + ((InsufficientPermissionException) e).getPermission().getName(), channel);
            } else if (e instanceof ErrorResponseException) {
                int errorCode = ((ErrorResponseException) e).getErrorCode();
                if (errorCode == 50013) {
                    messageService.sendError("Bot is missing permission to add reactions", channel);
                } else if (errorCode != 10008) {
                    // ignore errors thrown when the message has been deleted
                    logger.warn("Could not add reaction to message " + message, e);
                }
            }
        });
    } catch (InsufficientPermissionException e) {
        // exception is actually never thrown when it should be, remove completable future hack if this ever changes
        throw new UserException("Bot is missing permission: " + e.getPermission().getName(), e);
    } catch (ErrorResponseException e) {
        if (e.getErrorCode() == 50013) {
            throw new UserException("Bot is missing permission to add reactions");
        } else {
            logger.warn("Could not add reaction to message " + message, e);
        }
    }
}
Also used : WidgetContribution(net.robinfriedli.aiode.entities.xml.WidgetContribution) InsufficientPermissionException(net.dv8tion.jda.api.exceptions.InsufficientPermissionException) Guild(net.dv8tion.jda.api.entities.Guild) GroovyShell(groovy.lang.GroovyShell) InsufficientPermissionException(net.dv8tion.jda.api.exceptions.InsufficientPermissionException) ErrorResponseException(net.dv8tion.jda.api.exceptions.ErrorResponseException) ExecutionException(java.util.concurrent.ExecutionException) UserException(net.robinfriedli.aiode.exceptions.UserException) MessageService(net.robinfriedli.aiode.discord.MessageService) TextChannel(net.dv8tion.jda.api.entities.TextChannel) CompletableFuture(java.util.concurrent.CompletableFuture) MessageChannel(net.dv8tion.jda.api.entities.MessageChannel) ErrorResponseException(net.dv8tion.jda.api.exceptions.ErrorResponseException) UserException(net.robinfriedli.aiode.exceptions.UserException) Member(net.dv8tion.jda.api.entities.Member)

Example 5 with UserException

use of net.robinfriedli.aiode.exceptions.UserException in project aiode by robinfriedli.

the class CommandExecutionInterceptor method performChained.

@Override
public void performChained(Command command) {
    boolean completedSuccessfully = false;
    boolean failedManually = false;
    String errorMessage = null;
    boolean unexpectedException = false;
    boolean aborted = false;
    try {
        try {
            if (command.isAborted()) {
                aborted = true;
                return;
            }
            command.doRun();
        } catch (Exception e) {
            if ((command.getTask() != null && command.getTask().isTerminated()) || Thread.currentThread().isInterrupted()) {
                logger.warn(String.format("Suppressed '%s' because command execution was interrupted.", e));
                return;
            }
            try {
                command.onFailure();
            } catch (Exception e1) {
                logger.error("Exception thrown in onFailure of command, logging this error and throwing the exception that caused the command to fail.", e1);
            }
            throw e;
        }
        if (!command.isFailed()) {
            command.onSuccess();
            completedSuccessfully = true;
        } else {
            command.onFailure();
            failedManually = true;
        }
    } catch (AmbiguousCommandException e) {
        if (command instanceof AbstractCommand) {
            ((AbstractCommand) command).askQuestion(e.getOptions(), e.getDisplayFunc());
        } else {
            throw e;
        }
    } catch (CommandFailure e) {
        throw e;
    } catch (NoLoginException e) {
        MessageChannel channel = command.getContext().getChannel();
        User user = command.getContext().getUser();
        String message = "User " + user.getName() + " is not logged in to Spotify";
        messageService.sendError(message, channel);
        errorMessage = message;
        throw new CommandFailure(e);
    } catch (UserException e) {
        messageService.sendTemporary(e.buildEmbed().build(), command.getContext().getChannel());
        errorMessage = e.getMessage();
        throw new CommandFailure(e);
    } catch (FriendlyException e) {
        EmbedBuilder embedBuilder = new EmbedBuilder();
        embedBuilder.setTitle("Could not load track");
        if (e.getMessage() != null) {
            embedBuilder.setDescription("Message returned by source: " + e.getMessage());
        }
        embedBuilder.setColor(Color.RED);
        messageService.sendTemporary(embedBuilder.build(), command.getContext().getChannel());
        throw new CommandFailure(e);
    } catch (UnauthorizedException e) {
        String message = "Unauthorized: " + e.getMessage();
        messageService.sendException(message, command.getContext().getChannel());
        logger.warn("Unauthorized Spotify API operation", e);
        errorMessage = message;
        unexpectedException = true;
        throw new CommandFailure(e);
    } catch (TooManyRequestsException e) {
        String message = "Executing too many Spotify requests at the moment, please try again later.";
        messageService.sendException(message, command.getContext().getChannel());
        logger.warn("Executing too many Spotify requests", e);
        errorMessage = message;
        unexpectedException = true;
        throw new CommandFailure(e);
    } catch (GoogleJsonResponseException e) {
        String message = e.getDetails().getMessage();
        StringBuilder responseBuilder = new StringBuilder("Error occurred when requesting data from YouTube.");
        if (!Strings.isNullOrEmpty(message)) {
            responseBuilder.append(" Error response: ").append(message);
        }
        messageService.sendException(responseBuilder.toString(), command.getContext().getChannel());
        logger.error("Exception during YouTube request", e);
        errorMessage = message;
        unexpectedException = true;
        throw new CommandFailure(e);
    } catch (ErrorResponseException e) {
        messageService.sendException(String.format("Discord returned error (code: %d): %s", e.getErrorCode(), e.getMeaning()), command.getContext().getChannel());
        logger.error("Blocking Discord request returned error", e);
        throw new CommandFailure(e);
    } catch (CommandRuntimeException e) {
        if (e.getCause() != null) {
            errorMessage = e.getCause().getClass().getSimpleName() + ": " + e.getCause().getMessage();
        } else {
            errorMessage = e.getClass().getSimpleName() + ": " + e.getMessage();
        }
        unexpectedException = true;
        throw e;
    } catch (Exception e) {
        errorMessage = e.getClass().getSimpleName() + ": " + e.getMessage();
        unexpectedException = true;
        throw new CommandRuntimeException(e);
    } finally {
        postCommand(command, completedSuccessfully, failedManually, errorMessage, unexpectedException, aborted);
    }
}
Also used : AmbiguousCommandException(net.robinfriedli.aiode.exceptions.AmbiguousCommandException) User(net.dv8tion.jda.api.entities.User) AbstractCommand(net.robinfriedli.aiode.command.AbstractCommand) UnauthorizedException(se.michaelthelin.spotify.exceptions.detailed.UnauthorizedException) GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) UserException(net.robinfriedli.aiode.exceptions.UserException) NoLoginException(net.robinfriedli.aiode.exceptions.NoLoginException) FriendlyException(com.sedmelluq.discord.lavaplayer.tools.FriendlyException) ErrorResponseException(net.dv8tion.jda.api.exceptions.ErrorResponseException) AmbiguousCommandException(net.robinfriedli.aiode.exceptions.AmbiguousCommandException) CommandRuntimeException(net.robinfriedli.aiode.exceptions.CommandRuntimeException) TooManyRequestsException(se.michaelthelin.spotify.exceptions.detailed.TooManyRequestsException) FriendlyException(com.sedmelluq.discord.lavaplayer.tools.FriendlyException) GoogleJsonResponseException(com.google.api.client.googleapis.json.GoogleJsonResponseException) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) TooManyRequestsException(se.michaelthelin.spotify.exceptions.detailed.TooManyRequestsException) NoLoginException(net.robinfriedli.aiode.exceptions.NoLoginException) MessageChannel(net.dv8tion.jda.api.entities.MessageChannel) UnauthorizedException(se.michaelthelin.spotify.exceptions.detailed.UnauthorizedException) ErrorResponseException(net.dv8tion.jda.api.exceptions.ErrorResponseException) CommandFailure(net.robinfriedli.aiode.exceptions.CommandFailure) UserException(net.robinfriedli.aiode.exceptions.UserException) CommandRuntimeException(net.robinfriedli.aiode.exceptions.CommandRuntimeException)

Aggregations

UserException (net.robinfriedli.aiode.exceptions.UserException)9 ExecutionException (java.util.concurrent.ExecutionException)3 EmbedBuilder (net.dv8tion.jda.api.EmbedBuilder)3 Message (net.dv8tion.jda.api.entities.Message)3 CompletableFuture (java.util.concurrent.CompletableFuture)2 Guild (net.dv8tion.jda.api.entities.Guild)2 MessageChannel (net.dv8tion.jda.api.entities.MessageChannel)2 TextChannel (net.dv8tion.jda.api.entities.TextChannel)2 User (net.dv8tion.jda.api.entities.User)2 ErrorResponseException (net.dv8tion.jda.api.exceptions.ErrorResponseException)2 InsufficientPermissionException (net.dv8tion.jda.api.exceptions.InsufficientPermissionException)2 AbstractCommand (net.robinfriedli.aiode.command.AbstractCommand)2 CommandContext (net.robinfriedli.aiode.command.CommandContext)2 CommandParseException (net.robinfriedli.aiode.exceptions.CommandParseException)2 CommandRuntimeException (net.robinfriedli.aiode.exceptions.CommandRuntimeException)2 GoogleJsonResponseException (com.google.api.client.googleapis.json.GoogleJsonResponseException)1 FriendlyException (com.sedmelluq.discord.lavaplayer.tools.FriendlyException)1 GroovyShell (groovy.lang.GroovyShell)1 CancellationException (java.util.concurrent.CancellationException)1 TimeoutException (java.util.concurrent.TimeoutException)1