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());
}
}
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));
}
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();
}
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);
}
}
}
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);
}
}
Aggregations