[Java + JDA] 디스코드 봇 만들기 : 사용자의 답변을 기다려 대답하기

toto9602·2024년 5월 18일
1

최근 스프링부트 + 자바로 디스코드 봇을 만드는 사이드를 진행해 보고 있습니다!

개발 과정에서, JDA 및 JDA-utilities 활용하여
사용자의 답변을 기다렸다가, 대답하는 기능 구현 과정에서..
삽질한 과정을 기록해 두고자 합니다 ^^;

참고자료

https://github.com/discord-jda/JDA
https://github.com/JDA-Applications/JDA-Utilities
https://github.com/discord-jda/JDA/discussions/1541

0. 패키지 (JDA, JDA-utilities)

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가 없다....

같은 오류 메시지를 만나게 됩니다..ㅠㅠ

1. EventWaiter 초기화

JDA-utilities에서 이뤄진 Discussion에 따르면 (Examples > Prerequisite), 사용자의 답변 Event를 기다리기 위해 사용할 EventWaiter는 단일 인스턴스인 것이 권장된다고 합니다!

따라서, EventWaiter를 단일 인스턴스로 관리하기 위해, 저는 EventWaiterProvider 클래스를 따로 작성해 주었습니다.

[ EventWaiterProvider ]

@Service
@Getter
public class EventWaiterProvider {
    private final EventWaiter eventWaiter = new EventWaiter();
}

2. 봇 실행 (feat. addEventListeners)

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) {
    // 필요한 로직은 후술하겠습니다! 
    }
}

3. 사용자의 Command 답변 후, 사용자의 응답 기다리기

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의 파라미터로

  • 기다릴 Event
  • Event에 대한 조건 콜백
  • 기다린 Event에 대해 수행할 작업
  • Timeout 시간
  • Timeout 도달시 수행할 작업

이 들어간다고 생각하시면 크게 어렵지 않을 것 같습니다! :)

profile
주니어 백엔드 개발자입니다! 조용한 시간에 읽고 쓰는 것을 좋아합니다 :)

0개의 댓글