From 3d2f0b23adf67f0d3f96c0c7be47236db379d5d5 Mon Sep 17 00:00:00 2001 From: GuavaPopper Date: Fri, 5 Jun 2026 18:57:23 +0700 Subject: [PATCH] refactor: Perbaiki Proxy Pipeline dan simplify dashboard configuration --- groups/RODA/.env | 4 -- groups/RODA/index.html | 65 +++++++++----------------------- groups/RODA/server.js | 85 +++--------------------------------------- 3 files changed, 24 insertions(+), 130 deletions(-) delete mode 100644 groups/RODA/.env diff --git a/groups/RODA/.env b/groups/RODA/.env deleted file mode 100644 index b5545e4..0000000 --- a/groups/RODA/.env +++ /dev/null @@ -1,4 +0,0 @@ -DASHBOARD_TARGET_URL=https://dashboard.informatika.untan.ac.id/index.php?penelitian -DASHBOARD_PROXY_1=https://api.codetabs.com/v1/proxy?quest={{url}} -DASHBOARD_PROXY_2=https://api.allorigins.win/get?url={{url}}&ts={{ts}} -DASHBOARD_PROXY_3=https://thingproxy.freeboard.io/fetch/{{rawUrl}} \ No newline at end of file diff --git a/groups/RODA/index.html b/groups/RODA/index.html index 05b5752..70bbaf5 100644 --- a/groups/RODA/index.html +++ b/groups/RODA/index.html @@ -77,12 +77,6 @@ debugLogs: false, dashboardRuntimeFetch: 'always', dashboardApiUrl: 'api/dashboard', - dashboardTargetUrl: 'https://dashboard.informatika.untan.ac.id/index.php?penelitian', - dashboardProxyTemplates: [ - 'https://api.codetabs.com/v1/proxy?quest={{url}}', - 'https://api.allorigins.win/get?url={{url}}&ts={{ts}}', - 'https://thingproxy.freeboard.io/fetch/{{rawUrl}}' - ] }; @@ -1662,56 +1656,33 @@ } let lastError = null; + + if (isDashboardRuntimeFetchAllowed()) { + const dashboardApiUrl = window.APP_CONFIG?.dashboardApiUrl?.trim(); + + if (dashboardApiUrl) { + try { + const rows = await fetchProxyRows(dashboardApiUrl); + applyDashboardRows(rows); + return; + } catch (error) { + lastError = error; + } + } + } + + // Fallback ke data yang di-embed saat build jika runtime fetch gagal atau dinonaktifkan const embeddedHtml = readEmbeddedDashboardHtml(); if (embeddedHtml) { try { applyDashboardRows(parseDashboardRows(embeddedHtml)); return; } catch (error) { - lastError = error; + lastError = lastError || error; } } - if (!isDashboardRuntimeFetchAllowed()) { - renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(lastError || new Error('DASHBOARD_RUNTIME_FETCH_DISABLED')), 'Coba Lagi', 'fetchDashboardData()'); - return; - } - - const targetUrl = window.APP_CONFIG?.dashboardTargetUrl?.trim(); - const dashboardApiUrl = window.APP_CONFIG?.dashboardApiUrl?.trim(); - const proxyTemplates = Array.isArray(window.APP_CONFIG?.dashboardProxyTemplates) - ? window.APP_CONFIG.dashboardProxyTemplates.filter(Boolean) - : []; - - const proxyServers = dashboardApiUrl ? [() => dashboardApiUrl] : []; - - if (targetUrl) { - proxyTemplates.forEach((template) => { - proxyServers.push((url) => template - .replaceAll('{{url}}', encodeURIComponent(url)) - .replaceAll('{{rawUrl}}', url) - .replaceAll('{{ts}}', String(Date.now()))); - }); - } - - if (!proxyServers.length) { - renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(new Error('DASHBOARD_PROXY_NOT_CONFIGURED')), 'Coba Lagi', 'fetchDashboardData()'); - return; - } - - try { - const proxyUrls = proxyServers.map((getProxyUrl) => getProxyUrl(targetUrl)); - const rows = await Promise.any(proxyUrls.map((proxyUrl) => fetchProxyRows(proxyUrl))); - applyDashboardRows(rows); - return; - } catch (error) { - lastError = error instanceof AggregateError && error.errors?.length - ? error.errors[error.errors.length - 1] - : error; - } - - // Jika semua proxy gagal - renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(lastError), 'Coba Lagi', 'fetchDashboardData()'); + renderRisetFeedback('Pemuatan Data Gagal', getDashboardErrorMessage(lastError || new Error('DASHBOARD_RUNTIME_FETCH_DISABLED')), 'Coba Lagi', 'fetchDashboardData()'); } diff --git a/groups/RODA/server.js b/groups/RODA/server.js index 2bf9d4e..626f615 100644 --- a/groups/RODA/server.js +++ b/groups/RODA/server.js @@ -6,69 +6,21 @@ const { URL } = require('url'); const ROOT_DIR = __dirname; const PARENT_DIR = path.join(__dirname, '..', '..'); const INDEX_PATH = path.join(ROOT_DIR, 'index.html'); -const ENV_PATH = path.join(ROOT_DIR, '.env'); const HOST = process.env.HOST || '127.0.0.1'; const PORT = Number(process.env.PORT || 3000); -const DEFAULT_DASHBOARD_TARGET_URL = 'https://dashboard.informatika.untan.ac.id/index.php?penelitian'; +const DASHBOARD_TARGET_URL = 'https://dashboard.informatika.untan.ac.id/index.php?penelitian'; const RODA_PATH_PREFIX = '/groups/RODA'; function logServerError(scope, error, extra = {}) { console.error(`[${scope}]`, error && error.stack ? error.stack : error, extra); } -function parseEnvFile(filePath) { - if (!fs.existsSync(filePath)) { - return {}; - } - - const env = {}; - const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/); - - for (const rawLine of lines) { - const line = rawLine.trim(); - if (!line || line.startsWith('#')) { - continue; - } - - const separatorIndex = line.indexOf('='); - if (separatorIndex === -1) { - continue; - } - - const key = line.slice(0, separatorIndex).trim(); - let value = line.slice(separatorIndex + 1).trim(); - - if ( - (value.startsWith('"') && value.endsWith('"')) || - (value.startsWith("'") && value.endsWith("'")) - ) { - value = value.slice(1, -1); - } - - env[key] = value; - } - - return env; -} - function getAppConfig() { - const env = { - ...parseEnvFile(ENV_PATH), - ...process.env - }; - - const dashboardProxyTemplates = [ - env.DASHBOARD_PROXY_1, - env.DASHBOARD_PROXY_2, - env.DASHBOARD_PROXY_3 - ].filter(Boolean); - return { - debugLogs: env.DEBUG_LOGS === 'true', - dashboardRuntimeFetch: env.DASHBOARD_RUNTIME_FETCH || 'always', - dashboardApiUrl: env.DASHBOARD_API_URL || 'api/dashboard', - dashboardTargetUrl: env.DASHBOARD_TARGET_URL || DEFAULT_DASHBOARD_TARGET_URL, - dashboardProxyTemplates + debugLogs: false, + dashboardRuntimeFetch: 'always', + dashboardApiUrl: 'api/dashboard', + dashboardTargetUrl: DASHBOARD_TARGET_URL, }; } @@ -76,10 +28,6 @@ const DASHBOARD_CACHE_TTL_MS = 5 * 60 * 1000; let dashboardCache = { html: null, timestamp: 0 }; async function fetchDashboardHtml() { - const targetUrl = getAppConfig().dashboardTargetUrl; - if (!targetUrl) { - throw new Error('DASHBOARD_TARGET_URL kosong'); - } const now = Date.now(); if (dashboardCache.html && (now - dashboardCache.timestamp) < DASHBOARD_CACHE_TTL_MS) { @@ -89,7 +37,7 @@ async function fetchDashboardHtml() { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 12000); try { - const response = await fetch(targetUrl, { + const response = await fetch(DASHBOARD_TARGET_URL, { signal: controller.signal, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36' @@ -111,35 +59,14 @@ async function fetchDashboardHtml() { } } -function validateAppConfig(config) { - const errors = []; - - if (!config.dashboardTargetUrl) { - errors.push('DASHBOARD_TARGET_URL belum diisi.'); - } - - return errors; -} - function injectConfig(html) { const configScript = ``; - const defaultConfigScript = ''; - - if (html.includes(defaultConfigScript)) { - return html.replace(defaultConfigScript, configScript); - } - return html.replace('', ` ${configScript}\n`); } function sendHtml(res) { try { const html = fs.readFileSync(INDEX_PATH, 'utf8'); - const configErrors = validateAppConfig(getAppConfig()); - if (configErrors.length) { - logServerError('config', new Error('Invalid app config'), { configErrors }); - } - const withConfig = injectConfig(html); res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(withConfig);