디스코드 봇 만들기 (2)

주노·2023년 12월 4일
1

초록 스터디

목록 보기
4/7
post-thumbnail

서론

지난 시간에 아래 코드를 통해 촐랑이가 TV를 보게 만들었다.

public static void main(String[] args) {
    JDABuilder builder = JDABuilder.createDefault(TOKEN)
        .disableCache(CacheFlag.MEMBER_OVERRIDES, CacheFlag.VOICE_STATE)
        .setBulkDeleteSplittingEnabled(false)
        .setActivity(Activity.watching("TV"));
    builder.build();
}

Github에서 PR이 Approve되었을 때 촐랑이가 뭔가 메시지를 보낼 수 있게 만드는게 목적이다.

다음과 같은 단계를 위 목적을 달성하기 위해 다음과 같은 요구사항을 정의할 수 있겠다.

  • 촐랑이가 서버에 메시지를 보낸다.
  • 촐랑이가 Github PR Approve 상태를 인지한다. (webhook)
  • 촐랑이를 배포한다 (?)

이번에는 촐랑이가 서버에 메시지를 보낼 수 있도록 구성해보자.

시작하기

이제 공식문서를 보면서 촐랑이가 메시지를 보내게 해보자.

잠깐 트러블슈팅

우선 메시지를 전송하기 위한 예제를 긁어서 실행해보려고했다.

public static void main(String[] args) {
    JDA jda = JDABuilder.createDefault(TOKEN)
        .enableIntents(GatewayIntent.MESSAGE_CONTENT) // enables explicit access to message.getContentDisplay()
        .build();
    //You can also add event listeners to the already built JDA instance
    // Note that some events may not be received if the listener is added after calling build()
    // This includes events such as the ReadyEvent
    jda.addEventListener(new MyListener());
}

public class MyListener extends ListenerAdapter {

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        if (event.isFromType(ChannelType.PRIVATE))
        {
            System.out.printf("[PM] %s: %s\n", event.getAuthor().getName(),
                event.getMessage().getContentDisplay());
        }
        else
        {
            System.out.printf("[%s][%s] %s: %s\n", event.getGuild().getName(),
                event.getChannel().getName(), event.getMember().getEffectiveName(),
                event.getMessage().getContentDisplay());
        }
    }
}

[JDA MainWS-WriteThread] INFO WebSocketClient - Connected to WebSocket
[JDA MainWS-WriteThread] ERROR WebSocketClient - WebSocket connection was closed and cannot be recovered due to identification issues
CloseCode[DISALLOWED_INTENTS](code=4014, meaning=Disallowed intents. Your bot might not be eligible to request a privileged intent such as GUILD_PRESENCES, MESSAGE_CONTENT, or GUILD_MEMBERS.)

위와 같이 오류가 발생한다.

대락적으로 아래와 같은 형태로 통신이 이뤄지는데 App이 discord Gateway로부터 요청을 받고, 보내는 과정에서 몇몇 권한이 필요하다.

Connection Lifecycle

디스코드 개발자 도구로 들어가서 다음 옵션들을 활성화시켜줘야한다.

설정 후 봇을 다시 실행하니 잘 동작하는것을 확인할 수 있다.

메시지 확인하기

위 예제코드로 메시지를 수신하여 확인할 수 있다.

메시지 보내기

MyListener 클래스를 다음과 같이 수정해보자.

public class MyListener extends ListenerAdapter {

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        if (event.getAuthor().isBot()) {
            return;
        }
        Message message = event.getMessage();
        String content = message.getContentRaw();

        if (content.contains("촐랑아 안녕") && event.getMember() != null) {
            MessageChannel channel = event.getChannel();
            channel.sendMessage("안녕하세요! " + event.getMember().getEffectiveName() + "님!").queue();
        }
    }
}

촐랑이가 잘 답장해준다. (귀여워..)

Github PR 확인하기

다양한 웹훅 설정이 필요하기 때문에 하나씩 차근차근 만들어보자.

디스코드 웹훅 채널 추가

디스코드에서 웹훅 채널을 추가한다.

웹후크 추가 후 웹 후크 URL을 복사한다.

https://discord.com/api/webhooks/123/WDF123_f12fs..
웹훅 URL은 대략적으로 이렇게 생겼다.

Github webhook

이때 payload URL은 위에서 복사한 웹 후크 URL을 사용한다.

Github Repositoy에 들어가서 webhook 설정을 추가해준다.

설정을 완료하면 추가한 이벤트에 따라 채널에 메시지가 오는 것을 확인할 수 있다.

고민하기

여기서 봇 배포 및 webhook 등록에 대한 결정에 따라 구현 방식이 결정되기 때문에 잠시 고민하는 시간을 가져본다.

Github에서는 Webhook을 이용하여 PR, Issue 등 다양한 이벤트에 대한 내용을 제공한다.

webhook을 어떤 방식으로 활용할 수 있을까?

1. webhook client 구현

위와 같은 흐름으로 동작하길 기대하는 방향이다.

위와 같이 리뷰를 남기면 github는 아래와 같은 payload를 전송한다.

{
 "action": "submitted",
  "review": {
    ...
    "user": {
      "login": "Choi-JJunho",
      ...
    },
    "body": "승인 안할건데?",
    "commit_id": "ce58b92df8f608807e85f69110c6429412c1511f",
    "submitted_at": "2023-12-04T07:26:21Z",
    "state": "changes_requested",
    ...
    "author_association": "OWNER",
    "_links": {
      ...
      "pull_request": {
        "href": "https://api.github.com/repos/Choi-JJunho/koin_temp/pulls/5"
      }
    }
  }

이를 활용할 경우 해당 payload를 수신하여 분석하고 동작하는 bot을 만드는 방법이 생각난다.

2. 채널 메시지 활용

위와 같은 흐름으로 동작하길 기대하는 방향이다.

github webhook을 discord가 받아서 출력하는 값은 다음과 같다.

// Request Change 요청 시 discord가 출력하는 값
{
  ...
  "d": {
    ...
    "author": {
      "bot": true,
      "id": "1181107313243869225",
      "avatar": "df91181b3f1cf0ef1592fbe18e0962d7",
      "username": "GitHub",
      "discriminator": "0000"
    },
    ...
    "embeds": [
      {
        "color": 16525609,
        "author": {
          ...
          "name": "Choi-JJunho",
          ...
        },
        "description": "RC 드립니다.",
        "type": "rich",
        "title": "[Choi-JJunho/koin_temp] Pull request review submitted: #5 Create README.md",
        "url": "https://github.com/Choi-JJunho/koin_temp/pull/5#pullrequestreview-1761705005"
      }
    ],
    "channel_id": "1181125289787523072",
    "timestamp": "2023-12-04T06:58:41.949000+00:00"
  }
}
// Approve 시 discord가 출력하는 값
{
  ...
  "d": {
    ...
    "author": {
      "bot": true,
      "id": "1181107313243869225",
      "avatar": "df91181b3f1cf0ef1592fbe18e0962d7",
      "username": "GitHub",
      "discriminator": "0000"
    },
    ...
    "embeds": [
      {
        "color": 38912,
        "author": {
          ...
          "name": "Choi-JJunho",
          ...
        },
        "description": "승인합니다.",
        "type": "rich",
        "title": "[Choi-JJunho/koin_temp] Pull request review submitted: #5 Create README.md",
        "url": "https://github.com/Choi-JJunho/koin_temp/pull/5#pullrequestreview-1761705005"
      }
    ],
    "channel_id": "1181125289787523072",
    "timestamp": "2023-12-04T06:58:41.949000+00:00"
  }
}

두번 꼬아서 생각해봤을 때 discord 상에서 Github Bot이 출력하는 메시지 형태를 촐랑이가 읽고 분석해서 적절한 행동을 취하게 만들 수도 있을 것 같다.

정리

배포를 어떻게 할까..? 고민이다.
위에서 말한 1번을 택한다면 webhook 수신에 대한 개발을 추가로 해야할 것이다.
이를 위해 Github에서 보내는 Post 요청 수신, SSL 처리 (선택) 등을 고민해봐야 할 것 같다. 또한 이 데이터를 JDA를 통해 bot이 메시지를 전송하도록 핸들링도 해야한다.

해당 방법으로 개발하기에는 모르는 우발적 요소가 많아보인다.

반대로 2번을 택한다면 메시지의 색깔(color)로 해당 메시지가 Approve임을 구분할 수 있을 것이고 이에 대한 촐랑이의 행동을 제어할 수 있을 것 같다.

추가로 배포는 어디에 할 것인지 고민되기도한다. 만약 AWS를 이용한다면 프리티어로 1년정도 운영 가능해보이긴 한다만...
뭔가 더 비용을 걱정하지 않아도되는 방법이 없을까? 고민되는 부분이다.

이 부분은 조금 더 이야기를 나눠봐야할 부분같다.

+) 이런저런 자료를 찾다보니 유튜브에 JDA 튜토리얼이 정말 잘 되어있었다.
만약 처음 시도해보는 사람들은 해당 영상을 보고 시작하면 좋을 것 같다.

https://www.youtube.com/watch?v=dOmyJhB_feM&list=PLWnw41ah3I4YxBetY8iCa-b9t1JwV2jsW&index=1

Reference

profile
안녕하세요 😆

2개의 댓글

comment-user-thumbnail
2023년 12월 8일

초록 스터디 화이팅!

1개의 답글