최근 스프링부트 + 자바로 디스코드 봇을 만드는 사이드를 진행해 보고 있습니다!
개발 과정에서, JDA 및 JDA-utilities 활용하여
사용자의 답변을 기다렸다가, 대답하는 기능 구현 과정에서..
삽질한 과정을 기록해 두고자 합니다 ^^;
https://github.com/discord-jda/JDA
https://github.com/JDA-Applications/JDA-Utilities
https://github.com/discord-jda/JDA/discussions/1541
JDA와 JDA-utilities 패키지를 사용합니다!
저는 gradle
을 사용했기 때문에, 아래와 같이 dependency 정보를 추가해 주었습니다.
dependencies {
implementation"net.dv8tion:JDA:5.0.0-alpha.11"
implementation 'com.jagrosh:jda-utilities:3.0.5'
...
...
}
P.S. JDA와 JDA-utilities를 함께 사용하실 때는 버전 정보에 유의하시면 좋을 것 같습니다!
JDA와 jda-utilities의 버전이 서로 호환되지 않으면, build 과정에서
JDA에 ShutdownEvent가 없다....
같은 오류 메시지를 만나게 됩니다..ㅠㅠ
JDA-utilities에서 이뤄진 Discussion에 따르면 (Examples > Prerequisite), 사용자의 답변 Event를 기다리기 위해 사용할 EventWaiter는 단일 인스턴스인 것이 권장된다고 합니다!
따라서, EventWaiter를 단일 인스턴스로 관리하기 위해, 저는 EventWaiterProvider 클래스를 따로 작성해 주었습니다.
[ EventWaiterProvider ]
@Service
@Getter
public class EventWaiterProvider {
private final EventWaiter eventWaiter = new EventWaiter();
}
String botToken = {사용할_디스코드봇_토큰};
JDA jda = JDABuilder.create(botToken, EnumSet.of(GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MESSAGE_REACTIONS))
.addEventListeners(slashCommandListener)
.addEventListeners(eventWaiterProvider.getEventWaiter())
.build()
.awaitReady();
저는 SlashCommand를 사용할 예정이기에, SlashCommandListener를 함께 추가해 주었습니다!
[ cf. SlashCommandListener ]
@Service
@RequiredArgsConstructor
@Slf4j
public class SlashCommandListener extends ListenerAdapter {
@Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
// 필요한 로직은 후술하겠습니다!
}
}
JDA와 jda-utilities가 본격적으로 사용되는 부분입니다!
@Service
@RequiredArgsConstructor
@Slf4j
public class SlashCommandListener extends ListenerAdapter {
private final EventWaiterProvider eventWaiterProvider;
@Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
event.reply("봇이 응답을 전송합니다.").queue();
event.getChannel().sendMessage("봇이 질문을 보냅니다, 답변해 주세요!")
.queue(
message -> eventWaiterProvider.getEventWaiter().waitForEvent(
MessageReceivedEvent.class, // 어떤 Event를 기다릴지 넣어 줍니다!
e ->
{ // 1번 콜백 : Event에 대한 조건이 들어가는 부분입니다.
if (e.getAuthor().isBot()) {
// 봇이 전송한 메시지라면, 이는 고려하지 않습니다 :)
return false;
}
// 해당 이벤트의 author가, SlashCommandEvent의 user와 동일한지를 확인!
return e.getAuthor().equls(event.getUser())
},
e ->
{ // 2번 콜백 : 기다린 Event에 대해 수행할 작업
String authorMessage = e.getMessage().getContentRaw();
event.getchannel()
.sendMessage("응답 " + authorMessage + "를 수신했습니다")
.queue();
return;
},
10, TimeUnit.SECONDS, // Timeout을 지정해 줍니다. 예제에서는 10초입니다! :)
() ->
{ // 3번 콜백 : timeout 도달시 수행할 작업
event.getChannel().sendMEssage("답변 시간이 초과되었습니다..!").queue();
return;
}
)
}
}
코드가 다소 길고 어지럽지만 ^^;
waitForEvent
의 파라미터로
이 들어간다고 생각하시면 크게 어렵지 않을 것 같습니다! :)