// data_fetchers.js import { API_BASE_URL, configStore } from './global.js'; import { showConfigModal, switchTab } from './modals.js'; import { listListeners } from './listeners.js'; // Will be imported later // ========================================================================= // YAML UTILITY FUNCTION // ========================================================================= /** * Extracts the YAML section for a specific domain from the filterChains array. * NOTE: This is a complex utility that you may decide is no longer needed * given the new approach in showDomainConfig (generating from JSON). * However, since it was in the original code, we keep it here. * @param {string} yamlData - The full YAML string containing the listener configuration. * @param {string} domainName - The domain name to search for. * @returns {string | null} The YAML string for the matching filterChain. */ export function extractFilterChainByDomain(yamlData, domainName) { if (typeof require === 'undefined' && typeof jsyaml === 'undefined') { console.error("Error: YAML parser (e.g., js-yaml) is required but not found."); return null; } // ... (rest of the original extractFilterChainByDomain function logic) ... let fullConfig; try { const yaml = (typeof require !== 'undefined') ? require('js-yaml') : jsyaml; const allDocs = yaml.loadAll(yamlData); fullConfig = allDocs.find(doc => doc && typeof doc === 'object'); } catch (e) { console.error("Error parsing YAML data:", e); return null; } if (!fullConfig || !Array.isArray(fullConfig.filterChains)) { console.warn("Input YAML does not contain a 'filterChains' array, or the main document was not found."); return null; } const matchingChain = fullConfig.filterChains.find(chain => { const serverNames = chain.filter_chain_match?.server_names; return serverNames && serverNames.includes(domainName); }); if (!matchingChain) { console.log(`No filterChain found for domain: ${domainName}`); return null; } try { const yaml = (typeof require !== 'undefined') ? require('js-yaml') : jsyaml; const outputYaml = yaml.dump(matchingChain, { indent: 2, lineWidth: -1, flowLevel: -1 }); return outputYaml.trim(); } catch (e) { console.error("Error dumping YAML data:", e); return null; } } // ========================================================================= // CONFIG-SPECIFIC MODAL LAUNCHERS // ========================================================================= /** * Handles showing the configuration for an individual FilterChain/Domain. * This function loads the JSON from memory and generates the YAML from it. * @param {HTMLElement} element - The DOM element that triggered the function. */ export async function showDomainConfig(element) { const title = element.getAttribute('data-title'); const listenerName = element.getAttribute('data-listener-name'); const chainIndex = element.getAttribute('data-chain-index'); if (!listenerName || chainIndex === null) { console.error("Missing required data attributes for domain config."); return; } const listener = configStore.listeners[listenerName]; const jsonData = listener?.filterChains?.[parseInt(chainIndex)]; if (!jsonData) { const errorMsg = 'Filter Chain configuration not found in memory.'; console.error(errorMsg); showConfigModal(`🚨 Error: ${title}`, { error: errorMsg }, errorMsg); return; } let yamlData = 'Generating YAML from in-memory JSON...'; let defaultTab = 'yaml'; try { if (typeof require === 'undefined' && typeof jsyaml === 'undefined') { throw new Error("YAML parser (e.g., js-yaml) is required but not found."); } const yaml = (typeof require !== 'undefined') ? require('js-yaml') : jsyaml; yamlData = yaml.dump(jsonData, { indent: 2, lineWidth: -1, flowLevel: -1 }); } catch (error) { console.error("Failed to generate YAML from JSON. Falling back to approximation.", error); const yamlApproximation = JSON.stringify(jsonData, null, 2) .replace(/[{}]/g, '') .replace(/"(\w+)":\s*/g, '$1: ') .replace(/,\n\s*/g, '\n') .replace(/\[\n\s*(\s*)/g, '\n$1 - ') .replace(/,\n\s*(\s*)/g, '\n$1- ') .replace(/:\s*"/g, ': ') .replace(/"/g, ''); yamlData = yamlApproximation + `\n\n--- WARNING: YAML is an approximation because the js-yaml library is missing or failed to parse. ---\n\n`; defaultTab = 'json'; // Switch to JSON tab if YAML generation failed } showConfigModal(title, jsonData, yamlData, defaultTab); } export async function showClusterConfigModal(clusterName) { const config = configStore.clusters[clusterName]; if (!config) { showConfigModal(`🚨 Error: Cluster Not Found`, { name: clusterName, error: 'Configuration data missing from memory.' }, 'Error: Cluster not in memory.'); return; } let yamlData = configStore.clusters[clusterName]?.yaml || 'Loading YAML...'; if (yamlData === 'Loading YAML...') { try { const response = await fetch(`${API_BASE_URL}/get-cluster?name=${clusterName}&format=yaml`); if (!response.ok) { yamlData = `Error fetching YAML: ${response.status} ${response.statusText}`; } else { yamlData = await response.text(); configStore.clusters[clusterName].yaml = yamlData; // Store YAML } } catch (error) { console.error("Failed to fetch YAML cluster config:", error); yamlData = `Network Error fetching YAML: ${error.message}`; } } showConfigModal(`Full Config for Cluster: ${clusterName}`, config, yamlData); } export async function showListenerConfigModal(listenerName) { const config = configStore.listeners[listenerName]; if (!config) { showConfigModal(`🚨 Error: Listener Not Found`, { name: listenerName, error: 'Configuration data missing from memory.' }, 'Error: Listener not in memory.'); return; } let yamlData = configStore.listeners[listenerName]?.yaml || 'Loading YAML...'; if (yamlData === 'Loading YAML...') { try { const response = await fetch(`${API_BASE_URL}/get-listener?name=${listenerName}&format=yaml`); if (!response.ok) { yamlData = `Error fetching YAML: ${response.status} ${response.statusText}`; } else { yamlData = await response.text(); configStore.listeners[listenerName].yaml = yamlData; // Store YAML } } catch (error) { console.error("Failed to fetch YAML listener config:", error); yamlData = `Network Error fetching YAML: ${error.message}`; } } showConfigModal(`Full Config for Listener: ${listenerName}`, config, yamlData); } // ========================================================================= // FILTER CHAIN ADDITION LOGIC (NEW) // ========================================================================= /** * Handles the submission of the new filter chain YAML. */ export async function submitNewFilterChain() { const listenerName = document.getElementById('add-fc-listener-name').value; const yamlData = document.getElementById('add-fc-yaml-input').value.trim(); if (!yamlData) { alert("Please paste the filter chain YAML configuration."); return; } if (!listenerName) { alert("Listener name is missing. Cannot submit."); return; } const payload = { listener_name: listenerName, yaml: yamlData }; try { const response = await fetch(`${API_BASE_URL}/append-filter-chain`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { const errorBody = await response.text(); throw new Error(`HTTP Error ${response.status}: ${errorBody}`); } alert(`Successfully appended new filter chain to '${listenerName}'.`); // Close modal and refresh listener list document.getElementById('addFilterChainModal').style.display = 'none'; listListeners(); } catch (error) { console.error(`Failed to append filter chain to '${listenerName}':`, error); alert(`Failed to append filter chain. Check console for details. Error: ${error.message}`); } }