일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 백준 7579
- TypeScript
- 포도주시식
- 백준 #7568번 #파이썬 #동적계획법
- 동적계획법
- popup
- 갓생
- background script
- C언어로 쉽게 풀어쓴 자료구조
- Chrome Extension
- discord.js
- nodejs
- 2156
- 공부시간측정어플
- 자료구조
- X
- 프로그래머스 #정수삼각형 #동적계획법
- content script
- 백준
- 캠스터디
- 파이썬
- react
- webpack
- 디스코드 봇
- 크롬 익스텐션
- Message Passing
- 크롬 확장자
- supabase
- Today
- Total
히치키치
시간이 측정되고 DB에 저장된다 본문
목표 체크
✅ 캠스터디 음성 채널 입장 & 캠스터디 음성 채널 퇴장 & 캠스터디 음성 채널 접속 유지 시간
✅ supabase DB에 캠스터디 접속 시간과 해당 유저 정보 저장
✅ 하드 코딩이 아닌 환경 변수로 코드 작성
코드 리뷰
1. 필요한 모듈 가져오기
discord.js : 디스코드 API와 상호작용
@supabase/supabase-js : Supabase DB와 상호 작용
dotenv : 환경 변수 관리
const { Client, GatewayIntentBits, REST, Routes } = require("discord.js");
const { createClient } = require("@supabase/supabase-js");
const dotenv =require("dotenv");
dotenv.config();
2. discord 클라이트 생성
서버, 서버 음성 상태, 서버 메세지 상태, 서버 메세지 내용을 추적하도록 설정
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
3. supabase 클라이언트 생성
환경 변수에서 supabase URL과 API 키를 제공해야 함
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_API_KEY
);
4. 디스코드 봇의 사용 준비 완료~!
client.once("ready", () => {
console.log("Bot is ready!");
});
5. 음성 채널에서 사용자 접속 측정
5-1. 봇이 추적 해야하는 음성 채널 지정
환경 변수에서 해당 채널의 ID 값을 가져옴
// YOUR_VOICE_CHANNEL_ID
const channelToTrack = process.env.VOICE_CHANNEL;
5-2. 사용자의 음성 시작 시간, 종료 시간, 총 시간을 저장하는 Map 객체 생성
const userDurations = new Map();
5-3. 사용자 채널 입장에 대한 처리
startDuration 함수 : 사용자Id 기반으로 사용자의 채널 입장에 대한 정보를 Map 객체에 저장함
인자 : 사용자 고유 ID
객체 저장 값:
음성 시작 시간 : (현재 시간 설정)
종료 시간 : 지정 되지 않음 (null)
총 시간 : 지정 되지 않음 (0)
// Record the start time
userDurations.set(userId, {
startTime: new Date(), // 음성 시작 시간 : 현재 시간
endTime: null, // 음성 종료 시간 : 지정되지 않음 null
totalDuration: 0, // 총 시간 : 지정되지 않음 0
});
}
5-4. 사용자 채널 퇴장에 대한 처리
endDuration 함수 : 사용자Id 기반으로 음성 채널 퇴장에 대한 정보를 Map 객체에 저장
인자 : 사용자 고유 ID
객체 저장 값:
종료 시간 : (현재 시간 설정)
총 시간 : 종료 시간 - 시작 시간
function endDuration(durationInfo) {
durationInfo.endTime = new Date();
durationInfo.totalDuration = Math.floor(
(durationInfo.endTime.getTime() - durationInfo.startTime.getTime()) / 1000
);
}
5-5. 사용자 음성 상태 변경에 대한 이벤트 등록
사용자의 음성 상태가 변경될 때마다 호출되는 voiceStateUpdate 이벤트 리스너 설정
콜백 함수로 이벤트 발생 전 상태 (oldState)와 이벤트 발생 후 상태 (newState)를 전달 받음
입장한 경우
- 상태 : 유저 존재 & 이벤트 발생 후 해당 채널==공부방 음성 채널
- 처리 : startDuration
퇴장한 경우
- 상태 : 유저 존재 & 이벤트 발생 전 해당 채널==공부방 음성 채널 & 이벤트 발생 후 채널 == 없음
- (퇴장한 이후임으로 이벤트에 채널이 없는 상태)
- 처리 : endDuration -> saveDuration
client.on("voiceStateUpdate", (oldState, newState) => {
const user = newState.member;
// console.log(user)
if (user && newState.channelId === channelToTrack) {
// 이벤트 발생이 최초로 입장한 유저의 경우
if(userDurations.has(user.id)===false){
// User joined the specified voice channel
console.log(
`${user.user.tag} joined ${newState.channel?.name}: ${new Date()}`
);
startDuration(user.id);
}
} else if (
user &&
oldState.channelId === channelToTrack &&
newState.channel === null
) {
// User left the specified voice channel
const { id: userUId, tag: userTag, globalName: userGlobalName } = user.user;
console.log(`${userGlobalName} left ${oldState.channel?.name}: ${new Date()}`);
if (userDurations.has(userUId)) {
const durationInfo = userDurations.get(userUId);
endDuration(durationInfo);
const { startTime, endTime, totalDuration } = durationInfo;
saveDuration(
userUId,
userGlobalName,
userTag,
startTime,
endTime,
totalDuration
);
// Remove the user from the tracking map
userDurations.delete(user.id);
}
}
});
5-6. 객체에 담긴 유저의 입퇴장 정보 DB 저장
saveDuration 함수 : Map 객체에 사용자Id 기반 음성 채널 입퇴장에 대한 정보를 supabase에 연결
user 테이블에 { dsUId, dsGlobalName, dsTag, start, end, duration } 칼럼에 해당 레코드 값 매칭
async function saveDuration(dsUId, dsGlobalName, dsTag, start, end, duration) {
// Save the duration to the Superbase database
const { data, error, status } = await supabase
.from("user")
.insert({ dsUId, dsGlobalName, dsTag, start, end, duration });
if (error) {
console.log(error);
} else {
console.log(data, status);
}
}
5-7. 디스코드 봇의 디스코드 서버 로그인
디스코드 봇의 인증 코드를 환경 변수에서 가져옴
디스코드 서버에 로그인 해 봇 기능 수행 준비
client.login(process.env.DISCORD_TOKEN);
6. DB 구조

7. 실행 결과

하하하 아주 잘 되고 있다~~
8. 앞으로는?
❓노트북으로 매번 서버 구동하지 않고 자동으로 계속 꺼지지 않고 돌아가도록 with 경제적인 가격
❓index.js에 모든 코드 다 있음... 정리 필요
❓환경 변수와 package script에서 테스트 디스코드 서버와 배포 디스코드 서버 분리 필요
❓다양한 기능 아이디어와 동시에 DB 구조 확인
'Cognisle' 카테고리의 다른 글
모달 현명하게 관리하기 (0) | 2024.07.01 |
---|---|
프로젝트 세팅 : 스타일 및 레이아웃 관련 (1) | 2024.04.26 |
프로젝트 세팅 : 설치 및 바벨 설정 (0) | 2024.04.26 |
내가 기차역이라 그런가? 사이트가 버벅거려 (0) | 2024.03.18 |
공부는 내가 할테니 관리 좀 해줄 사람? (1) | 2023.11.25 |