
우리 서비스는 3개의 플랫폼에 각각 어드민이 존재하는 형태이고
그 중 하나의 플랫폼에서 라이브 스트리밍을 시범할 예정이다.
해당 플랫폼의 서비스, 어드민, 웹뷰 가 존재하는데 라이브 스트리밍을 개발하다보면 공통 코드들이 존재한다.
방송 연결/제어, 채팅 연결/제어, 방송 metadata 수신 등
이러한 부분이 존재하기 때문에 cto님께서 이를 라이브러리화하여 하나의 레포에서 관리하는 게 어떻냐고 제안을 주셨다. 좋은 경험이라 생각해 라이브러리를 만들었다.
먼저 리스트업을 해보았다.
- 방송 연결
- 방송 시작
- 방송 관리
- 채팅 연결
- 채팅 관리
- 채팅 메타 데이터 수신
- ivs token (우리 서비스 토큰) 송/수신
사실 cto님께서 원하시는 라이브러리는 사내 라이브러리로 범용성이 좋은 기능들의 집약이 아닌
우리 서비스에 특화된 라이브러리를 원하셨다. 그런데 필자는 우리 서비스 라이브러리 특성을 범용성으로 생각했다. 이 후에 리펙토링을 진행해야한다. 일단 공개 라이브러리라 생각하고 개발을 했다..ㅋㅋ..
요즘 말하는 딸깍이란 한 번의 행위로 많은 득을 얻는 개념이다
최대한 사용하는 쪽에서 많은 정보를 넘기지 않고 최소한의 정보를 송신하고 최대한의 정보를 수신 할 수 있도록 계획했다. 나만의 룰은 매개변수를 3개 이상 넘기지 말자.
이 후 처참히 어겨졌지만..
예시 코드 하나 가져오면
function connectChat(
tokenInfo: ReceivedIvsToken,
setChatList: SetChatList,
currentUser: any,
setAmIKick?: React.Dispatch<React.SetStateAction<boolean>>,
setBroadcastEnd?: React.Dispatch<React.SetStateAction<boolean>>
) {
if (!tokenInfo) {
return;
}
const room = new ChatRoom({
regionOrUrl: "ap-northeast-2",
tokenProvider: () => tokenProvider(tokenInfo),
});
const unsubscribeOnConnecting = room.addListener("connecting", () =>
console.log("연결중")
);
const unsubscribeOnConnected = room.addListener("connect", () =>
console.log("연결됨")
);
const unsubscribeOnDisconnected = room.addListener("disconnect", () => {
console.log("채팅 연결이 끊어졌습니다");
});
const unsubscribeOnMessageReceived = room.addListener(
"message",
(message) => {
const name = message.sender.attributes.nickname;
const content = message.content;
const messageId = message.id;
const ivsUserType = message.sender.attributes.ivsUserType;
const userId = String(message.sender.userId);
setChatList((current) => {
const newMessage = {
name,
content,
messageId,
ivsUserType,
userId,
};
return current ? [...current, newMessage] : [newMessage];
});
}
);
const unsubscribeOnEventReceived = room.addListener("event", (event) => {
const eventname = event.eventName;
if (eventname === "BROADCAST_END") {
setBroadcastEnd(true);
}
});
const unsubscribeOnMessageDelete = room.addListener(
"messageDelete",
(event) => {
const deletedMessageIds = event.messageId;
setChatList((current) =>
current
? current.filter((item) => item?.messageId !== deletedMessageIds)
: null
);
}
);
const unsubscribeOnUserDisconnect = room.addListener(
"userDisconnect",
(event) => {
if (event.userId === String(currentUser.id)) {
setAmIKick(true);
}
}
);
room.connect();
const cleanup = () => {
room.disconnect();
unsubscribeOnConnected();
unsubscribeOnConnecting();
unsubscribeOnDisconnected();
unsubscribeOnEventReceived();
unsubscribeOnMessageDelete();
unsubscribeOnMessageReceived();
unsubscribeOnUserDisconnect();
};
return { room, cleanup };
}
export { connectChat };
사용하는 쪽에서
connectChat({매개변수})
하면 이벤트 리스너가 등록되고 chat room과 연결이 된다.
매개변수를 줄이고 기능을 좀 더 세분화해야할지.. 아니면 매개변수가 더 되더라도 큰 기준의 기능을 제공하는 게 맞는지 고민이 되었다.
나눈 다면 connection 함수 1개 eventListener 함수 1개로 나눌 수 있을 거 같다.
일단은 이렇게 두고 이후 리펙토링 스프린트 할 때 개발 후 포스팅하겠다.
우리 서비스의 admin은 React.TS, 서비스는 Next.TS를 사용하고 있다.
렌더링 방식이 다르기 때문에 라이브러리를 개발 하는데 어려움이 있었다.
예를들어 컴포넌트 자체를 return 하도록 라이브러리 함수를 개발한다 했을 때
React에서는 오류 발생하지 않아도 Next.TS에서는 오류가 발생했다.
사실 공통 모듈을 개발하면서 컴포넌트 렌더링 함수를 계획하진 않았다. 기능적 함수만 라이브러리에서 가져오도록 하는게 목표였는데 cto님께서 하나의 모든 기능이 들어간 컴포넌트 형태로 라이브러리에서 관리하면 좋겠다고 말씀해주셨다. 그래서 그 부분은 리펙토링 스프린트에 진행할 예정이다.
지금은 state,useEffect 등 렌더링에 영향을 줄 수 있는 기능은 모두 빠져있는 상태이다.
ivs sdk와의 연동 위주로 개발이 되어있다.
아마 그래서 라이브러리를 최초 공개 배포 후 1주일이 됐을 때 2300다운로드를 기록한게 아닐까싶다..
사실 왜 누가 이 라이브러리를 3000회나 받은지는 모르겠다..
지금은 프라이빗 레포로 배포가 되어있어서 사실 목적에 맞는 라이브러리로 리펙토링 해야한다.
이런 고민거리를 가지고 라이브러리를 개발했다. 프라이빗 레포이기 때문에 레포를 공개할 수는 없지만 공통 소스를 찾고 사용자 입장을 고려하여 개발하는 과정이 재미있었고 또 신기했다. npm에 내가 직접 라이브러리를 올려보다니 ! 기회가 된다면 따로 라이브러리 하나 더 만들어보고싶다. 뭐.. 메뉴를 몇개 넣으면 식단표를 만들어주는 라이브러리라던지..ㅋㅋ..