|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
|
|
|
const form = document.getElementById('campaign-form'); |
|
|
const startBtn = document.getElementById('start-btn'); |
|
|
const pauseBtn = document.getElementById('pause-btn'); |
|
|
const stopBtn = document.getElementById('stop-btn'); |
|
|
const logOutput = document.getElementById('log-output'); |
|
|
const trlTextarea = document.getElementById('trl'); |
|
|
const templateNewNationsBtn = document.getElementById('template-new-nations-btn'); |
|
|
const templateWaDelegatesBtn = document.getElementById('template-wa-delegates-btn'); |
|
|
|
|
|
let eventSource = null; |
|
|
|
|
|
|
|
|
function updateUI(status) { |
|
|
if (status === 'running') { |
|
|
startBtn.disabled = true; |
|
|
pauseBtn.disabled = false; |
|
|
pauseBtn.textContent = 'Pause'; |
|
|
stopBtn.disabled = false; |
|
|
setFormDisabled(true); |
|
|
} else if (status === 'paused') { |
|
|
startBtn.disabled = true; |
|
|
pauseBtn.disabled = false; |
|
|
pauseBtn.textContent = 'Resume'; |
|
|
stopBtn.disabled = false; |
|
|
setFormDisabled(true); |
|
|
} else { |
|
|
startBtn.disabled = false; |
|
|
pauseBtn.disabled = true; |
|
|
pauseBtn.textContent = 'Pause'; |
|
|
stopBtn.disabled = true; |
|
|
setFormDisabled(false); |
|
|
if (eventSource) { |
|
|
eventSource.close(); |
|
|
eventSource = null; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
function setFormDisabled(disabled) { |
|
|
const elements = form.elements; |
|
|
for (let i = 0; i < elements.length; i++) { |
|
|
elements[i].disabled = disabled; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function connectToLogStream() { |
|
|
if (eventSource) { |
|
|
eventSource.close(); |
|
|
} |
|
|
logOutput.textContent = 'Connecting to log stream...\n'; |
|
|
eventSource = new EventSource('/api/logs'); |
|
|
|
|
|
eventSource.onmessage = (event) => { |
|
|
logOutput.textContent += event.data + '\n'; |
|
|
logOutput.scrollTop = logOutput.scrollHeight; |
|
|
}; |
|
|
|
|
|
eventSource.onerror = () => { |
|
|
logOutput.textContent += '--- Connection to log stream lost. Reconnecting... ---\n'; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
eventSource.addEventListener('close', () => { |
|
|
logOutput.textContent += '--- Log stream closed by server. ---\n'; |
|
|
eventSource.close(); |
|
|
updateUI('stopped'); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
async function postWithFeedback(url, body) { |
|
|
try { |
|
|
const response = await fetch(url, { |
|
|
method: 'POST', |
|
|
headers: { 'Content-Type': 'application/json' }, |
|
|
body: body ? JSON.stringify(body) : null, |
|
|
credentials: 'include', |
|
|
}); |
|
|
if (!response.ok) { |
|
|
const error = await response.json(); |
|
|
alert(`Error: ${error.error || 'Unknown error'}`); |
|
|
return false; |
|
|
} |
|
|
return true; |
|
|
} catch (error) { |
|
|
alert(`Network error: ${error.message}`); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function saveSettings() { |
|
|
const formData = new FormData(form); |
|
|
const settings = {}; |
|
|
formData.forEach((value, key) => { |
|
|
if (form.elements[key].type === 'checkbox') { |
|
|
settings[key] = form.elements[key].checked; |
|
|
} else { |
|
|
settings[key] = value; |
|
|
} |
|
|
}); |
|
|
localStorage.setItem('nsrecruit_settings', JSON.stringify(settings)); |
|
|
} |
|
|
|
|
|
function loadSettings() { |
|
|
const settings = JSON.parse(localStorage.getItem('nsrecruit_settings')); |
|
|
if (settings) { |
|
|
Object.keys(settings).forEach(key => { |
|
|
const element = form.elements[key]; |
|
|
if (element) { |
|
|
if (element.type === 'checkbox') { |
|
|
element.checked = settings[key]; |
|
|
} else if (element.type === 'radio') { |
|
|
|
|
|
document.querySelector(`input[name="${key}"][value="${settings[key]}"]`).checked = true; |
|
|
} else { |
|
|
element.value = settings[key]; |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
startBtn.addEventListener('click', async () => { |
|
|
if (!form.reportValidity()) return; |
|
|
|
|
|
const settings = { |
|
|
client_key: form.elements['client_key'].value, |
|
|
tg_id: form.elements['tg_id'].value, |
|
|
secret_key: form.elements['secret_key'].value, |
|
|
trl: form.elements['trl'].value, |
|
|
tg_type: form.elements['tg_type'].value, |
|
|
dry_run: form.elements['dry_run'].checked, |
|
|
continuous: form.elements['continuous'].checked, |
|
|
}; |
|
|
|
|
|
const success = await postWithFeedback('/api/start', settings); |
|
|
if (success) { |
|
|
updateUI('running'); |
|
|
connectToLogStream(); |
|
|
} |
|
|
}); |
|
|
|
|
|
pauseBtn.addEventListener('click', async () => { |
|
|
const action = pauseBtn.textContent.toLowerCase(); |
|
|
const success = await postWithFeedback(`/api/control/${action}`); |
|
|
if (success) { |
|
|
updateUI(action === 'pause' ? 'paused' : 'running'); |
|
|
} |
|
|
}); |
|
|
|
|
|
stopBtn.addEventListener('click', async () => { |
|
|
if (!confirm('Are you sure you want to stop the campaign?')) return; |
|
|
const success = await postWithFeedback('/api/control/stop'); |
|
|
if (success) { |
|
|
updateUI('stopped'); |
|
|
} |
|
|
}); |
|
|
|
|
|
form.addEventListener('change', saveSettings); |
|
|
|
|
|
templateNewNationsBtn.addEventListener('click', () => { |
|
|
const template = `# Get a pool of the latest 50 new nations |
|
|
+new [50]; |
|
|
|
|
|
# Remove nations ending in a number (e.g., "My Nation 5") |
|
|
-name_regex [\\d$]; |
|
|
|
|
|
# Remove nations ending in an underscore and Roman numerals (e.g., "queen_vii") |
|
|
-name_regex [[\\s_][ivxlcdmIVXLCDM]+$]; |
|
|
`; |
|
|
trlTextarea.value = template; |
|
|
|
|
|
trlTextarea.dispatchEvent(new Event('change', { bubbles: true })); |
|
|
}); |
|
|
|
|
|
templateWaDelegatesBtn.addEventListener('click', () => { |
|
|
const template = `# Get all World Assembly delegates |
|
|
+wa [delegates]; |
|
|
`; |
|
|
trlTextarea.value = template; |
|
|
|
|
|
trlTextarea.dispatchEvent(new Event('change', { bubbles: true })); |
|
|
}); |
|
|
|
|
|
|
|
|
async function initialize() { |
|
|
loadSettings(); |
|
|
try { |
|
|
const response = await fetch('/api/state', { credentials: 'include' }); |
|
|
const state = await response.json(); |
|
|
updateUI(state.status); |
|
|
if (state.status !== 'stopped') { |
|
|
connectToLogStream(); |
|
|
} |
|
|
} catch (error) { |
|
|
logOutput.textContent = 'Could not fetch initial state from server.'; |
|
|
} |
|
|
} |
|
|
|
|
|
initialize(); |
|
|
}); |