PasswordTreeWriter.kt

package de.pflugradts.passbird.adapter.passwordtree
import de.pflugradts.kotlinextensions.TryResult
import de.pflugradts.kotlinextensions.tryCatching
import de.pflugradts.passbird.application.configuration.ReadableConfiguration
import de.pflugradts.passbird.application.configuration.ReadableConfiguration.Companion.PASSWORD_TREE_FILENAME
import de.pflugradts.passbird.application.failure.WritePasswordTreeFailure
import de.pflugradts.passbird.application.failure.reportFailure
import de.pflugradts.passbird.application.passwordtree.PasswordTreeEnvelope
import de.pflugradts.passbird.application.passwordtree.PasswordTreePayloadWriter
import de.pflugradts.passbird.application.passwordtree.PasswordTreeSnapshot
import de.pflugradts.passbird.application.toDirectory
import de.pflugradts.passbird.application.toFileName
import de.pflugradts.passbird.application.util.SystemOperation
import de.pflugradts.passbird.domain.model.shell.Shell
import de.pflugradts.passbird.domain.service.password.encryption.CryptoProvider
import de.pflugradts.passbird.domain.service.password.tree.EggStreamSupplier
import de.pflugradts.passbird.domain.service.password.tree.emptyMemory
class PasswordTreeWriter constructor(
    private val systemOperation: SystemOperation,
    private val configuration: ReadableConfiguration,
    private val cryptoProvider: CryptoProvider,
    private val passwordTreeEnvelope: PasswordTreeEnvelope,
    private val passwordTreePayloadWriter: PasswordTreePayloadWriter,
) {
    fun sync(eggSupplier: EggStreamSupplier): TryResult<Unit> {
        val eggs = eggSupplier.get().toList()
        return writeToDisk(
            passwordTreePayloadWriter.write(
                PasswordTreeSnapshot(
                    eggs = eggs,
                    favorites = eggSupplier.favorites(),
                    memory = if (configuration.domain.eggIdMemory.persisted) eggSupplier.memory() else emptyMemory(),
                    nests = eggSupplier.nests(),
                ),
            ),
        )
    }
    private fun writeToDisk(shell: Shell) = tryCatching {
        try {
            systemOperation.writeBytesToSensitiveFile(filePath, passwordTreeEnvelope.wrap(cryptoProvider.encrypt(shell).toByteArray()))
        } finally {
            shell.scramble()
        }
        Unit
    }.onFailure { reportFailure(WritePasswordTreeFailure(filePath, it)) }
    private val filePath get() =
        systemOperation.resolvePath(configuration.adapter.passwordTree.location.toDirectory(), PASSWORD_TREE_FILENAME.toFileName())
}