๐Ÿ”Œ ์‹ค์‹œ๊ฐ„ ์†Œ์ผ“ ํ†ต์‹ ์˜ ๋„์ „๊ธฐ: ๋‹ค์–‘ํ•œ ์กฐ๊ฑด์ด ์กด์žฌํ•˜๋Š” ํ†ต์‹  feat. ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ๊ฐ์—์„œ์˜ ๊ณ ๋ฏผ๊ณผ ์„ค๊ณ„ ๊ณผ์ •

์ •ํ˜œ์ธยท2024๋…„ 12์›” 1์ผ
0

์•ˆ๋…•ํ•˜์„ธ์š”, ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ตœ๊ทผ ๊ตฌํ˜„ํ–ˆ๋˜ ์›น์†Œ์ผ“(WebSocket) ๊ธฐ๋ฐ˜์˜ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์— ๋Œ€ํ•œ ๊ฒฝํ—˜์„ ๊ณต์œ ํ•ด๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค.

ํŠนํžˆ Guest์™€ Host๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ์—ญํ• ๋กœ ๋‚˜๋‰˜๋Š” ํด๋ผ์ด์–ธํŠธ ๊ฐ„ ์†Œ์ผ“ ํ†ต์‹ ์„ ์„ค๊ณ„ํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๊ฒช์€ ์–ด๋ ค์›€๊ณผ ํ•ด๊ฒฐ ๊ณผ์ •์„ ๋‹ด์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‹จ์ˆœํ•œ ์ฑ„ํŒ… ์•ฑ์ด๋‚˜ ๊ธฐ๋ณธ์ ์ธ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๋„˜์–ด์„œ, Guest(๋ฐฉ๋ฌธ์ž)์™€ Host(๋ฐฉ ๊ด€๋ฆฌ์ž) ๊ฐ„ ์—ญํ•  ๊ตฌ๋ถ„์ด ๋ช…ํ™•ํ•œ ํ†ต์‹ ์„ ์š”๊ตฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ์ œ๊ฐ€ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ณ ๋ฏผ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  • "์–ด๋–ป๊ฒŒ Guest์™€ Host๋ฅผ ๊ฐ™์€ ๋ฐฉ์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ?"
  • "์—ญํ• (role)์„ ๊ธฐ์ค€์œผ๋กœ ์ ์ ˆํžˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋ ค๋ฉด ์–ด๋–ค ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ• ๊นŒ?"
  • "์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์˜ ํŠน์„ฑ์ƒ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์™ธ ์ƒํ™ฉ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๊นŒ?"

์ด ๋ชจ๋“  ๊ฒƒ์„ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ์—์„œ ์„ค๊ณ„ํ•˜๊ณ  ๊ตฌํ˜„ํ•ด์•ผ ํ–ˆ๋˜ ํ’€์Šคํƒ์˜ ์ž…์žฅ์—์„œ, ์–ด๋–ค ์ ์„ ๊ณ ๋ฏผํ–ˆ๊ณ , ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ์ž์„ธํžˆ ๊ณต์œ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿง ์ƒํ™ฉ ์„ค๋ช…: Guest์™€ Host์˜ ์‹ค์‹œ๊ฐ„ ์†Œํ†ต

์ด ํ”„๋กœ์ ํŠธ์˜ ๋ชฉํ‘œ๋Š” Guest์™€ Host๊ฐ€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์œผ๋ฉฐ ์†Œํ†ตํ•˜๋Š” ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, Guest๋Š” ์ž์‹ ์˜ ์œ„์น˜ ์ •๋ณด๋ฅผ ์ง€์†์ ์œผ๋กœ ์ „์†กํ•˜๊ณ , Host๋Š” ์ด๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•˜๋ฉฐ ํ•„์š”ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‹ ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„

์ฃผ์š” ๊ธฐ๋Šฅ์„ ์ •๋ฆฌํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Host์™€ Guest๋Š” ํŠน์ • ๋ฐฉ(room)์—์„œ๋งŒ ํ†ต์‹  ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. โ†’ Guest์™€ Host๋Š” ๊ฐ์ž ๊ณ ์œ ํ•œ channelId๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ†ต์‹ ํ•ฉ๋‹ˆ๋‹ค.
  • Guest๋Š” ์ž์‹ ์˜ ์œ„์น˜ ๋ฐ์ดํ„ฐ๋ฅผ Host์—๊ฒŒ๋งŒ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค. โ†’ Guest๋Š” Host์—๊ฒŒ๋งŒ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ฉฐ, ๋‹ค๋ฅธ Guest๋Š” ์ด๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • Host๋Š” ๋ฐฉ ์•ˆ์˜ ๋ชจ๋“  Guest ์ •๋ณด๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. โ†’ Host๋Š” ๋ฐฉ์— ์ฐธ์—ฌ ์ค‘์ธ ๋ชจ๋“  Guest์˜ ์‹ค์‹œ๊ฐ„ ์œ„์น˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ˜ฉ ์ฃผ์š” ๊ณ ๋ฏผ ์‚ฌํ•ญ

์ œ๊ฐ€ ์„ค๊ณ„๋ฅผ ํ•˜๋ฉฐ ๊ณ ๋ คํ•ด์•ผ ํ–ˆ๋˜ ๋ถ€๋ถ„์€ ํฌ๊ฒŒ ์•„๋ž˜์™€ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค.

1. Guest์™€ Host์˜ ์—ญํ•  ๊ด€๋ฆฌ

์†Œ์ผ“ ํ†ต์‹ ์—์„œ Guest์™€ Host์˜ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Guest๋Š” Host์—๊ฒŒ๋งŒ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ฉฐ, ๋‹ค๋ฅธ Guest๋Š” ์ด๋ฅผ ๋ณผ ์ˆ˜ ์—†๊ณ ,

Host๋Š” ๋ฐฉ์— ์ฐธ์—ฌ ์ค‘์ธ ๋ชจ๋“  Guest์˜ ์‹ค์‹œ๊ฐ„ ์œ„์น˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ Guest์™€ Host์˜ ์—ญํ•  ๋ณ„๋กœ ๋ณด๋‚ด๊ณ  ๋ฐ›๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ๋‹ฌ๋ผ์ ธ์•ผ ํ•œ๋‹ค๋Š” ์ ์ด ์ผ๋ฐ˜์ ์ธ ์†Œ์ผ“ ๊ตฌํ˜„๊ณผ์˜ ์ฐจ์ด์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

2. ์ฑ„๋„ ๊ด€๋ฆฌ

๋˜ ์ €ํฌ ํ”„๋กœ์ ํŠธ์—๋Š” ์ฑ„๋„(channel) ๊ฐœ๋…์ด ์กด์žฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฑ„๋„์€ ์—ฐ๊ฒฐ๋œ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๊ณ , ๋ฉ”์‹œ์ง€๋ฅผ ํŠน์ • ๊ทธ๋ฃน์—๋งŒ ์ „์†กํ•˜๋„๋ก ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์—ญํ• ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ,

  • ๋ฐฉ์— ์†ํ•˜์ง€ ์•Š์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ์š”์ฒญํ–ˆ์„ ๋•Œ ์ด๋ฅผ ๋ง‰์•„์•ผ ํ–ˆ๊ณ ,
  • ๋ฐฉ ์•ˆ์—์„œ๋„ ์—ญํ• (role)์— ๋”ฐ๋ผ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‹ฌ๋ผ์ ธ์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

3. ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์˜ ํŠน์„ฑ์ƒ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋“ค

์›น์†Œ์ผ“์€ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด์ฃผ์–ด์•ผ ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋น„์ •์ƒ์ ์œผ๋กœ ์—ฐ๊ฒฐ์„ ๋Š์—ˆ์„ ๋•Œ, ์ด๋ฅผ ์„œ๋ฒ„๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ธ๊ฐ€?
  • ์—ฐ๊ฒฐ ์ค‘ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ฉด ์–ด๋–ป๊ฒŒ ๊ฒ€์ฆํ•  ๊ฒƒ์ธ๊ฐ€?
  • ํ•˜๋‚˜์˜ guestID url์— ์—ฌ๋Ÿฌ๋ช…์ด ์ ‘์†ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ๊ฐ€?

๐Ÿ’ป ํ•ด๊ฒฐ ๊ณผ์ •: ์„ค๊ณ„์™€ ๊ตฌํ˜„

1๏ธโƒฃ Websocket ์—ฐ๊ฒฐ ์‹œ ์ฑ„๋„, host, guest ๋ถ„๋ฆฌ ๋กœ์ง

์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ,

์ €ํฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ฑ„๋„ ๋ณ„๋กœ ๊ทธ ๊ทธ๋ฃน ๋‚ด์—์„œ๋งŒ ํ†ต์‹ ์ด ์ด๋ฃจ์–ด์ ธ์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ฑ„๋„ ๋‚ด์—์„œ๋„, Host์™€ Guest๊ฐ€ ๊ฐ๊ฐ ๋ณด๋‚ด๊ณ  ๋ฐ›๋Š” ๋ฐ์ดํ„ฐ์˜ ์ •๋ณด๊ฐ€ ๋‹ฌ๋ผ์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ WebSocket ์—ฐ๊ฒฐ ์‹œ ์ด๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋…ผ๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹คโ€ฆ.

๊ทธ๋ž˜์„œ ๊ฐ€์žฅ ๋จผ์ €,

WebSocket ์—ฐ๊ฒฐ ์‹œ URL ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ role, channelId, guestId๋ฅผ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

  • role: ํด๋ผ์ด์–ธํŠธ์˜ ์—ญํ• (host ๋˜๋Š” guest)
  • channelId: ํ†ต์‹ ํ•  ๋ฐฉ ID
  • guestId: ๊ฒŒ์ŠคํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ID

์„œ๋ฒ„๋Š” ์ด ์ •๋ณด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•˜๊ณ , Host์™€ Guest์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ ์ ˆํžˆ ๊ด€๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ฝ”๋“œ ์ผ๋ถ€

const params = new URLSearchParams(req.url.split('?')[1]);
const channelId = params.get('channelId'); // ๋ฐฉ ID
const guestId = params.get('guestId'); // Guest ๊ณ ์œ  ID
const role = params.get('role'); // 'host' or 'guest'

์ด๋ ‡๊ฒŒ ๊ตฌ๋ถ„ํ•ด์คŒ์œผ๋กœ์จ ๊ฐ ์†Œ์ผ“ ์—ฐ๊ฒฐ์ด ์–ด๋–ค ์ฑ„๋„์— ์†ํ•ด ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  Guest์™€ Host ์—ญํ• ์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

1. ์ฑ„๋„๋ณ„ ์†Œ์ผ“ ๋ฐฉ ์ƒ์„ฑ

์šฐ์„ , ์ฑ„๋„ ๋‚ด์—์„œ๋งŒ ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค๊ณ„ํ•˜๊ธฐ ์œ„ํ•ด WebSocket ์—ฐ๊ฒฐ ์‹œ ์ฑ„๋„ ID(channelId)๋ฅผ URL ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ๋Š” ์ „๋‹ฌ๋ฐ›์€ channelId๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์†Œ์ผ“ ๋ฐฉ์„ ์ƒ์„ฑํ•˜๋ฉฐ, ํ•ด๋‹น ๋ฐฉ ์•ˆ์—์„œ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์—์„œ ์š”์ฒญํ•˜๋Š” ์†Œ์ผ“์˜ url ์ฝ”๋“œ

const ws = new WebSocket(
  `${BASE_URL}/socket?channelId=${channelId}`
);

์œ„์™€ ๊ฐ™์ด ์ฑ„๋„์„ ๊ตฌ๋ถ„ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

2. Guest ID๋กœ ์‚ฌ์šฉ์ž ๊ตฌ๋ถ„

๋˜, Guest๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ์‚ฌ์šฉ์ž๋Š” ๊ณ ์œ ํ•œ guestId๋ฅผ URL ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ url ์ฝ”๋“œ์—์„œ guestId๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด Host๋Š” ํŠน์ • Guest์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์—์„œ ์š”์ฒญํ•˜๋Š” ์†Œ์ผ“์˜ url ์ฝ”๋“œ

const ws = new WebSocket(
  `${BASE_URL}/socket?channelId=${channelId}&guestId=${guestId}`
);

3. Host์™€ Guest ๊ตฌ๋ถ„

๋‹ค์Œ์œผ๋กœ๋Š” Host์™€ Guest์—์„œ ๋ณด๋‚ด๊ณ  ๋ฐ›๋Š” ์ •๋ณด๊ฐ€ ๊ฐ๊ฐ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ url ์ฝ”๋“œ์—์„œ role์„ ์ถ”๊ฐ€ํ•ด์ค€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์—์„œ ์š”์ฒญํ•˜๋Š” ์†Œ์ผ“์˜ url ์ฝ”๋“œ

const ws = new WebSocket(
  `${BASE_URL}/socket?role=guest&channelId=${channelId}&guestId=${guestId}`
);

๊ฒฐ๋ก ์ ์œผ๋กœ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ Guest์˜ ์œ„์น˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ channelId, guestID, role ์„ ํ•จ๊ป˜ ๋ณด๋‚ด์ฃผ๊ฒŒ ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

2๏ธโƒฃ ์—ญํ• ์— ๋”ฐ๋ฅธ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๊ตฌ์กฐ

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ, ๊ฐ™์€ ๋ฐฉ์— ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ๋ผ๋„ ์—ญํ• ์— ๋”ฐ๋ผ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋„๋ก ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

1) Guest๊ฐ€ Host์—๊ฒŒ ์œ„์น˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ

์šฐ์„  Guest๋Š” ์ž์‹ ์˜ ์œ„์น˜๋ฅผ Host์—๊ฒŒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์—”๋“œ ์ฝ”๋“œ ์ผ๋ถ€

useEffect(() => {
  // ์œ„์น˜ ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ „์†ก
  if (lat && lng && wsRef.current?.readyState === WebSocket.OPEN) {
    wsRef.current.send(
      JSON.stringify({
        type: 'location',
        location: { lat, lng, alpha },
      }),
    );
  }
}, [lat, lng, alpha]);

2) Host๊ฐ€ Guest ๋ชฉ๋ก์„ ์š”์ฒญํ•  ๋•Œ

์œ„์˜ 1๋ฒˆ์€ Guest์˜ ์ž…์žฅ์ด์—ˆ๋‹ค๋ฉด, ์ด๋ฒˆ์—๋Š” Host์˜ ์ž…์žฅ์„ ๊ณ ๋ คํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Host๋Š” ๋ฐฉ ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  Guest์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์›น์†Œ์ผ“์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•˜์„ ๋•Œ, (ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋Š”Guest์˜ ์‹ค์‹œ๊ฐ„ ์œ„์น˜์ด๊ธฐ ๋•Œ๋ฌธ์—) ๊ฐ™์€ ์ฑ„๋„์— ์†ํ•œ Guest๋“ค์˜ ์‹ค์‹œ๊ฐ„ ์œ„์น˜๋ผ๊ณ  ํŒ๋‹จํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์—”๋“œ ์ฝ”๋“œ ์ผ๋ถ€

useEffect(() => {
  ws.onmessage = event => {
    const data = JSON.parse(event.data);

    const updatedLocations = data.clients.map((client: any, index: number) => {
      const matchingGuest = channelInfo?.guests?.find(guest => guest.id === client.guestId);
      return {
        ...client,
        color: matchingGuest?.markerStyle.color ?? markerDefaultColor[index],
      };
    });
    setOtherLocations(updatedLocations);
  };
}, [ws, guestsData]);

3๏ธโƒฃ Guest์˜ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ ์‹œ์  ๊ด€๋ฆฌ

์œ„์—์„œ ๊ตฌํ˜„ํ•œ ๊ฒƒ์œผ๋กœ ์‹คํ–‰์„ ํ•˜๋ฉด, host๊ฐ€ ๋จผ์ € ์ ‘์†ํ•ด์žˆ๊ณ , guest๊ฐ€ ์ดํ›„์— ์ ‘์†ํ•œ ์ƒํ™ฉ์—์„œ๋Š” ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ์ง€๋งŒ,

guest๊ฐ€ ๋จผ์ € ์ ‘์†ํ•ด ์žˆ๊ณ , ์ดํ›„ host๊ฐ€ ์ ‘์†ํ•œ ์ƒํ™ฉ ์—์„œ๋Š” guest๋Š” host๊ฐ€ ์ ‘์†ํ•˜๊ธฐ ์ „์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ธ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— host ์ ‘์† ์ด์ „์˜ guest๋“ค์— ๋Œ€ํ•œ ์œ„์น˜๋Š” ๋ฐ›์•„์˜ฌ ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋ฉด ์ข‹์„์ง€ ๊ณ ๋ฏผํ•˜๋‹ค, ์†Œ์ผ“์— ํƒ€์ž…์„ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์„ ์ƒ๊ฐํ•ด๋ƒˆ์Šต๋‹ˆ๋‹ค.

์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด,

ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฒ˜์Œ ์ ‘์†ํ•˜๋ฉด, ์†Œ์ผ“์— ๋ณด๋‚ด๋Š” ๋ฉ”์‹œ์ง€์˜ type์„ init ์œผ๋กœ ๋ณด๋‚ด์ฃผ๊ณ ,

๋ฐฑ์—”๋“œ ์ž…์žฅ์—์„œ๋Š” ๊ฒŒ์ŠคํŠธ๋“ค์˜ ์ •๋ณด๋“ค์„ ๋ฏธ๋ฆฌ ์ €์žฅํ•ด๋‘์—ˆ๋‹ค๊ฐ€

ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฒ˜์Œ ์ ‘์†ํ•œ ๊ฒฝ์šฐ(type์ด init์ธ ๊ฒฝ์šฐ) ์—๋Š” ์ด์ „ ๊ฒŒ์ŠคํŠธ๋“ค์˜ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ๋ณด๋‚ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด, host ํด๋ผ์ด์–ธํŠธ ์—์„œ๋Š” ๋ฐ›์•„์˜จ ์†Œ์ผ“์˜ ๋ฉ”์‹œ์ง€ ํƒ€์ž…์ด init ์ธ์ง€, location์ธ์ง€์— ๋”ฐ๋ผ

์ด์ „ ๊ฒŒ์ŠคํŠธ๋“ค์˜ ์ •๋ณด๋„ ๋ฐ›์•„์˜ค๊ณ , ์ƒˆ๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฒŒ์ŠคํŠธ๋“ค์˜ ์ •๋ณด๋„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

ws.onmessage = event => {
  const data = JSON.parse(event.data);
  console.log(data);
  if (data.type === 'init') {
    // ๊ธฐ์กด ํด๋ผ์ด์–ธํŠธ๋“ค์˜ ์œ„์น˜ ์ดˆ๊ธฐํ™”
    const updatedLocations = data.clients.map((client: any, index: number) => {
      const matchingGuest = channelInfo?.guests?.find(guest => guest.id === client.guestId);
      return {
        ...client,
        color: matchingGuest?.markerStyle.color ?? markerDefaultColor[index],
      };
    });
    setOtherLocations(updatedLocations);
  } else if (data.type === 'location') {
    // ์ƒˆ๋กœ ๋“ค์–ด์˜จ ์œ„์น˜ ์—…๋ฐ์ดํŠธ
    const matchingGuest = guestsData?.find(guest => guest.id === data.guestId);
    const updatedLocation = {
      guestId: data.guestId,
      location: data.location,
      token: data.token,
      color: matchingGuest?.markerStyle.color ?? '#ffffff',
    };

    setOtherLocations(prev => {
      const index = prev.findIndex(el => el.guestId === data.guestId);

      if (index !== -1) {
        const updatedLocations = [...prev];
        updatedLocations[index] = updatedLocation;
        return updatedLocations;
      }
      return [...prev, updatedLocation];
    });
  }
};

4๏ธโƒฃ ๋™์ผํ•œ Guest ID ์ ‘์† ์ฒ˜๋ฆฌ

guestId๊ฐ€ ๋™์ผํ•œ ์ƒํƒœ์—์„œ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘์†ํ•  ๊ฒฝ์šฐ, ๊ธฐ์กด์˜ ์—ฐ๊ฒฐ์ด ์œ ์ง€๋˜๋ฉด์„œ ๋ฐ์ดํ„ฐ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ € ๋‹จ์œ„์˜ ๊ณ ์œ  ํ† ํฐ์„ ์ƒ์„ฑํ•ด localStorage์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € ๋‹จ์œ„ ๊ณ ์œ  ํ† ํฐ ์ƒ์„ฑ ๋ฐ ์ €์žฅ

const token = localStorage.getItem('socketToken') || uuidv4();
localStorage.setItem('socketToken', token);

๊ทธ๋ฆฌ๊ณ  ๋ฐฑ์—”๋“œ์—์„œ๋Š” ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๊ฐ€ ๋™์ผํ•œ guestId๋กœ ์ ‘์†ํ•  ๊ฒฝ์šฐ, ์ด์ „ ์—ฐ๊ฒฐ์„ ๊ฐ•์ œ๋กœ ๋Š๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ์—์„œ ์ค‘๋ณต Guest ID ์ฒ˜๋ฆฌ

const guestSockets = {};

io.on('connection', socket => {
  const { channelId, guestId, token } = socket.handshake.query;

  if (guestSockets[guestId] && guestSockets[guestId] !== token) {
    io.to(guestSockets[guestId]).emit('disconnect');
  }
  guestSockets[guestId] = socket.id;

  socket.on('disconnect', () => {
    if (guestSockets[guestId] === socket.id) {
      delete guestSockets[guestId];
    }
  });
});

์ด์ œ ๋™์ผํ•œ guestId๋กœ ์ ‘์†ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์žˆ์œผ๋ฉด, ๊ธฐ์กด ์—ฐ๊ฒฐ์€ ๋Š๊ธฐ๊ณ  ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋งŒ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.


๐ŸŽ‰ ๊ฒฐ๋ก โ€ฆ..

์ด์ œ Host์™€ Guest๋Š” ๊ฐ™์€ ๋ฐฉ์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹คโ€ฆโ€ฆ..

๊ฒฐ๊ตญ ์•„๋ž˜ 3๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ๋ชจ๋‘ ๊ตฌํ˜„ ๋˜์—ˆ๊ณ , ์‹ค์‹œ๊ฐ„ ์†Œ์ผ“ ํ†ต์‹ ์—์„œ ์—ญํ•  ๊ตฌ๋ถ„, ์ฑ„๋„ ๊ด€๋ฆฌ, ์ค‘๋ณต ์ ‘์† ์ฒ˜๋ฆฌ ๋“ฑ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹คโ€ฆโ€ฆโ€ฆโ€ฆโ€ฆโ€ฆ.

  1. Guest๋Š” ์ž์‹ ์˜ ์œ„์น˜๋ฅผ Host์—๊ฒŒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ „๋‹ฌ
  2. Host๋Š” ๊ฐ™์€ ์ฑ„๋„ ๋‚ด์˜ ๋ชจ๋“  Guest ์ •๋ณด๋ฅผ ํ™•์ธ ๋ฐ ๊ด€๋ฆฌ
  3. ๋™์ผํ•œ guestId๋กœ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘์†ํ•œ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ

๊ฒฐ๋ก ์ ์œผ๋กœ ํ•ด๊ฒฐํ•œ ํ๋ฆ„์„ ๋‚˜ํƒ€๋‚ด๋ณด๋ฉด ์œ„์˜ gif์™€ ๊ฐ™์€๋ฐ,

ํ”„๋ก ํŠธ์—”๋“œ(ํด๋ผ์ด์–ธํŠธ)์™€ ๋ฐฑ์—”๋“œ(์„œ๋ฒ„)์—์„œ ๊ฐ๊ฐ ์ด ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ์„ค๊ณ„ํ•˜๋Š” ๊ณผ์ •์ด ๋„ˆ๋ฌด ๋ณต์žกํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” ์ฑ„๋„id์™€ guestID๋กœ ๋ถ„๋ฆฌํ–ˆ๋Š”๋ฐ,

๋ถ„๋ฆฌํ•ด์„œ ํ†ต์‹ ํ•˜๋‹ค ๋ณด๋‹ˆ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ์‹œ์  ๋•Œ๋ฌธ์— host๊ฐ€ ์ ‘์†ํ•˜๊ธฐ ์ด์ „์— ์ ‘์†ํ–ˆ๋˜ ๊ฒŒ์ŠคํŠธ ์ •๋ณด๊นŒ์ง€ ๋ฐ›์•„์˜ค๋Š” ๋กœ์ง๋„ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ–ˆ๊ณ ,

์ด ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๋ณด๋‹ˆ ๊ฐ™์€ guestId๋กœ ์—ฌ๋Ÿฌ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ ‘์†ํ•˜๊ฒŒ ๋˜์—ˆ์„ ๋•Œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋„ ํ•„์š”ํ•ด์กŒ์Šต๋‹ˆ๋‹คโ€ฆ..


์ •๋ง ์ด๋ฒˆ์— ์›น์†Œ์ผ“ ๊ตฌํ˜„ ํ•˜๋ฉด์„œ ๊ณ ๋ คํ•ด์•ผ ํ•  ๋ถ€๋ถ„์ด ๋งŽ์•„ ๋จธ๋ฆฌ๊ฐ€ ํ„ฐ์งˆ ๊ฒƒ ๊ฐ™์•˜๋Š”๋ฐ, ํ™•์‹คํžˆโ€ฆโ€ฆ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋””ํ…Œ์ผํ•œ ์„ค๊ณ„๋ฅผ ํ–ˆ๋‹ค๋ฉด ์ข‹์•˜๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•˜๊ฒŒ ๋˜์—ˆ๊ณ ,

์†Œ์ผ“ ๊ด€๋ จ ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด๋ณธ ๊ฒƒ์ด ์ฒ˜์Œ์ด๋ผ ๋””ํ…Œ์ผํ•œ ๋ถ€๋ถ„๊นŒ์ง€ ๊ณ ๋ คํ•˜์ง€ ๋ชปํ–ˆ์ง€๋งŒ

๋‹ค์Œ ๋ฒˆ์— ๋น„์Šทํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, ๊ทธ ๋•Œ๋Š” ์ •๋ง ๊ตฌ์ฒด์ ์œผ๋กœ ๋ฐœ์ƒํ•  ๋ฌธ์ œ๋“ค์„ ๊ฐ€์ •ํ•ด๊ฐ€๋ฉด์„œ ์„ค๊ณ„๋ฅผ ํƒ„ํƒ„ํžˆ ํ•ด๋‘์–ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹คโ€ฆโ€ฆโ€ฆ..

0๊ฐœ์˜ ๋Œ“๊ธ€