Add backup
This commit is contained in:
parent
94c35b9067
commit
07a619f826
|
@ -85,6 +85,7 @@
|
|||
.board-running {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
|
||||
&:empty + .board-running-empty {
|
||||
display: block;
|
||||
|
|
|
@ -3,6 +3,7 @@ package de.kif.backend
|
|||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import de.kif.backend.route.*
|
||||
import de.kif.backend.route.api.*
|
||||
import de.kif.backend.util.Backup
|
||||
import de.kif.backend.util.pushService
|
||||
import io.ktor.application.Application
|
||||
import io.ktor.application.call
|
||||
|
@ -101,4 +102,6 @@ fun Application.main() {
|
|||
}
|
||||
|
||||
logger.info { "Responding at http://${Configuration.Server.host}:${Configuration.Server.port}$prefix/" }
|
||||
|
||||
Backup.startBackupService()
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ object Configuration {
|
|||
val uploads by required<String>()
|
||||
val database by required<String>()
|
||||
val announcement by required<String>()
|
||||
val backup by required<String>()
|
||||
}
|
||||
|
||||
object Path {
|
||||
|
@ -60,6 +61,9 @@ object Configuration {
|
|||
|
||||
val announcement by c(PathSpec.announcement)
|
||||
val announcementPath: java.nio.file.Path by lazy { Paths.get(announcement).toAbsolutePath() }
|
||||
|
||||
val backup by c(PathSpec.backup)
|
||||
val backupPath: java.nio.file.Path by lazy { Paths.get(backup).toAbsolutePath() }
|
||||
}
|
||||
|
||||
private object ScheduleSpec : ConfigSpec("schedule") {
|
||||
|
@ -93,6 +97,7 @@ object Configuration {
|
|||
private object GeneralSpec : ConfigSpec("general") {
|
||||
val allowedUploadExtensions by required<String>("allowed_upload_extensions")
|
||||
val wikiUrl by required<String>("wiki_url")
|
||||
val backupInterval by required<Long>("backup_interval")
|
||||
}
|
||||
|
||||
object General {
|
||||
|
@ -101,6 +106,7 @@ object Configuration {
|
|||
allowedUploadExtensions.split(",").map { it.trim().toLowerCase() }.toSet()
|
||||
}
|
||||
val wikiUrl by c(GeneralSpec.wikiUrl)
|
||||
val backupInterval by c(GeneralSpec.backupInterval)
|
||||
}
|
||||
|
||||
private object TwitterSpec : ConfigSpec("twitter") {
|
||||
|
|
|
@ -83,11 +83,19 @@ object Resources {
|
|||
Files.createDirectories(Configuration.Path.sessionsPath)
|
||||
Files.createDirectories(Configuration.Path.uploadsPath)
|
||||
Files.createDirectories(Configuration.Path.webPath)
|
||||
Files.createDirectories(Configuration.Path.backupPath)
|
||||
|
||||
if (!Files.exists(Configuration.Path.announcementPath)) {
|
||||
Files.createFile(Configuration.Path.announcementPath)
|
||||
}
|
||||
|
||||
logger.info { "Database path: ${Configuration.Path.databasePath}" }
|
||||
logger.info { "Sessions path: ${Configuration.Path.sessionsPath}" }
|
||||
logger.info { "Uploads path: ${Configuration.Path.uploadsPath}" }
|
||||
logger.info { "Web path: ${Configuration.Path.webPath}" }
|
||||
logger.info { "Backup path: ${Configuration.Path.backupPath}" }
|
||||
|
||||
logger.info { "Announcement file: ${Configuration.Path.announcementPath}" }
|
||||
|
||||
logger.info { "Extract web content..." }
|
||||
extractWeb()
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
package de.kif.backend.util
|
||||
|
||||
import de.kif.backend.Configuration
|
||||
import de.kif.backend.database.Connection
|
||||
import de.kif.backend.repository.*
|
||||
import de.kif.common.RepositoryType
|
||||
import de.kif.common.Serialization
|
||||
import de.kif.common.model.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.Serializable
|
||||
import mu.KotlinLogging
|
||||
import java.lang.Exception
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
@Serializable
|
||||
data class Backup(
|
||||
|
@ -17,6 +24,8 @@ data class Backup(
|
|||
val workGroups: List<WorkGroup> = emptyList()
|
||||
) {
|
||||
companion object {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
suspend fun backup(vararg repositories: RepositoryType): String {
|
||||
var backup = Backup()
|
||||
|
||||
|
@ -78,7 +87,9 @@ data class Backup(
|
|||
var workGroup = it
|
||||
val track = workGroup.track
|
||||
if (track != null) {
|
||||
workGroup = workGroup.copy(track = track.copy(id = trackMap.firstOrNull { (i,_) -> i.equalsIgnoreId(track) }?.second ?: run {
|
||||
workGroup = workGroup.copy(track = track.copy(id = trackMap.firstOrNull { (i, _) ->
|
||||
i.equalsIgnoreId(track)
|
||||
}?.second ?: run {
|
||||
println("Cannot import work group, due to missing track")
|
||||
return@mapNotNull null
|
||||
}))
|
||||
|
@ -94,14 +105,16 @@ data class Backup(
|
|||
newSchedules.forEach {
|
||||
ScheduleRepository.create(
|
||||
it.copy(
|
||||
room = it.room.copy(id = roomMap.firstOrNull { (i,_) -> i.equalsIgnoreId(it.room) }?.second ?: run {
|
||||
println("Cannot import schedule, due to missing room")
|
||||
return@forEach
|
||||
}),
|
||||
workGroup = it.workGroup.copy(id = workGroupMap.firstOrNull { (i,_) -> i.equalsIgnoreId(it.workGroup) }?.second ?: run {
|
||||
println("Cannot import schedule, due to missing work group")
|
||||
return@forEach
|
||||
})
|
||||
room = it.room.copy(
|
||||
id = roomMap.firstOrNull { (i, _) -> i.equalsIgnoreId(it.room) }?.second ?: run {
|
||||
println("Cannot import schedule, due to missing room")
|
||||
return@forEach
|
||||
}),
|
||||
workGroup = it.workGroup.copy(
|
||||
id = workGroupMap.firstOrNull { (i, _) -> i.equalsIgnoreId(it.workGroup) }?.second ?: run {
|
||||
println("Cannot import schedule, due to missing work group")
|
||||
return@forEach
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -114,5 +127,39 @@ data class Backup(
|
|||
|
||||
import(data)
|
||||
}
|
||||
|
||||
fun startBackupService() {
|
||||
val backupPath = Configuration.Path.backupPath.toFile()
|
||||
val backupInterval = Configuration.General.backupInterval
|
||||
|
||||
val formatter = SimpleDateFormat("yyyyMMdd'T'HHmmss")
|
||||
|
||||
thread(
|
||||
start = true,
|
||||
isDaemon = true,
|
||||
name = "backup-service"
|
||||
) {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(backupInterval)
|
||||
|
||||
if (!backupPath.exists()) {
|
||||
backupPath.mkdirs()
|
||||
}
|
||||
|
||||
val date = formatter.format(Date())
|
||||
|
||||
val backupFile = backupPath.resolve("backup_$date.json")
|
||||
|
||||
val backup = runBlocking {
|
||||
backup(*RepositoryType.values())
|
||||
}
|
||||
backupFile.writeText(backup)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "Cannot create backup" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ sessions = "data/sessions"
|
|||
uploads = "data/uploads"
|
||||
database = "data/portal.db"
|
||||
announcement = "data/announcement.txt"
|
||||
backup = "data/backup"
|
||||
|
||||
[schedule]
|
||||
reference = "1970-01-01"
|
||||
|
@ -27,6 +28,7 @@ sign_key = "d1 20 23 8c 01 f8 f0 0d 9d 7c ff 68 21 97 75 31 38 3f fb 91 20 3a 8d
|
|||
[general]
|
||||
allowed_upload_extensions = "png, jpg, jpeg"
|
||||
wiki_url = ""
|
||||
backup_interval = 3600000
|
||||
|
||||
[twitter]
|
||||
timeline = ""
|
||||
|
|
Loading…
Reference in a new issue