지난 9월 6일부터 7일까지, 명지전문대학 예체능관에서 구름톤 유니브 4기 시즌톤 예선전이 개최되었습니다.
이번 시즌톤은 구름과 구름톤 유니브가 공동 주관하며, 전국 62개 대학에서 약 500여 명의 참가자가 모인 대규모 해커톤 행사였는데요.
이번 포스팅에서는 참가자 출석 체크 시스템을 개발하던 중, react-qr-code 오픈소스에 첫 기여하게 된 과정을 공유해보려 합니다.
이전에도 여러 번 해커톤을 주최하고 운영해본 경험이 있었지만, 항상 출석 확인은 중요하면서도 시간이 꽤 소모되는 일이었습니다.
특히 참가자가 수백 명에 이르는 대규모 행사일 경우, 수기로 진행하는 방식은 비효율적이고 지연도 발생하곤 했습니다.
그래서 지난 3기 행사에서는, 현재 함께 총괄을 맡고 계신 희찬님이 참가자별 QR 코드를 생성해 이메일로 전송하고, 현장에서 이를 인식할 수 있는 리더기 앱을 직접 구현해주셨습니다.
하지만, 기능상에는 문제가 없었지만 QR 내에 담긴 참가자 정보가 최신정보가 아니라는 이슈가 있어 아쉬움이 남았습니다.
그래서 이번 기수에는 현재 팀빌딩으로 이용했던 사이트, 구름톤 유니브 공식 사이트 내 마이 페이지에 QR을 두기로 했습니다.
사이트 내에 있는 데이터는 항상 최신 데이터를 유지하고 있기 때문이였습니다.
QR 리더기는 여전히 희찬님께서 만들어주시고,
QR을 마이페이지에 띄우는 UI는 기존 사이트를 개발했던 제가 담당했습니다.
*위 사진에 있는 QR은 실제 데이터와 다릅니다!
리더기는 QR안에 있는 데이터들을 읽어주고, 자체적으로 체크인이 되었는지를 확인할 수 있게 데이터를 관리할 수 있도록 했어요. 그래서 QR안에 참가자 이름, 학교, 팀 명, 그리고 팀 번호를 넣어서 보내기로 했습니다!
{
name: "김은혜",
univ: "구름대학교",
team_number: 1,
team_name: "구름톤 유니브 중앙운영단"
}
이런식으로요!
라이브러리는 위에 희찬님께서 보내주신 react-qr-code 라이브러리를 사용했습니다.
단순히 value 값에 데이터를 넣으면 바로 QR을 생성해주는 구조라 굉장히 간편하게 적용할 수 있었습니다.
(사실 프론트엔드 측에서는 크게 복잡한 작업은 없었던 셈이죠 😅)
그런데 예상외로 바로 되지 않았습니다...
실제로 제가 카메라로 찍어보니 결과는 이랬습니다.
희찬님이 말씀하신대로 인코딩이 제대로 안되고 있었습니다. 아마 비 ASCII 문자는 깨지는 것 같습니다.
그래서 우선 encodeuriComponent함수를 통해 글 같은 비ASCII 문자들이 QR에 들어갈 때 깨지는 것을 방지했습니다. 물론 스캔할 때는 그래서 값이 이런식으로 나오겠지만요.
{"name":"%EA%B9%80%EB%8B%A4%EC%98%81","univ":"%EC%84%9C%EC%9A%B8%EB%8C%80%ED%95%99%EA%B5%90","teamId":"1","teamName":"AI%20%ED%95%99%EC%8A%B5%20%ED%94%8C%EB%9E%AB%ED%8F%BC%20%ED%8C%80"}
*해당 데이터는 임의로 만들었습니다.
하지만 이것은 임시방편이고, 사용자가 직접 디코딩해야한다는 불편함이 있고, 데이터 자체 길이가 증가하며, UX에도 불편할 것 같았습니다.
사실 이전에 오픈소스에 기여해본 경험이 없어, 오픈소스 기여하는 방법... 테스트 하는 법 등.. 좀 찾아본 것 같습니다.
우선 해당 라이브러리의 오픈소스 기여 전 궁금한 점은 다음과 같았습니다.
“UTF-8은 대부분의 언어와 문자를 지원하니까, 인코딩 방식을 바꾸면 해결되지 않을까?”
UTF-8은 사실상 전 세계 대부분의 언어와 문자를 인코딩할 수 있는 표준이며, 모든 시스템 웹, 애플리케이션 기본 인코딩으로 사용되고 있다고 합니다.
기존에 qrcode의 value값이 들어오면 그냥 바로 qrcode.addData(value);라고 되어 있었습니다.
export const QRCode = forwardRef(({ bgColor = "#FFFFFF", fgColor = "#000000", level = "L", size = 256, value, ...props }, ref) => {
// Use type === -1 to automatically pick the best type.
const qrcode = new QRCodeImpl(-1, ErrorCorrectLevel[level]);
qrcode.addData(value);
qrcode.make();
....
실제로 아무런 인코딩 없이 addData(value)를 하면, qr.js에서는 아래와 같이 처리를 하게 됩니다.
for (let i = 0; i < value.length; i++) {
buffer.put(value.charCodeAt(i), 8); // 8비트 단위로 넣음
}
즉, charCodeAt()을 통해 UTF-16 코드 유닛을 바이트처럼 다루게 되고, 이를 8비트에 넣으면 상위 바이트가 잘리고, 문자가 깨지는 현상이 발생한다는 것입니다.
따라서 이를 다음과 같이 바꿔주었습니다.
export function bytesToBinaryString(bytes) {
return bytes.map((b) => String.fromCharCode(b & 0xff)).join("");
}
export function encodeStringToUtf8Bytes(input) {
return Array.from(new TextEncoder().encode(input));
}
export const QRCode = forwardRef(
({ bgColor = "#FFFFFF", fgColor = "#000000", level = "L", size = 256, value, ...props }, ref) => {
const qrcode = new QRCodeImpl(-1, ErrorCorrectLevel[level]);
const utf8Bytes = encodeStringToUtf8Bytes(value);
const binaryString = bytesToBinaryString(utf8Bytes);
qrcode.addData(binaryString, "Byte");
qrcode.make();
...
먼저 value값을 받아 encodeStringToUtf8Bytes 함수에 넣어 TextEncoder를 사용하여 UTF-8 바이트 배열을 생성하고, 이를 Array 형태로 변환합니다.
즉, 이와 같이 변환되는 것이죠.
["안녕"] -> [236, 149, 136, 235, 133, 149]
그리고 바이트 배열을 바이너리 문자열로 변환해주는 bytesToBinaryString함수입니다.
QR 코드 생성 시, 문자열이 아닌 실제 바이트 단위로 데이터를 넣기 위해서 각 바이트를 단일 문자로 변환해주었습니다.
그리고 테스트 결과, value값에 한국어가 들어가도 깨지지 않게 완성했습니다!
사실은 TextEncoder 한 줄만 써도 내부적으로 UTF-8 인코딩을 수행해주는데, 기여하겠다는 욕심으로 직접 하나하나 진수 변환을 하는 코드를 짜고 있었습니다...(바보다)
이 점을 라이브러리 구현하신 분께서 리뷰해주셔서 바로 고치고 굉장히 짧은 코드로 다시 올렸습니다.
이 점 외에도 몇몇 리뷰를 해주셨는데, 처음 오픈소스를 기여해보는 거라 매우 설렜고, 영어로 리뷰를 받고 답글을 다는 재미도 있었습니다 ㅎㅎ
마지막은 제가 한국인인걸 아시고 '감사합니다' 하고 Merge해주셨어요ㅎㅎ 뿌듯!
또한, README에 비ASCII 문자 테스트를 위한 예시로 일본어나 이모지를 포함한 내용도 제안드렸고, 해당 내용도 함께 반영되었습니다. (와! 외국인이 만든 라이브러리에 한국어가 있다니!)
“누군가는 이미 했겠지…”
그렇게 생각하고 지나쳤다면 놓쳤을 기회였습니다.
어쩌면 누군가가 이미 발견하고 추가했을 법한 사항이라고 생각했는데, 막상 이슈를 찾아보니 아무도 언급한 적이 없었고, 그 덕분에 제가 직접 기여할 수 있었죠.
오픈 소스 기여를 했다는 사실만으로도 너무 좋아서, 운이 좋았다고 생각했습니다.
특히나 한국어 지원을 위해 기여했다는 점, 그리고 제가 참여한 해커톤 시스템의 일부가 오픈소스에 반영되었다는 사실에 큰 의미가 있었습니다.
앞으로 또 오픈소스에 기여할 일이 더 있다면 자신감을 가지고 꼼꼼하게 체크하며 함께 기여하고 싶습니다.
읽어주셔서 감사합니다!
One of the best and necessary information about the onine betting games, that was awesome. This info is similar to 3patticrownapk.org . Thanks for the guide and tips.
One of the best and necessary information about the onine betting games, that was awesome. This info is similar to 3Patti Crown. Thanks for the guide and tips. https://3patticrownapk.org/
과정이 멋있네요