Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- index like
- 회고록
- 개발자 취업 준비
- mysql like
- aws m2
- 개발자 회고록
- token 탈취
- mongo 4.4
- VUE
- kubernetes
- 퇴사
- 팩토리 패턴 언제
- docker m2
- 쿠버네티스
- 개발자 면접 팁
- 밸런스 게임
- 라즈베리바이4 mongo
- nestjs
- 신입 개발자 면접
- mongo 4.4.18
- ECS
- 인텔리제이 github 로그인
- index in
- OSI 7계층
- 개발자 전직
- github accesstoken
- 신입 면접 팁
- git
- 팩토리 패턴 예제
- mysql index 속도차이
Archives
- Today
- Total
주니어 개발자 1호
사이퍼즈 디스코드 봇 [1] 본문
2023/02/26일 기준 mvp 동작 단계 확인
목적: 사이퍼즈 API, discord.js 를 활용한 API 봇 생성
- 기존 code 미 백업으로 인한 재작업
- 기존 동작 예시
링크: https://github.com/2Ruk/cyphers-bot-discord
기능
- /정보 닉네임
- 유저에 해당하는 닉네임, 급수(LEVEL), 승률등을 Embed 형태로 제공
필요사항
- discord bot setting ( message indent 설정등 )
- cyphers api key 발급
설계
- index.js
- discord client 실행
- discord event handle 설정
- controller
- 추후 확장성을 고려한 controller
- router와 같은 역할 수행
- service
- api 통신 및 비지니스 수행
- helper
- 공통적으로 쓰이거나, 연산을 도와주는 클래스, 함수에 대한 모음
- dto
- data transfer object
- 사용할 객체에 대한 설계
진행 순서
- 프로젝트 세팅
- repository layer 설계
- axios 통신 및 api to dto 설계
- msg.reply 요청에 대한 응답 반환
- reply: message → embed 로 변경
2편에 계속 진행할 부분
- 명확한 layer 분리
- api query에 필요한 기능 세팅 ( helper function 등으로 정리 - 날짜 세팅, limit 등이 필요 )
간략 코드 설명
Index.js
import * as Discord from 'discord.js';
import dotenv from 'dotenv';
import {cyphersController} from "./cyphers/controller/cyphers.controller.js";
import {routeHelper} from "./common/helper/route.helper.js";
import {UserInfoDto} from "./cyphers/dto/user-info.dto.js";
import {getUserDetailUserInfo, getUserId} from "./common/api/test/test.js";
dotenv.config({
path: '.env'
});
const discord_token = process.env.DISCORD_TOKEN
const client = new Discord.Client();
// ready시 출력
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
// message handler
client.on('message', async msg => {
const userInput = msg.content;
const [command,param] = userInput.split(' ');
if(command === '/전적'){
msg.reply('전적')
}
if(command === '/정보'){
const userId = await getUserId(param);
if(!userId) return;
const userDetailInfo = await getUserDetailUserInfo(userId);
if(!userDetailInfo) return;
const totalWinCount = userDetailInfo.records[0].winCount + userDetailInfo.records[1].winCount;
const totalLoseCount = userDetailInfo.records[0].loseCount + userDetailInfo.records[1].loseCount;
const userWinRate = totalWinCount / (totalWinCount + totalLoseCount) * 100 ;
const userInfo = new UserInfoDto(userId,userDetailInfo.nickname, userDetailInfo.grade, userDetailInfo.clanName)
userInfo.setWinLoseInfo(totalWinCount, totalLoseCount, userWinRate);
const embed = new Discord.MessageEmbed()
.setTitle('사이퍼즈 전적')
.setAuthor('치킨봇', '<https://resource.cyphers.co.kr/ui/img/comm/logo.png>', '<https://discord.js.org>')
.setDescription('사이퍼즈 전적입니다.')
.setThumbnail('<https://resource.cyphers.co.kr/ui/img/comm/logo.png>')
.addFields(
{ name: '닉네임', value: userInfo.userName },
{ name: '랭크', value: userInfo.userGrade },
{ name: '클랜', value: userInfo.userClanName },
{ name: '승률', value: userInfo.userWinRate },
)
.setTimestamp()
.setFooter('치킨봇', '<https://i.imgur.com/wSTFkRM.png>');
msg.reply(embed);
// msg.reply(`닉네임: ${userInfo.userName} \\n 랭크: ${userInfo.userGrade} \\n 클랜: ${userInfo.userClanName} \\n 승률: ${userInfo.userWinRate}`);
}
});
// 추후 아래 컨트롤러로 변경
// const {command,param,router} = routeHelper(msg);
// if (router==='cyphers') {
// cyphersController(command, param,msg);
// }
client.login(discord_token);
UserInfo Dto
- 필수적인 사항 → 생성자
- 이외 세팅 사항 → 내부 setting function
export class UserInfoDto {
constructor(userId,userName, userGrade, userClanName) {
this.userId = userId;
this.userName = userName;
this.userGrade = userGrade;
this.userClanName = userClanName;
}
userId='';
userName = '';
userGrade = 0;
userClanName = '';
userWinCount = 0;
userLoseCount = 0;
userWinRate = 0;
set setUserId(userId){
this.userId = userId;
}
setAllUserInfo(userName, userGrade, clanName, userWinCount, userLoseCount, userWinRate) {
this.userName = userName;
this.userGrade = userGrade;
this.userClanName = clanName;
this.userWinCount = userWinCount;
this.userLoseCount = userLoseCount;
this.userWinRate = userWinRate;
}
setDefaultUserInfo(userName, userGrade, clanName){
this.userName = userName;
this.userGrade = userGrade;
this.userClanName = clanName;
}
setWinLoseInfo(userWinCount, userLoseCount, userWinRate){
this.userWinCount = userWinCount;
this.userLoseCount = userLoseCount;
this.userWinRate = userWinRate;
}
getUserInfo() {
return {
userName: this.userName,
userGrade: this.userGrade,
userClanName: this.userClanName,
userWinCount: this.userWinCount,
userLoseCount: this.userLoseCount,
userWinRate: this.userWinRate
}
}
}
cyphers api helper
- 기본적인 null check guard
- api에 맞는 url 작성
import axios from "axios";
import * as dotenv from "dotenv";
import {UserInfoDto} from "../../../cyphers/dto/user-info.dto.js";
dotenv.config({
path: '.env'
});
const api_key = process.env.CYPHERS_API_KEY;
export async function getUserId(userNickName){
const { data } = await axios.get(`https://api.neople.co.kr/cy/players?nickname=${userNickName}&apikey=${api_key}`);
if(!data){
return null;
}
if(data.rows.length === 0){
return null;
}
return data.rows[0].playerId;
}
export async function getUserDetailUserInfo(userId){
const { data } = await axios.get(`https://api.neople.co.kr/cy/players/${userId}?apikey=${api_key}`);
if(!data){
return null;
}
return data;
}
export async function getMatchList(userId){
const { data } = await axios.get(`https://api.neople.co.kr/cy/players/${userId}/matches?gameTypeId=normal&apikey=${api_key}`);
if(!data){
return null;
}
return data;
}
// (async()=>{
// const userId = await getUserId("반ㅋ반ㅋ치ㅋ킨ㅋ");
// if(!userId) return;
//
// const userMatchInfo = await getMatchList(userId);
// console.log(userMatchInfo.matches.rows)
// console.log(userMatchInfo.matches.rows[0].playInfo.partyInfo)
// })()
// ((async () => {
// const userId = await getUserId("반ㅋ반ㅋ치ㅋ킨ㅋ");
// if(!userId) return;
//
// const userDetailInfo = await getUserDetailUserInfo(userId);
// if(!userDetailInfo) return;
//
// // -- 일반, 공식을 나누어서 분석
// // const normalWinCount = userDetailInfo.records.find(record => record.gameTypeId === 'normal').winCount;
// // const normalLoseCount = userDetailInfo.records.find(record => record.gameTypeId === 'normal').loseCount;
// // const normalWinRate = normalWinCount / (normalWinCount + normalLoseCount) * 100;
// //
// // const ratingWinCount = userDetailInfo.records.find(record => record.gameTypeId === 'rating').winCount;
// // const ratingLoseCount = userDetailInfo.records.find(record => record.gameTypeId === 'rating').loseCount;
// // const ratingWinRate = ratingWinCount / (ratingWinCount + ratingLoseCount) * 100;
// //
// // const totalWinCountExample2 = normalWinCount + ratingWinCount;
// // const totalLoseCountExample2 = normalLoseCount + ratingLoseCount;
// // const userWinRateExample2 = totalWinCountExample2 / (totalWinCountExample2 + totalLoseCountExample2) * 100;
//
// // -- reduce를 이용한 분석
// // const totalWinCountExample = userDetailInfo.records.reduce((acc,cur)=> acc += cur.winCount ,0)
// // const totalLoseCountExample = userDetailInfo.records.reduce((acc,cur)=> acc += cur.loseCount ,0)
// // const userWinRateExample = totalWinCountExample / (totalWinCountExample + totalLoseCountExample) * 100 ;
//
// // -- 더 간단하게
// const totalWinCount = userDetailInfo.records[0].winCount + userDetailInfo.records[1].winCount;
// const totalLoseCount = userDetailInfo.records[0].loseCount + userDetailInfo.records[1].loseCount;
// const userWinRate = totalWinCount / (totalWinCount + totalLoseCount) * 100 ;
//
// const userInfo = new UserInfoDto(userId,userDetailInfo.nickname, userDetailInfo.grade, userDetailInfo.clanName)
// userInfo.setWinLoseInfo(totalWinCount, totalLoseCount, userWinRate);
//
//
//
//
// })());
'사이드 프로젝트 진행' 카테고리의 다른 글
개발자 밸런스 게임 출시 (4) | 2023.05.12 |
---|---|
개발자 밸런스게임 ( 진행중 2 ) (0) | 2023.04.23 |
개발자 밸런스게임 (진행 중 1 ) (0) | 2023.04.16 |
API가 없어도 웹 크롤링으로 가능한 게임 기능 수집 (0) | 2023.04.09 |
리액트 토이 프로젝트 개발, 오늘도 열심히 살았습니다. (0) | 2023.04.02 |