我正在开发一个Discord机器人,在该机器人上应该更新或创建特定消息(如果不存在)。如果该消息已被具有访问权限的某人删除,则会出现问题。创建一个悬空引用,并在该时间更新异常。如何检测当前通道中是否不存在具有特定ID的消息?
这是当前代码:
TextChannel scoreChannel = channel.getGuild().getTextChannelsByName(gameType + "-ladder", true).get(0);
String id = ScoreboardController.getScoreboardMessageId(gameType);
if (id == null)
scoreChannel.sendMessage(eb.build()).queue();
else {
scoreChannel.editMessageById(id, eb.build()).queue(); // this part can fail
}
请注意,getScoreboardMessageId从数据库中获取先前存储的ID。
我需要按标题查询消息,或者通过其他方式查找消息是否丢失。
我试图像这样检索嵌入的消息,但没有成功:
List<Message> messages = scoreChannel.getHistory().getRetrievedHistory();
After some more searching I managed to do this which works but is not Async:
TextChannel scoreChannel = channel.getGuild().getTextChannelsByName(gameType + "-ladder", true).get(0);
List<Message> messages = new MessageHistory(scoreChannel).retrievePast(10).complete();
boolean wasUpdated = false;
for (Message msg : messages) {
if (msg.getEmbeds().get(0).getTitle().equals(content[0])) {
scoreChannel.editMessageById(msg.getId(), eb.build()).queue();
wasUpdated = true;
}
}
if (!wasUpdated)
scoreChannel.sendMessage(eb.build()).queue();
答案 0 :(得分:1)
您可以使用队列的失败回调:
channel.editMessageById(messageId, embed).queue(
(success) -> {
System.out.printf("[%#s] %s (edited)\n",
success.getAuthor(), success.getContentDisplay()); // its a Message
},
(failure) -> {
failure.printStackTrace(); // its a throwable
}
);
被调用的失败回调意味着编辑失败。如果消息不再存在或发生某些连接问题,则可能发生这种情况。请注意,您可以为这两个回调中的任何一个传递null,以简化仅应处理失败或仅成功的情况。
文档建议getRetrievedHistory()
的方法返回一个空列表,除非您先前使用了都返回的 retrievePast 或 retrieveFuture RestAction<List<Message>>
。这意味着您必须使用:
history.retrievePast(amount).queue((messages) -> {
/* use messages here */
});
该数量限制为每个呼叫最多100条消息。 channel.getIterableHistory().takeAsync(amount)
提供了一种不受此限制的更简单的API,该API返回CompletableFuture
,并且可以与thenAccept
结合使用。
最好使用channel.retrieveMessageById(messageId)
,它仅检索消息,如果消息不存在则失败。但是,在您的情况下则不需要此操作,因为您可以通过id来编辑消息,并且可以仅使用该消息的失败响应,而不必遇到TOCTOU Problem。