[TIL] 24.11.24 SUN

GDORI·2024년 11월 24일
0

TIL

목록 보기
112/143
post-thumbnail

디스코드 봇

갑자기 디스코드봇?
서버를 EC2에 올려놓았다보니, 서버 접속권한이 없는 클라이언트의 경우 로그를 매번 물어볼 수 밖에 없는 상황이라
디스코드에서 간단한 명령어로 보면 좋을 것 같아 만들었다.

디스코드 봇 생성

https://discord.com/developers/applications

위 개발자 사이트에서 New Application 버튼을 통해 사용할 봇을 만들어준다.

토큰 발급받기

좌측 Bot 탭에서 이름과 사진을 지정할 수 있고, Reset Token 버튼을 통해 토큰을 발급받을 수 있다.
나중에 node.js 서버에서 사용해야하니 저장 해 놓는다.

권한 부여


OAuth2 탭에서 bot을 체크해주고 밑에 필요한 권한을 체크해준 후 하단 GENERATED URL을 브라우저에 복사해서 붙여넣으면 내 권한이 있는 채널에 봇을 추가할 수 있다.

이제 이 봇친구에게 생명을 불어 넣어줘야 할 차례

python과 nodejs 를 지원한다고 알고있는데, 나는 nodejs를 사용중이니... discord.js를 사용해준다.

프로젝트 생성

  1. 프로젝트를 생성해주고 npm init -y
  2. index.js 파일 생성 후 npm install discord.js
  3. .env 파일 생성 후 안에 토큰 정보 기입
  4. index.js에 아래 코드 붙여넣기
import { Client, Collection, GatewayIntentBits, Partials } from 'discord.js';
import { config } from './config/config.js';

const client = new Client({
  intents: [
    GatewayIntentBits.DirectMessages,
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.commands = new Collection();

// 준비
client.on('ready', () => console.log(`${client.user.tag} 에 로그인됨`));
// 로그인
client.login(config.discord.token);
  1. node index.js 로 테스트

채팅방 입력된 메세지 받기

// 메세지 
client.on('messageCreate', msg => {
  console.log(msg.content)
})

messageCreate 명령어를 사용하면 봇이 참여하고 있는 채팅방의 메세지를 읽어올 수 있다. index.js 하단부에 추가해준다.

지정된 접두어(prefix)에 따라 실행

// 메세지 
client.on('messageCreate', msg => {
  // 봇 명령어 구분 문자
  const prefix = '!';

  // 작성자 봇이면 리턴
  if (msg.author.bot) return;
  // ! 시작 아니면 리턴
  if (!msg.content.startsWith(prefix)) return;
  if (msg.content.slice(0, prefix.length) !== prefix) return;

  const args = msg.content.slice(prefix.length).trim().split(/ +/g);
  const command = args.shift().toLowerCase();

  let cmd = client.commands.get(command);
  if (cmd) cmd.execute(client, msg, args);
})

맨 앞에 ! 가 붙어있고 지정된 커맨드가 있으면 해당 커맨드를 실행할 수 있는 코드이다.

커맨드 추가

node가 실행된 기준이 아닌 해당 파일 경로 기준으로 설정하기 위해 path 를 활용하여 commands 폴더 내에 있는 커맨드 파일을 쌱~ 읽어올 것이다.
전 프로젝트꺼 가져와서 붙여버리기~ 재활용이 제일 편해ㅋㅋ

import fs from 'fs';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import { formatDate } from '../utils/formatter/dateFormatter.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const commandDir = path.join(__dirname, '../commands');

const getAllCommands = (dir, fileList = []) => {
  const files = fs.readdirSync(dir); // 주어진 디렉토리 내 모든 파일과 폴더 목록 읽기
  files.forEach((file) => {
    const filePath = path.join(dir, file);

    // 하위 디렉토리가 있으면 재귀적으로 호출하여 커맨드 파일 검색
    if (fs.statSync(filePath).isDirectory()) {
      getAllCommands(filePath, fileList);
    } else if (path.extname(file) === '.js') {
      fileList.push(filePath); // 핸들러 파일 경로를 fileList 배열에 추가
    }
  });

  return fileList; // 모든 핸들러 함수를 반환
};

export const init = async (data) => {
  try {
    const commandFiles = getAllCommands(commandDir);
    for (const file of commandFiles) {
      const { default: command } = await import(pathToFileURL(file).href);
      data.set(command.name, command);
    }
  } catch (err) {
    console.log(err);
    const date = new Date();
    console.error(`[${formatDate(date)} - FAIL] Fail to load Command files`);
  }
};

index.js에 await init(client.commands); 이 한줄 추가해주면 된다!
commands 폴더에 들어갈 커맨드 들을 살펴보자.
예시로 유명한 핑퐁을 작성해보자

export default {
  name: 'ping',
  description: 'Ping 명령어',
  execute(client, message, args) {
    message.reply('Pong!');
  },
};

excute는 본인이 하고싶은 이름대로 짓고 onMessageCreate 명령어 내에서만 수정해주면 된다.
run을 하든 good을 하든 상관없다. 수정만 잘해주고 인자만 잘 넣어주면 된다.

제일 중요한 도커 로그 보여주려면?

이것도 그냥 저 위에 핑퐁 틀에다가 뭘 실행할지만 적어주면 된다.
child_process의 exec를 활용할 것이다.

import { exec } from 'child_process';

export default {
  name: 'log',
  description: '컨테이너 조회 명령어',
  execute(client, message, args) {
    exec(`docker logs <컨테이너명>`, (error, stdout, stderr) => {
      if (error) {
        // 에러가 발생하면 에러 메시지 출력
        message.reply(`명령어 실행 중 에러가 발생했습니다: ${error.message}`);
        return;
      }
      if (stderr) {
        // 표준 에러 메시지가 있으면 출력
        message.reply(`명령어 실행 중 오류가 발생했습니다: ${stderr}`);
        return;
      }

      // 정상적으로 출력된 결과를 메시지로 보냄
      message.reply(`\`\`\`${stdout}\`\`\``); // 코드 블록 안에 결과를 보내기 위해 \`\`\`을 사용
    });
  },
};

정상적으로 처리되었다면 코드블록 내 로그를 찍어줄 것이다.

재시작 테스트 하느라 로그가 3번 찍혀있긴 한데, 정상적으로 출력되는 것 맞다 ㅎㅎ..
이제 이 봇을 테스트 채널이 아닌 팀원들과 같이 있는 채널에 등록시켜주면 된다!

굳!

profile
하루 최소 1시간이라도 공부하자..

0개의 댓글