PassbirdApplication.kt

package de.pflugradts.passbird.application.boot.main
import de.pflugradts.passbird.application.InactivityTerminationRequestedException
import de.pflugradts.passbird.application.RunContext
import de.pflugradts.passbird.application.StdinTerminationRequestedException
import de.pflugradts.passbird.application.UserInterfaceAdapterPort
import de.pflugradts.passbird.application.boot.Bootable
import de.pflugradts.passbird.application.commandhandling.InputHandler
import de.pflugradts.passbird.application.process.Initializer
import de.pflugradts.passbird.application.process.inactivity.InactivityHandler
import de.pflugradts.passbird.domain.model.nest.Nest
import de.pflugradts.passbird.domain.model.shell.Shell.Companion.shellOf
import de.pflugradts.passbird.domain.model.transfer.Input
import de.pflugradts.passbird.domain.model.transfer.Output.Companion.outputOf
import de.pflugradts.passbird.domain.model.transfer.OutputFormatting.NEST
import de.pflugradts.passbird.domain.service.nest.NestService
const val INTERRUPT = 0x03.toChar()
class PassbirdApplication constructor(
    private val inactivityHandler: InactivityHandler,
    private val initializers: Set<Initializer>,
    private val inputHandler: InputHandler,
    private val nestService: NestService,
    private val runContext: RunContext,
    private val userInterfaceAdapterPort: UserInterfaceAdapterPort,
) : Bootable {
    override fun boot() {
        userInterfaceAdapterPort.sendLineBreak()
        nestService.moveToNestAt(runContext.initialSlot)
        initializers.forEach { it.run() }
        while (true) {
            try {
                receiveInput().let { input ->
                    if (isSigTerm(input)) {
                        return
                    }
                    inactivityHandler.registerInteraction()
                    inputHandler.handleInput(input)
                }
            } catch (_: InactivityTerminationRequestedException) {
                inactivityHandler.handlePendingTermination()
                return
            } catch (_: StdinTerminationRequestedException) {
                return
            }
        }
    }
    private fun receiveInput() = userInterfaceAdapterPort.receive(
        outputOf(shellOf(nestPrefix()), NEST),
        outputOf(shellOf("Enter command: ")),
    )
    private fun nestPrefix() = nestService.currentNest().let {
        if (it == Nest.DEFAULT) "" else "[${it.viewNestId().asString()}] "
    }
    private fun isSigTerm(input: Input) = input.data.isEmpty && !input.command.isEmpty && input.command.firstByte == INTERRUPT.code.toByte()
}