diff --git a/src/views/Main.vue b/src/views/Main.vue index 1e546f0..15db917 100644 --- a/src/views/Main.vue +++ b/src/views/Main.vue @@ -175,8 +175,8 @@ const todayUnique = ref(0); const activeNow = ref(0); let analyticsTimer = null; -// ๐ŸŸข [NEW] NAS ์ƒ์กด ์—ฌ๋ถ€ ์‹ค์‹œ๊ฐ„ ํŒ๋‹จ์šฉ ๋ฐ˜์‘ํ˜• ๋ณ€์ˆ˜ -const isNasOnline = ref(true); +// ๐ŸŸข [NEW] ์›Œ์ปค ํ‘œ์ง€ํŒ์„ ๋‹ด์„ ๋ฐ˜์‘ํ˜• ๋ณ€์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: nas) +const currentServerSource = ref('nas'); const menuItems = [ { id: 'main', name: 'HOME' }, @@ -188,36 +188,32 @@ const menuItems = [ const isLoggedIn = computed(() => !!authToken.value); -// ๐ŸŸข [NEW] ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ์„œ๋ฒ„ ํŒ๋ณ„ ์—”์ง„ (์‹œ๊ฐ„ + API ์ƒ์กด ์—ฌ๋ถ€ ์กฐํ•ฉ) -const currentServerSource = computed(() => { - const currentHour = new Date().getUTCHours() + 9; // ํ•œ๊ตญ ํ‘œ์ค€์‹œ(KST) ๋ณด์ • - const localHour = currentHour % 24; - - // 1. ๋ฐค 12์‹œ ~ ์•„์นจ 8์‹œ ์‚ฌ์ด (์›Œ์ปค๊ฐ€ ํ‡ด๊ทผ์‹œํ‚ค๊ณ  ํŒŒ์ด์–ด๋ฒ ์ด์Šค๋กœ ๋ฌด์กฐ๊ฑด ์šฐํšŒํ•˜๋Š” ์ •๊ธฐ ๋ฐฑ์—… ์‹œ๊ฐ„๋Œ€) - if (localHour >= 0 && localHour < 8) { - return 'firebase_backup'; - } - - // 2. ๋‚ฎ ์‹œ๊ฐ„๋Œ€์ธ๋ฐ NAS ํ†ต์‹ ์ด ๋Š๊ฒผ๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค ์šฐํšŒ ๋Œ€ํ”ผ์†Œ๋กœ ๊ธด๊ธ‰ ์ด๋™๋œ ์ƒํƒœ - if (!isNasOnline.value) { - return 'firebase_failover'; - } - - // 3. ๋‚ฎ ์‹œ๊ฐ„๋Œ€์— NAS ์„œ๋ฒ„๊ฐ€ ๊ฑด๊ฐ•ํ•˜๊ฒŒ ์„œ๋น„์Šค๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋Š” ์ตœ๊ณ  ๊ถŒํ•œ ๋ฉ”์ธ ๋…ธ๋“œ ์ƒํƒœ - return 'nas_main'; -}); - -// ๐ŸŸข [NEW] ํ„ฐ๋ฏธ๋„ ์ฝ˜์†” ๊ฐ์„ฑ์˜ ๋ฌธ์ž์—ด ๋งตํ•‘ ์ถœ๋ ฅ ๊ธฐ๋ฏน +// ๐ŸŸข [NEW] ํ—ค๋” ์ƒํƒœ์— ๋”ฐ๋ฅธ ํ„ฐ๋ฏธ๋„ UI ํ…์ŠคํŠธ ๋ณ€ํ™˜ const currentServerSourceDisplay = computed(() => { - if (currentServerSource.value === 'firebase_backup') { - return 'NODE:FB_NIGHT_MODE'; + if (currentServerSource.value === 'firebase_night') { + return 'HOST: FIREBASE (NIGHT)'; } if (currentServerSource.value === 'firebase_failover') { - return 'NODE:FB_FAILOVER'; + return 'HOST: FIREBASE (FAILOVER)'; } - return 'NODE:NAS_ACTIVE'; + return 'HOST: GNET-NAS (LOCAL)'; }); +// ๐ŸŸข [NEW] ์›Œ์ปค๊ฐ€ ๋‚ ๋ ค์ค€ 'x-served-by' ํ—ค๋”๋ฅผ ์ง์ ‘ ์ฝ์–ด ํŒ๋ณ„ํ•˜๋Š” ํ•ต์‹ฌ ๊ฐ์ง€ ์—”์ง„ +const detectRealtimeServerSource = async () => { + try { + // 0๋ฐ”์ดํŠธ ์งœ๋ฆฌ ์ดˆ๊ณ ์† HEAD ์š”์ฒญ์„ ๋‚ด ๋„๋ฉ”์ธ์œผ๋กœ ์ „์†กํ•˜์—ฌ ํ—ค๋”๋งŒ ๊ฐ€๋ณ๊ฒŒ ๊ธ์–ด์˜ด + const res = await fetch(window.location.origin, { method: 'HEAD' }); + const servedBy = res.headers.get('x-served-by'); + + if (servedBy) { + currentServerSource.value = servedBy; // 'nas', 'firebase_night', 'firebase_failover' ์ ์šฉ + } + } catch (err) { + console.error("์‹ค์‹œ๊ฐ„ ์„œ๋ฒ„ ์†Œ์Šค ํŒ๋ณ„ ์‹คํŒจ:", err); + } +}; + const rawAscii = ` โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ @@ -242,7 +238,6 @@ const formattedAscii = computed(() => { return rawAscii.replace(/ /g, 'โ–ˆ'); }); -// ๐ŸŸข [MODIFY] 30์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ์ŠคํŽ™์„ ๊ธ์–ด์˜ฌ ๋•Œ NAS๊ฐ€ ๊ฑด๊ฐ•ํ•˜๊ฒŒ ์‘๋‹ตํ•˜๋Š”์ง€ ์ฒดํฌํ•˜๋Š” ์œ ํšจ์„ฑ ๋กœ์ง ์ถ”๊ฐ€ const fetchAnalyticsData = async () => { try { const apiBaseUrl = import.meta.env.VITE_API_URL || ''; @@ -250,11 +245,9 @@ const fetchAnalyticsData = async () => { if (res.data) { todayUnique.value = res.data.todayUnique || 0; activeNow.value = res.data.activeNow || 0; - isNasOnline.value = true; // ๐ŸŸข ์ •์ƒ ๋™์ž‘ ํ™•์ธ -> 'NODE:NAS_ACTIVE' ์ถœ๋ ฅ ๋ณด์žฅ } } catch (err) { console.error("๊ด€์ œ ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ:", err); - isNasOnline.value = false; // ๐ŸŸข ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ž๋™์œผ๋กœ ๋น„์ƒ๋ง ๋ฐฐ์ง€('NODE:FB_FAILOVER')๋กœ ๊ต์ฒด } }; @@ -403,9 +396,15 @@ const handleLoginSubmit = async () => { onMounted(() => { fetchVideos(); - fetchAnalyticsData(); - analyticsTimer = setInterval(fetchAnalyticsData, 30000); + + // ๐ŸŸข [NEW] ๋ถ€ํŒ… ์‹œ ํ‘œ์ง€ํŒ ํ—ค๋”๋ฅผ ํ™•์ธํ•˜์—ฌ ์†Œ์Šค์ง€ ์ฆ‰์‹œ ๊ฐ์ง€ + detectRealtimeServerSource(); + + analyticsTimer = setInterval(() => { + fetchAnalyticsData(); + detectRealtimeServerSource(); // 30์ดˆ๋งˆ๋‹ค ์ƒ์กด ์—ฌ๋ถ€ ๋ฐ ๊ฒฝ๋กœ ์‹ค์‹œ๊ฐ„ ํŠธ๋ž˜ํ‚น + }, 30000); const globaljQuery = window.$; if (globaljQuery && terminalRef.value) { @@ -563,13 +562,13 @@ onUnmounted(() => { transition: 0.3s; } /* NAS ํ™œ์„ฑํ™” ์ƒํƒœ (๊ทธ๋ฆฐ ๊ณ„์—ด/ํ˜„์žฌ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ ์ ์šฉ) */ -.server-badge.nas_main { +.server-badge.nas { color: var(--tui-color); text-shadow: 0 0 5px var(--tui-glow); border-color: var(--tui-border); } /* ์ •๊ธฐ ์•ผ๊ฐ„ Firebase ๋ฐฑ์—… ์ž‘๋™ ์ƒํƒœ (ํ˜ธ๋ฐ•์ƒ‰) */ -.server-badge.firebase_backup { +.server-badge.firebase_night { color: #ffb000; text-shadow: 0 0 5px rgba(255, 176, 0, 0.6); border-color: rgba(255, 176, 0, 0.3); @@ -818,7 +817,7 @@ iframe { width: 100%; height: 180px; border-radius: 4px; } 50% { opacity: 1; text-shadow: 0 0 8px var(--tui-glow); } } -/* ๐ŸŸข [NEW] ๋น„์ƒ Failover ์ ๋ฉธ ์• ๋‹ˆ๋ฉ”์ด์…˜ */ +/* ๐ŸŸข [NEW] ๋น„์ƒ Failover ์ ๋ฉธ ์• ๋‹ˆ๋ฉ”์ด์…˜ */ @keyframes badgeBlink { 0%, 100% { opacity: 0.6; box-shadow: 0 0 5px rgba(255, 59, 59, 0.2); } 50% { opacity: 1; box-shadow: 0 0 15px rgba(255, 59, 59, 0.6); text-shadow: 0 0 12px #ff3b3b; }