갑자기 디스코드봇?
서버를 EC2에 올려놓았다보니, 서버 접속권한이 없는 클라이언트의 경우 로그를 매번 물어볼 수 밖에 없는 상황이라
디스코드에서 간단한 명령어로 보면 좋을 것 같아 만들었다.
https://discord.com/developers/applications
위 개발자 사이트에서 New Application
버튼을 통해 사용할 봇을 만들어준다.
좌측 Bot
탭에서 이름과 사진을 지정할 수 있고, Reset Token
버튼을 통해 토큰을 발급받을 수 있다.
나중에 node.js 서버에서 사용해야하니 저장 해 놓는다.
OAuth2
탭에서 bot
을 체크해주고 밑에 필요한 권한을 체크해준 후 하단 GENERATED URL
을 브라우저에 복사해서 붙여넣으면 내 권한이 있는 채널에 봇을 추가할 수 있다.
python과 nodejs 를 지원한다고 알고있는데, 나는 nodejs를 사용중이니... discord.js
를 사용해준다.
npm init -y
index.js
파일 생성 후 npm install discord.js
.env
파일 생성 후 안에 토큰 정보 기입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);
node index.js
로 테스트// 메세지
client.on('messageCreate', msg => {
console.log(msg.content)
})
messageCreate
명령어를 사용하면 봇이 참여하고 있는 채팅방의 메세지를 읽어올 수 있다. index.js
하단부에 추가해준다.
// 메세지
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번 찍혀있긴 한데, 정상적으로 출력되는 것 맞다 ㅎㅎ..
이제 이 봇을 테스트 채널이 아닌 팀원들과 같이 있는 채널에 등록시켜주면 된다!
굳!