291 lines
9.1 KiB
JavaScript
291 lines
9.1 KiB
JavaScript
const state = {
|
|
manifestUrl: '',
|
|
selectedPack: null,
|
|
selectedPackMeta: null,
|
|
installPath: '',
|
|
jdkPath: ''
|
|
}
|
|
|
|
const panelMap = new Map([...document.querySelectorAll('.panel')].map((panel) => [panel.dataset.panel, panel]))
|
|
const stepMap = new Map([...document.querySelectorAll('.steps li')].map((step) => [step.dataset.step, step]))
|
|
const logView = document.getElementById('logView')
|
|
const packList = document.getElementById('packList')
|
|
const manifestUrlInput = document.getElementById('manifestUrl')
|
|
const installPathInput = document.getElementById('installPath')
|
|
const jdkPathInput = document.getElementById('jdkPath')
|
|
const jdkStatus = document.getElementById('jdkStatus')
|
|
const jdkRecommended = document.getElementById('jdkRecommended')
|
|
const eulaBlock = document.getElementById('eulaBlock')
|
|
const eulaText = document.getElementById('eulaText')
|
|
const eulaLink = document.getElementById('eulaLink')
|
|
const startInstallButton = document.getElementById('startInstallButton')
|
|
|
|
function setActiveStep(step) {
|
|
for (const [key, panel] of panelMap.entries()) {
|
|
panel.classList.toggle('active', key === String(step))
|
|
}
|
|
|
|
for (const [key, item] of stepMap.entries()) {
|
|
item.classList.toggle('active', key === String(step))
|
|
}
|
|
}
|
|
|
|
function appendLog(entry) {
|
|
if (entry?.action === 'eula-required') {
|
|
eulaText.textContent = entry.eulaText ?? ''
|
|
eulaLink.href = entry.eulaUrl ?? '#'
|
|
eulaBlock.classList.remove('hidden')
|
|
return
|
|
}
|
|
|
|
const line = `[${entry?.tone ?? 'info'}] ${entry?.message ?? ''}`
|
|
logView.textContent += `${line}\n`
|
|
logView.scrollTop = logView.scrollHeight
|
|
}
|
|
|
|
function validateInstallPath(pathValue) {
|
|
const warning = document.getElementById('installPathWarning')
|
|
const hasHangul = /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(pathValue)
|
|
warning.textContent = hasHangul ? '경로에 한글이 포함되면 안 됩니다.' : ''
|
|
return !hasHangul && pathValue.trim().length > 0
|
|
}
|
|
|
|
function renderPackList(packs) {
|
|
packList.innerHTML = ''
|
|
packs.forEach((pack) => {
|
|
const label = document.createElement('label')
|
|
label.className = 'packOption'
|
|
label.innerHTML = `
|
|
<input type="radio" name="packChoice" value="${pack.file}" data-pack-name="${pack.name}" />
|
|
<div>
|
|
<strong>${pack.name}</strong>
|
|
<span>${pack.file}</span>
|
|
</div>
|
|
`
|
|
packList.appendChild(label)
|
|
})
|
|
}
|
|
|
|
async function loadPackManifest() {
|
|
state.manifestUrl = manifestUrlInput.value.trim()
|
|
state.selectedPack = null
|
|
state.selectedPackMeta = null
|
|
packList.innerHTML = '<div class="infoBox">서버팩 목록을 불러오는 중입니다.</div>'
|
|
try {
|
|
const manifest = await window.installerApi.loadPacks(state.manifestUrl)
|
|
renderPackList(manifest.packs)
|
|
} catch (error) {
|
|
packList.innerHTML = `<div class="infoBox">${error.message}</div>`
|
|
}
|
|
}
|
|
|
|
async function loadSelectedPackMeta() {
|
|
if (state.selectedPack == null) {
|
|
state.selectedPackMeta = null
|
|
return null
|
|
}
|
|
|
|
const packMeta = await window.installerApi.inspectPack(state.manifestUrl, state.selectedPack.file)
|
|
state.selectedPackMeta = packMeta
|
|
return packMeta
|
|
}
|
|
|
|
async function autoDetectJdkForSelectedPack() {
|
|
const packMeta = await loadSelectedPackMeta()
|
|
if (packMeta == null) {
|
|
jdkRecommended.textContent = '먼저 서버팩을 선택하세요.'
|
|
jdkStatus.textContent = ''
|
|
return
|
|
}
|
|
|
|
const recommendedVersion = packMeta.packDefinition.recommendedJdkVersion ?? null
|
|
jdkRecommended.textContent = recommendedVersion != null
|
|
? `선택한 서버팩의 권장 JDK 버전: ${recommendedVersion}`
|
|
: '선택한 서버팩에 권장 JDK 버전 정보가 없습니다.'
|
|
|
|
jdkStatus.textContent = 'JDK 자동 탐색 중입니다.'
|
|
const result = await window.installerApi.detectJdk(recommendedVersion)
|
|
if (result.detected != null) {
|
|
state.jdkPath = result.detected
|
|
jdkPathInput.value = result.detected
|
|
}
|
|
|
|
if (result.detected == null) {
|
|
jdkStatus.textContent = '설치 가능한 JDK를 찾지 못했습니다.'
|
|
return
|
|
}
|
|
|
|
const pickedCandidate = result.candidates.find((candidate) => candidate.path === result.detected)
|
|
const versionLabel = pickedCandidate?.majorVersion != null ? `JDK ${pickedCandidate.majorVersion}` : '버전 미확인 JDK'
|
|
if (result.recommendedVersion != null && result.exactMatch) {
|
|
jdkStatus.textContent = `권장 버전과 일치하는 ${versionLabel}를 자동 선택했습니다: ${result.detected}`
|
|
return
|
|
}
|
|
|
|
if (result.recommendedVersion != null) {
|
|
jdkStatus.textContent = `권장 JDK ${result.recommendedVersion}은 찾지 못해 ${versionLabel}를 대신 선택했습니다: ${result.detected}`
|
|
return
|
|
}
|
|
|
|
jdkStatus.textContent = `자동 탐색 성공: ${versionLabel} / ${result.detected}`
|
|
}
|
|
|
|
async function goToStep(step) {
|
|
setActiveStep(step)
|
|
|
|
if (step === 3) {
|
|
try {
|
|
await autoDetectJdkForSelectedPack()
|
|
} catch (error) {
|
|
jdkStatus.textContent = error.message
|
|
}
|
|
}
|
|
}
|
|
|
|
async function bootstrap() {
|
|
const defaults = await window.installerApi.getDefaults()
|
|
state.manifestUrl = defaults.manifestUrl
|
|
manifestUrlInput.value = defaults.manifestUrl
|
|
await loadPackManifest()
|
|
}
|
|
|
|
window.installerApi.onLog(appendLog)
|
|
|
|
packList.addEventListener('change', () => {
|
|
const checked = packList.querySelector('input[name="packChoice"]:checked')
|
|
if (checked == null) {
|
|
state.selectedPack = null
|
|
state.selectedPackMeta = null
|
|
return
|
|
}
|
|
state.selectedPack = {
|
|
file: checked.value,
|
|
name: checked.dataset.packName ?? checked.value
|
|
}
|
|
state.selectedPackMeta = null
|
|
})
|
|
|
|
document.querySelectorAll('[data-back]').forEach((button) => {
|
|
button.addEventListener('click', async () => {
|
|
await goToStep(button.dataset.back)
|
|
})
|
|
})
|
|
|
|
manifestUrlInput.addEventListener('change', async () => {
|
|
await loadPackManifest()
|
|
})
|
|
|
|
document.getElementById('toStep2').addEventListener('click', async () => {
|
|
if (state.selectedPack == null) {
|
|
alert('서버팩을 먼저 선택하세요.')
|
|
return
|
|
}
|
|
await goToStep(2)
|
|
})
|
|
|
|
document.getElementById('browseInstallPath').addEventListener('click', async () => {
|
|
const selected = await window.installerApi.chooseDirectory()
|
|
if (selected != null) {
|
|
state.installPath = selected
|
|
installPathInput.value = selected
|
|
validateInstallPath(selected)
|
|
}
|
|
})
|
|
|
|
installPathInput.addEventListener('input', (event) => {
|
|
state.installPath = event.target.value
|
|
validateInstallPath(state.installPath)
|
|
})
|
|
|
|
document.getElementById('toStep3').addEventListener('click', async () => {
|
|
if (!validateInstallPath(state.installPath)) {
|
|
alert('올바른 설치 경로를 입력하세요.')
|
|
return
|
|
}
|
|
await goToStep(3)
|
|
})
|
|
|
|
document.getElementById('browseJdkPath').addEventListener('click', async () => {
|
|
const selected = await window.installerApi.chooseJdk()
|
|
if (selected != null) {
|
|
state.jdkPath = selected
|
|
jdkPathInput.value = selected
|
|
}
|
|
})
|
|
|
|
jdkPathInput.addEventListener('input', (event) => {
|
|
state.jdkPath = event.target.value
|
|
})
|
|
|
|
document.getElementById('toStep4').addEventListener('click', async () => {
|
|
if (state.jdkPath.trim().length === 0) {
|
|
alert('JDK 경로를 지정하세요.')
|
|
return
|
|
}
|
|
await goToStep(4)
|
|
})
|
|
|
|
startInstallButton.addEventListener('click', async () => {
|
|
if (state.selectedPack == null) {
|
|
alert('서버팩을 먼저 선택하세요.')
|
|
return
|
|
}
|
|
|
|
logView.textContent = ''
|
|
eulaBlock.classList.add('hidden')
|
|
eulaText.textContent = ''
|
|
startInstallButton.disabled = true
|
|
|
|
try {
|
|
const result = await window.installerApi.startInstall({
|
|
manifestUrl: state.manifestUrl,
|
|
packFile: state.selectedPack.file,
|
|
installPath: state.installPath,
|
|
jdkPath: state.jdkPath
|
|
})
|
|
if (result.warning != null) {
|
|
appendLog({ message: result.warning, tone: 'warn' })
|
|
}
|
|
await goToStep(result.nextStep)
|
|
} finally {
|
|
startInstallButton.disabled = false
|
|
}
|
|
})
|
|
|
|
document.getElementById('acceptEulaButton').addEventListener('click', async () => {
|
|
await window.installerApi.acceptEula()
|
|
eulaBlock.classList.add('hidden')
|
|
})
|
|
|
|
document.getElementById('openConfigEditorButton').addEventListener('click', async () => {
|
|
const url = await window.installerApi.openConfigEditor()
|
|
document.getElementById('configEditorStatus').textContent = `브라우저에서 열림: ${url}`
|
|
})
|
|
|
|
document.getElementById('toStep6').addEventListener('click', async () => {
|
|
await goToStep(6)
|
|
})
|
|
|
|
document.getElementById('configurePortButton').addEventListener('click', async () => {
|
|
const result = await window.installerApi.configurePort()
|
|
document.getElementById('portStatusBox').textContent = result.message
|
|
})
|
|
|
|
document.getElementById('toStep7').addEventListener('click', async () => {
|
|
await goToStep(7)
|
|
})
|
|
|
|
document.getElementById('openFolderButton').addEventListener('click', async () => {
|
|
await window.installerApi.openFolder()
|
|
})
|
|
|
|
document.getElementById('finishButton').addEventListener('click', async () => {
|
|
const createShortcut = document.getElementById('createShortcutToggle').checked
|
|
const runServer = document.getElementById('runServerToggle').checked
|
|
await window.installerApi.createShortcut(createShortcut)
|
|
await window.installerApi.runServer(runServer)
|
|
alert('설치가 완료되었습니다.')
|
|
})
|
|
|
|
bootstrap()
|