// Local DNS UI functions function openLocalDnsModal(editIndex = -1) { const modal = document.getElementById('localDnsModal'); const title = document.getElementById('local-dns-title'); const nameInput = document.getElementById('local-name'); const typeSelect = document.getElementById('local-type'); const ttlInput = document.getElementById('local-ttl'); const submitBtn = document.getElementById('local-submit'); if (!modal || !title || !nameInput || !typeSelect || !ttlInput || !submitBtn) return; nameInput.value = ''; typeSelect.value = 'A'; ttlInput.value = 3600; if (window.updateLocalForm) updateLocalForm(); if (editIndex >= 0) { const rec = window.localDnsData?.find(r => r.index === editIndex); if (rec) { nameInput.value = rec.name; typeSelect.value = rec.type; if (window.updateLocalForm) updateLocalForm(rec); ttlInput.value = rec.ttl; title.textContent = 'Edit Local DNS Record'; submitBtn.textContent = 'Update'; window.editLocalIndex = editIndex; } } else { title.textContent = 'Add Local DNS Record'; submitBtn.textContent = 'Add'; window.editLocalIndex = -1; } modal.showModal(); } function updateLocalForm(rec = null) { const typeEl = document.getElementById('local-type'); const fields = document.getElementById('local-value-fields'); if (!typeEl || !fields) return; const type = typeEl.value; fields.innerHTML = ''; let inputHtml = ''; switch (type) { case 'A': case 'AAAA': inputHtml = ``; break; case 'CNAME': inputHtml = ``; break; case 'TXT': inputHtml = ``; break; case 'MX': inputHtml = ``; break; case 'SRV': inputHtml = ``; break; case 'SOA': inputHtml = ``; break; case 'CAA': inputHtml = ``; break; case 'NS': case 'PTR': inputHtml = ``; break; default: inputHtml = ``; break; } fields.innerHTML = inputHtml; if (rec) { switch (type) { case 'MX': const prefEl = document.getElementById('local-preference'); const exchEl = document.getElementById('local-exchange'); if (prefEl) prefEl.value = rec.preference || ''; if (exchEl) exchEl.value = rec.exchange || ''; break; case 'SRV': const priEl = document.getElementById('local-priority'); const weightEl = document.getElementById('local-weight'); const portEl = document.getElementById('local-port'); const targetEl = document.getElementById('local-target'); if (priEl) priEl.value = rec.priority || ''; if (weightEl) weightEl.value = rec.weight || ''; if (portEl) portEl.value = rec.port || ''; if (targetEl) targetEl.value = rec.target || ''; break; case 'SOA': const mnameEl = document.getElementById('local-mname'); const rnameEl = document.getElementById('local-rname'); const serialEl = document.getElementById('local-serial'); const refreshEl = document.getElementById('local-refresh'); const retryEl = document.getElementById('local-retry'); const expireEl = document.getElementById('local-expire'); const minimumEl = document.getElementById('local-minimum'); if (mnameEl) mnameEl.value = rec.mname || ''; if (rnameEl) rnameEl.value = rec.rname || ''; if (serialEl) serialEl.value = rec.serial || ''; if (refreshEl) refreshEl.value = rec.refresh || ''; if (retryEl) retryEl.value = rec.retry || ''; if (expireEl) expireEl.value = rec.expire || ''; if (minimumEl) minimumEl.value = rec.minimum || ''; break; case 'CAA': const flagsEl = document.getElementById('local-flags'); const tagEl = document.getElementById('local-tag'); const valueEl = document.getElementById('local-value'); if (flagsEl) flagsEl.value = rec.flags || ''; if (tagEl) tagEl.value = rec.tag || ''; if (valueEl) valueEl.value = rec.value || ''; break; default: const dataEl = document.getElementById('local-data'); if (dataEl) dataEl.value = rec.data || rec.value || ''; break; } } } async function submitLocalDns(buttonElement) { if (!buttonElement) return; const originalText = buttonElement.innerHTML; buttonElement.disabled = true; buttonElement.innerHTML = 'Saving... '; try { const nameEl = document.getElementById('local-name'); const typeEl = document.getElementById('local-type'); const ttlEl = document.getElementById('local-ttl'); if (!nameEl || !typeEl || !ttlEl) return; const name = nameEl.value; const type = typeEl.value; const ttl = parseInt(ttlEl.value) || 3600; let record = { name, type, ttl, class: 'IN' }; switch (type) { case 'MX': const prefEl = document.getElementById('local-preference'); const exchEl = document.getElementById('local-exchange'); record.preference = parseInt(prefEl?.value) || 10; record.exchange = exchEl?.value || ''; break; case 'SRV': record.priority = parseInt(document.getElementById('local-priority')?.value) || 0; record.weight = parseInt(document.getElementById('local-weight')?.value) || 0; record.port = parseInt(document.getElementById('local-port')?.value) || 0; record.target = document.getElementById('local-target')?.value || ''; break; case 'SOA': record.mname = document.getElementById('local-mname')?.value || ''; record.rname = document.getElementById('local-rname')?.value || ''; record.serial = parseInt(document.getElementById('local-serial')?.value) || 0; record.refresh = parseInt(document.getElementById('local-refresh')?.value) || 0; record.retry = parseInt(document.getElementById('local-retry')?.value) || 0; record.expire = parseInt(document.getElementById('local-expire')?.value) || 0; record.minimum = parseInt(document.getElementById('local-minimum')?.value) || 0; break; case 'CAA': record.flags = parseInt(document.getElementById('local-flags')?.value) || 0; record.tag = document.getElementById('local-tag')?.value || ''; record.value = document.getElementById('local-value')?.value || ''; break; default: record.data = document.getElementById('local-data')?.value || ''; break; } const isEdit = window.editLocalIndex >= 0; const url = isEdit ? '/api/update-local-dns' : '/api/add-local-dns'; const body = isEdit ? JSON.stringify({ index: window.editLocalIndex, record }) : JSON.stringify(record); const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body }); if (!response.ok) { throw new Error(await response.text()); } if (window.showNotification) window.showNotification(isEdit ? 'Record updated successfully' : 'Record added successfully'); const modal = document.getElementById('localDnsModal'); if (modal) modal.close(); if (window.genericFetch) window.genericFetch('local-dns', true); } catch (err) { console.error('Failed to submit local DNS record:', err); if (window.showNotification) window.showNotification('Failed to submit record: ' + err.message, 'error'); } finally { buttonElement.disabled = false; buttonElement.innerHTML = originalText; } } function editLocalDns(index) { openLocalDnsModal(index); } function deleteLocalDns(index) { if (window.showConfirm) { window.showConfirm('Delete this record?', async () => { try { const response = await fetch('/api/delete-local-dns', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ index }) }); if (!response.ok) { throw new Error(await response.text()); } if (window.showNotification) window.showNotification('Record deleted successfully'); if (window.genericFetch) window.genericFetch('local-dns', true); } catch (err) { console.error('Failed to delete local DNS record:', err); if (window.showNotification) window.showNotification('Failed to delete record: ' + err.message, 'error'); } }); } } async function toggleVersionPreference(domain, isPublic) { try { const version = isPublic ? 'public' : 'p2p'; const response = await fetch('/api/update-version-preference', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain, version }) }); if (!response.ok) { throw new Error(await response.text()); } if (window.showNotification) window.showNotification(`Version preference for ${domain} set to ${version}`); if (window.genericFetch) window.genericFetch('dns-conflicts', true); } catch (err) { console.error('Failed to update version preference:', err); if (window.showNotification) window.showNotification('Failed to update version preference: ' + err.message, 'error'); } } async function toggleHashPreference(domain, useLocal) { const newPreference = useLocal ? 'local' : 'resolved'; // Immediately update UI to show pending state if (window.showNotification) { window.showNotification(`Switching hash preference for ${domain}...`, 'info'); } try { // Step 1: Update the preference const response = await fetch('/api/update-hash-preference', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain, preference: newPreference }) }); if (!response.ok) { throw new Error(await response.text()); } // Step 2: Clear DNS cache for immediate effect await fetch('/api/clear-dns-cache', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain }) }); // Step 3: Wait for Holesail clients to fully restart await fetch('/api/restart-holesail-clients-for-domain', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain }) }); // Step 4: Verify the new connections are ready (small delay for startup) await new Promise(resolve => setTimeout(resolve, 500)); // Success - update UI if (window.showNotification) { window.showNotification(`Hash preference for ${domain} set to ${newPreference}`); } if (window.genericFetch) { window.genericFetch('p2p-domain-conflicts', true); } } catch (err) { console.error('Failed to update hash preference:', err); if (window.showNotification) { window.showNotification('Failed to update hash preference: ' + err.message, 'error'); } } } window.openLocalDnsModal = openLocalDnsModal; window.updateLocalForm = updateLocalForm; window.submitLocalDns = submitLocalDns; window.editLocalDns = editLocalDns; window.deleteLocalDns = deleteLocalDns; window.toggleVersionPreference = toggleVersionPreference;