// 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); // Find the main configuration object (usually the first object document) 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; } let matchingChain if (domainName === "*" && fullConfig.filterChains.length > 0) { matchingChain = fullConfig.filterChains.find(chain => { return chain.filterChainMatch == null }); } else { matchingChain = fullConfig.filterChains.find(chain => { const serverNames = chain.filterChainMatch?.serverNames; 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 = parseInt(element.getAttribute('data-chain-index'), 10); if (!listenerName || isNaN(chainIndex)) { console.error("Missing required data attributes or invalid chain index for domain config."); return; } // 1. Get the full Listener JSON config from memory const listenerConfig = configStore.listeners[listenerName]; if (!listenerConfig || !listenerConfig.filterChains || !listenerConfig.filterChains[chainIndex]) { console.error(`Listener or FilterChain at index ${chainIndex} not found in memory for ${listenerName}.`); showConfigModal(`🚨 Error: Domain Config Not Found`, { name: title, error: `FilterChain index ${chainIndex} not found for listener ${listenerName}.` }, 'Error: JSON configuration missing.'); return; } // The JSON data for the specific filter chain const jsonData = listenerConfig.filterChains[chainIndex]; // 2. Fetch the full YAML for the listener if not already in memory let fullListenerYaml = listenerConfig.yaml || 'Loading YAML...'; if (fullListenerYaml === 'Loading YAML...') { try { const response = await fetch(`${API_BASE_URL}/get-listener?name=${listenerName}&format=yaml`); if (!response.ok) { fullListenerYaml = `Error fetching YAML: ${response.status} ${response.statusText}`; } else { fullListenerYaml = await response.text(); configStore.listeners[listenerName].yaml = fullListenerYaml; // Store YAML } } catch (error) { console.error("Failed to fetch YAML listener config:", error); fullListenerYaml = `Network Error fetching YAML: ${error.message}`; } } let yamlData; // 3. Extract the specific filterChain YAML using the utility function. // Use the domain name from the title as a proxy, or the first server_name from the JSON. const domainName = jsonData.filter_chain_match?.server_names?.[0] || "*"; if (fullListenerYaml.startsWith('Error') || fullListenerYaml.startsWith('Network Error')) { yamlData = fullListenerYaml; // Pass the error message } else { // Use the utility function to extract the specific chain's YAML yamlData = extractFilterChainByDomain(fullListenerYaml, domainName); if (yamlData === null) { // As a fallback if the utility fails or doesn't find it, dump the JSON directly try { const yaml = (typeof require !== 'undefined') ? require('js-yaml') : jsyaml; yamlData = yaml.dump(jsonData, { indent: 2, lineWidth: -1, flowLevel: -1 }).trim(); } catch (e) { yamlData = `Could not extract or dump YAML for chain: ${domainName}. Error: ${e.message}`; } } } // 4. Show the modal showConfigModal(title, jsonData, yamlData, 'json'); // Default to 'json' since it's guaranteed from memory } // 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}`); } }