import $ from 'jquery'; import { JSONRPC } from '@/json-rpc.js'; const DNSMASQ_COMPONENT_NAME = 'ru.kirillius.pf.sdn.External.API.Components.DNSMASQ'; const FIELD_IDS = { container: 'dnsmasq-config-container', instancesList: 'dnsmasq-instances-list', addInstanceButton: 'dnsmasq-add-instance-btn', saveButton: 'save-dnsmasq-btn', status: 'dnsmasq-status-message' }; const CLASS_NAMES = { instance: 'dnsmasq-instance-entry', removeInstanceButton: 'dnsmasq-remove-instance-btn', host: 'dnsmasq-host', user: 'dnsmasq-user', password: 'dnsmasq-password', forwarder: 'dnsmasq-forwarder' }; const SELECTORS = { container: `#${FIELD_IDS.container}`, instancesList: `#${FIELD_IDS.instancesList}`, addInstanceButton: `#${FIELD_IDS.addInstanceButton}`, saveButton: `#${FIELD_IDS.saveButton}`, status: `#${FIELD_IDS.status}` }; let currentConfig = { instances: [] }; let statusTimeoutId = null; let instanceCounter = 0; const getStatusElement = () => $(SELECTORS.status); function normalizeConfig(config) { if (!config || !Array.isArray(config.instances)) { return { instances: [] }; } return { instances: config.instances.map(instance => ({ host: instance?.host || '127.0.0.1', user: instance?.user || '', password: instance?.password || '', forwarder: instance?.forwarder || '127.0.0.1' })) }; } function clearStatus() { const $status = getStatusElement(); if (!$status.length) { return; } if (statusTimeoutId) { clearTimeout(statusTimeoutId); statusTimeoutId = null; } $status.stop(true, true).hide().text('').removeClass('success-message error-message'); } function updateStatus(message, type) { const $status = getStatusElement(); if (!$status.length) { return; } if (statusTimeoutId) { clearTimeout(statusTimeoutId); } $status .removeClass('success-message error-message') .addClass(type === 'success' ? 'success-message' : 'error-message') .text(message) .show(); statusTimeoutId = window.setTimeout(() => { $status.fadeOut(); }, 5000); } async function runAction($button, pendingText, action, messages) { if (!$button.length) { return; } const originalText = $button.text(); $button.prop('disabled', true).text(pendingText); clearStatus(); try { const result = await action(); if (messages?.success) { const successMessage = typeof messages.success === 'function' ? messages.success(result) : messages.success; if (successMessage) { updateStatus(successMessage, 'success'); } } } catch (error) { console.error(messages?.log || 'Ошибка выполнения действия DNSMASQ:', error); if (messages?.error) { updateStatus(messages.error, 'error'); } } finally { $button.prop('disabled', false).text(originalText); } } function resetCounters() { instanceCounter = 0; } function getNextInstanceId() { instanceCounter += 1; return instanceCounter; } function createInstanceRow(instance = {}) { const instanceId = getNextInstanceId(); return `

Инстанс

`; } function populateInstances() { const instances = currentConfig.instances.length ? currentConfig.instances : []; const $list = $(SELECTORS.instancesList); resetCounters(); $list.empty(); instances.forEach(instance => { $list.append(createInstanceRow(instance)); }); } function renderDNSMASQForm() { const $container = $(SELECTORS.container); $container.html(`

Инстансы DNSMASQ

Настройте параметры подключения к DNSMASQ для синхронизации списков серверов. Можно добавить несколько инстансов.

`); populateInstances(); attachEventHandlers(); } function collectConfigFromForm() { const instances = []; $(SELECTORS.instancesList).find(`.${CLASS_NAMES.instance}`).each((_, element) => { const $instance = $(element); const host = $instance.find(`.${CLASS_NAMES.host}`).val().trim(); const user = $instance.find(`.${CLASS_NAMES.user}`).val().trim(); const $passwordField = $instance.find(`.${CLASS_NAMES.password}`); const newPassword = $passwordField.val(); const originalPassword = $passwordField.data('original-password') || ''; const password = newPassword ? newPassword : originalPassword; const forwarder = $instance.find(`.${CLASS_NAMES.forwarder}`).val().trim(); instances.push({ host, user, password, forwarder }); }); return { instances }; } async function loadConfig() { try { const fullConfig = await JSONRPC.System.getComponentConfig(DNSMASQ_COMPONENT_NAME); currentConfig = normalizeConfig(fullConfig); return true; } catch (error) { console.error('Ошибка при загрузке конфига DNSMASQ:', error); currentConfig = { instances: [] }; return false; } } function handleAddInstance() { const $list = $(SELECTORS.instancesList); $list.append(createInstanceRow({ host: '127.0.0.1', user: '', password: '', forwarder: '127.0.0.1' })); } function handleRemoveInstance(event) { event.preventDefault(); $(event.currentTarget).closest(`.${CLASS_NAMES.instance}`).remove(); } async function handleSave() { const $button = $(SELECTORS.saveButton); clearStatus(); const newConfig = collectConfigFromForm(); await runAction($button, 'Применение...', async () => { await JSONRPC.System.setComponentConfig(DNSMASQ_COMPONENT_NAME, newConfig); currentConfig = normalizeConfig(newConfig); populateInstances(); }, { success: 'Конфигурация DNSMASQ успешно сохранена.', error: 'Ошибка при сохранении конфигурации DNSMASQ.', log: 'Ошибка сохранения конфига DNSMASQ' }); } function attachEventHandlers() { $(SELECTORS.saveButton).off('click').on('click', handleSave); $(SELECTORS.addInstanceButton).off('click').on('click', handleAddInstance); $(SELECTORS.instancesList) .off('click', `.${CLASS_NAMES.removeInstanceButton}`).on('click', `.${CLASS_NAMES.removeInstanceButton}`, handleRemoveInstance); } function detachEventHandlers() { $(SELECTORS.saveButton).off('click'); $(SELECTORS.addInstanceButton).off('click'); $(SELECTORS.instancesList) .off('click', `.${CLASS_NAMES.removeInstanceButton}`); } export const DNSMASQConfig = { render: () => `

Настройка DNSMASQ

Загрузка конфигурации...

`, mount: async () => { const success = await loadConfig(); if (success) { renderDNSMASQForm(); } else { $(SELECTORS.container).html('

Не удалось загрузить конфигурацию DNSMASQ.

'); } }, unmount: () => { detachEventHandlers(); clearStatus(); currentConfig = { instances: [] }; } };