디스코드 베스트 포스트 추천 봇 만들기 3편 - 파일 읽기 쓰기와 디스코드 봇 커맨드 구현하기
Description: 파일을 읽기 및 쓰기하는 과정 특히 async와 race condition에 대해 이야기합니다. 그리고 디스코드봇 커맨드를 실제로 동작해봅니다
현재 노트: KR-110.00 c 디스코드 베스트 포스트 추천 봇 만들기 3편 - 파일 읽기 쓰기와 디스코드 봇 커맨드 구현하기
상위 분류: KR-110.00 디스코드 베스트 포스트 추천 봇 제작기
디스코드 베스트 포스트 추천 봇 만들기 3편 - 파일 읽기 쓰기와 디스코드 봇 커맨드 구현하기
본 글의 내용은 일반적으로 다음과 같은 흐름으로 진행됩니다.
원하는 것을 구현 시도 -> 문제가 생김 -> 해결
또다른 기능등 시도-> 다시 새로운 문제가 생김 -> 해결
... 구현 또는 수정이나 해결될 때까지 적절하게 반복
결론
예상과는 달리 디스코드 봇 커맨드의 경우 구현은 쉬었음, 다만 파일의 내용을 읽고 쓰기 하는 과정그리고 디스코드에서 말하는 프로퍼티와 제약사항을 직접 구현하면서 깨달은 점이 어려웠습니다.
savedata이후 display시 에러
fs를활용하여 json데이터를 읽어드린후, best5 데이터객체를 따로저장하는 함수
save5post
그리고 저장된 best5json을 읽어와 게시물제목, 총 리액션 수, 총메시지 수, 링크 를 추출하는 displaybest5
함수.
이 둘을 연속으로 실행하니깐 에러발생. display쪽 주석후 실행하니간 저장 잘됨.
즉 논리적으로는 문제 없어보이는 다음의 경우 문제 발생
save5post()
displaybest5()
만약 연속으로 실행시 원래 잘되던 저장함수도 이상해져서 빈값을 저장해버림.
예상
둘다 파일읽기, 쓰기이다보니 어딘가에서 꼬인거같음. 예를들어 save5post
가 저장하기도전에 display5post
에서 fs관련 건드려버려서 시작 index가 바뀌었다던가...
원인 Race Condition문제
https://fourjae.tistory.com/entry/Nodejs-Race-Condition
해결
비동기 fs함수들 전부 Sync를 붙여 동기함수로 수정
fswrite 바로 thread 저장시도 시 문제
에러 발생시 write부분
fs.writeFile(filePath, thread, (err) =>
다음과 같이 수정
fs.writeFile(filePath, JSON.stringify(thread, null, 2), (err)
chatgpt피셜
fs.writeFile을 사용할 때, 인자로 넘기는 데이터가 배열일 경우, Node.js 파일 시스템에서는 그 데이터를 문자열 형식으로 저장할 수 있도록 변환해야 합니다. 배열이나 객체를 바로 파일에 저장할 수 없기 때문에 JSON.stringify를 사용하여 문자열로 변환하는 것이 필요합니다
저장시 포맷에 대한 이해 부족이 원인
즉 fswrite는 배열을 입력받지 못하고 반드시 문자열을 입력받아야하기 때문에 처리를 해줘야한다.
이미 포맷된 배열에 대해 stringify시 다시한번 정렬되면서 문제될거라 생각했는데, 이미 포맷된 배열은 아무 변화없음
확실히 잘한 일 중 하나. 배치작업-> 중간에 채널마다데이터 저장하기
데이터가 많아지니 fetch시간도 길어지고, 중간에 데이터 유실되면 좀 많이 힘듬. 그래서 맨처음 단일 채널에서 10번횟수마다 배치작업형식으로 저장하기.
이후 더 복잡한 채널마다 저장하기
마지막으로 원하던 채널마다, 주차마다 정리하기함.
근데 데이터가 약 200개인데도 중간에 저장안하면 많이 힘든데, 최소 100개 정도 넘어가면 중간 저장은 필수 인듯
데이터가 많아져야 해볼만한 고민
display 이름이 원하는대로 표기 안됨. 디스코드 메시지의 이름 속성에 대한 이해
단순하게 username 속성 뿐만아니라 tag, display name, nickname등 사실 표기되는 이름의 종류가 많다는것을 디스코드 api구현하면서 알게 됨.
근데 displayname이 원하는 값인줄 알았느데 확인결과 해당값이 원하는 방식으로 적용되지 않는 케이스 발견. 예를들어 채널에설정된 이름이 변경없이 원래쓰던거면 몰라도, 채널마다 설정하는 이름의 경우 다른 값을 구현해야하는것같음.
해당 내용 관련 공식 docs확인
https://discord.js.org/docs/packages/discord.js/14.14.1/User:Class#toString
AI 확인결과 member라는 단위에서 확인 가능. 즉 autrhor에서 확인이 어려움.
다음과 같이 member객체 생성 후 해당 값에서 nickname또는 displayName을 가져옴. nickname의 경우 null이거나 유저가 설정한 값이라 해당 값을 우선순위로 둠
const member = await thread.guild.members.fetch(starterMessage.author.id);
authorName = member.nickname || member.displayName;
봇 메시지에 DM 링크를 넣으려는데 footer에 링크가 첨부안됨.
디스코드 봇 출력화면에서 나에게 바로 보낼 수 있는 DM링크를 첨부하고 싶은데, 기존의 footer를 사용하려했지만 링크첨부 및 마크다운 방식으로 시도해도 안됨. 아마 링크다보니 보안 위험같은 문제때문에 허용을 안한것 같음.
다음과 같은 링크방식 시도
작성자 [FE] 민찬 | DM discord.com/users/534738759527432192•오늘 오후 10:55
일단 footer가아닌 description에서는 마크다운이 되길래 마크다운 형식의 링크첨부로 해결
바로 send message되는 링크가있는지?(봇 메시지에 DM 링크를 넣으려는데 footer에 링크가 첨부안됨.)
해당링크는 유저프로필로 이어지기 떄문에 원하는 바로 1대1 DM 링크가 훨신 유저 경험이 좋을것이라 예상하여 해당 링크가 있는지 탐색
검색해도 잘안나와서 본인의 기존 1대1 DM 링크 url 살펴봄
다음과 같은 양식. 마지막이 자기 ID인것 같음
https://discord.com/channels/@me/11111111111111
구글 검색 결과 비슷한 문제로 토론한 페이지 발견
https://support.discord.com/hc/en-us/community/posts/360037884532-Link-to-enter-in-DM
여기서 제시한 방법도 내가 고려한 방법과 일치함
Hey guys, just use https://discordapp.com/channels/@me/USERID/
and change USERID to the userid of the user the link should send to
하지만 직접 해보니 액세스 거부발생.
계속 찾아보니 privacy 문제나 봇권한등의 문제같음. 예를들어 1대1 대화라는 것은 요청자와 받는자가 한정 돼있는데, 이게 봇에다가 걸어버리면 무슨 문제가 생기는 거 같음.