Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.nio.file.FileAlreadyExistsException
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.nio.file.attribute.FileTime
import java.security.MessageDigest
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import java.util.zip.*
import kotlin.coroutines.CoroutineContext
Expand Down Expand Up @@ -265,57 +266,83 @@ class BackupDatabaseService(
}
}
}
val md5 = if (sourceFile.isFile) sourceFile.inputStream().digest("MD5")
else ""
dbQuery {
BackupEntryTable.selectAll().where {
BackupEntryTable.path eq path.toString() and
(BackupEntryTable.isDirectory eq sourceFile.isDirectory) and
(BackupEntryTable.hash eq md5)
}.map { it.toBackupEntry() }.firstOrNull {
it.valid(this@BackupDatabaseService)
}
}?.let { return@retry it }

val blob = getBlobFile(md5)
val gzip = sourceFile.length() > 1024
val zippedSize: Long
val gzip = sourceFile.isFile && sourceFile.length() > 1024
var md5 = ""
var zippedSize: Long
if (sourceFile.isFile) {
if (!blob.exists()) runCatching {
// fuck u mcos
blob.createParentDirectories().createFile()
}
if (!gzip) {
try {
blob.outputStream().buffered().use { output ->
val beforeSize = sourceFile.length()
val beforeModified = sourceFile.lastModified()
val tempBlob = blobDir.resolve(".tmp").resolve(UUID.randomUUID().toString())
try {
tempBlob.createParentDirectories()
val digest = MessageDigest.getInstance("MD5")
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
if (gzip) {
GZIPOutputStream(tempBlob.outputStream().buffered()).use { output ->
sourceFile.inputStream().buffered().use { input ->
input.copyTo(output)
var read: Int
while (input.read(buffer).also { read = it } > 0) {
digest.update(buffer, 0, read)
output.write(buffer, 0, read)
}
}
}
} else {
tempBlob.outputStream().buffered().use { output ->
sourceFile.inputStream().buffered().use { input ->
var read: Int
while (input.read(buffer).also { read = it } > 0) {
digest.update(buffer, 0, read)
output.write(buffer, 0, read)
}
}
}
} catch (_: FileAlreadyExistsException) {
// fuck u macos
}
zippedSize = sourceFile.length()
}
else {
GZIPOutputStream(blob.outputStream().buffered()).use { stream ->
sourceFile.inputStream().buffered().use { input ->
input.copyTo(stream)
md5 = digest.digest().joinToString("") { "%02x".format(it) }
zippedSize = tempBlob.fileSize()

val afterSize = sourceFile.length()
val afterModified = sourceFile.lastModified()
if (beforeSize != afterSize || beforeModified != afterModified) {
tempBlob.deleteIfExists()
error("File changed while creating backup, file: $path")
}

dbQuery {
BackupEntryTable.selectAll().where {
BackupEntryTable.path eq path.toString() and
(BackupEntryTable.isDirectory eq sourceFile.isDirectory) and
(BackupEntryTable.hash eq md5)
}.map { it.toBackupEntry() }.firstOrNull {
it.valid(this@BackupDatabaseService)
}
}?.let {
tempBlob.deleteIfExists()
return@retry it
}

val blob = getBlobFile(md5)
if (blob.exists() && blob.fileSize() == zippedSize) {
tempBlob.deleteIfExists()
} else {
blob.createParentDirectories()
try {
tempBlob.moveTo(blob, StandardCopyOption.REPLACE_EXISTING)
} catch (e: IOException) {
if (blob.exists() && blob.fileSize() == zippedSize) {
tempBlob.deleteIfExists()
} else {
throw e
}
}
}
zippedSize = blob.fileSize()
} catch (e: Throwable) {
tempBlob.deleteIfExists()
throw e
}
}
else {
} else {
zippedSize = 0
}
if (sourceFile.isFile) {
if (MessageDigest.getInstance("MD5").digest(sourceFile.readBytes())
.joinToString("") { "%02x".format(it) } != md5
) {
error("File hash mismatch when creating backup, file: $path, expected: $md5")
}
}
syncDbQuery {
val backupEntry = BackupEntryTable.insert {
it[this.path] = path.toString()
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pluginManagement {

plugins {
id("dev.kikugie.stonecutter") version "0.7.7-beta.2"
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}

rootProject.name = "X Backup"
Expand All @@ -33,6 +34,7 @@ stonecutter {
"1.21.5",
"1.21.6",
"1.21.9",
"1.21.11",
)
}
create(rootProject)
Expand Down
14 changes: 14 additions & 0 deletions src/main/kotlin/com/github/zly2006/xbackup/Commands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.encodeToStream
import kotlinx.serialization.json.put
import me.lucko.fabric.api.permissions.v0.Permissions
//? if >=1.21.11 {
import net.minecraft.command.DefaultPermissions
//?}
import net.minecraft.command.argument.ColumnPosArgumentType
import net.minecraft.server.command.ServerCommandSource
import net.minecraft.text.ClickEvent
Expand Down Expand Up @@ -744,7 +747,18 @@ object Commands {
Permissions.check(source, perm, defaultLevel)
} catch (e: NoClassDefFoundError) {
// If the API is not available, just return true
//? if >=1.21.11 {
val permission = when {
defaultLevel <= 0 -> null
defaultLevel <= 1 -> DefaultPermissions.MODERATORS
defaultLevel <= 2 -> DefaultPermissions.GAMEMASTERS
defaultLevel <= 3 -> DefaultPermissions.ADMINS
else -> DefaultPermissions.OWNERS
}
permission == null || source.permissions.hasPermission(permission)
//?} else {
source.hasPermissionLevel(defaultLevel)
//?}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/com/github/zly2006/xbackup/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ object Utils {

inline fun MinecraftServer.save() {
saveAll(false, false, true)
//? if >=1.21.11 {
syncChunkWrites()
//?}
}

inline fun MinecraftServer.finishRestore() {
Expand Down
11 changes: 8 additions & 3 deletions src/main/kotlin/com/github/zly2006/xbackup/XBackup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ object XBackup : ModInitializer {

fun loadConfig() {
try {
config = (if (configPath.exists()) Json.decodeFromString(configPath.readText())
config = (if (configPath.exists()) json.decodeFromString(configPath.readText())
else Config())
config.language = I18n.setLanguage(config.language)
} catch (e: Exception) {
Expand All @@ -92,6 +92,7 @@ object XBackup : ModInitializer {
encodeDefaults = true
prettyPrint = true
allowTrailingComma = true
ignoreUnknownKeys = true
}

fun saveConfig() {
Expand Down Expand Up @@ -146,7 +147,11 @@ object XBackup : ModInitializer {
ServerLifecycleEvents.SERVER_STARTED.register { server ->
this.server = server

server.commandManager.executeWithPrefix(XBackup.server!!.commandSource ,"1")
//? if >= 1.21.11 {
server.commandManager.parseAndExecute(XBackup.server!!.commandSource, "1")
//?} else {
server.commandManager.executeWithPrefix(XBackup.server!!.commandSource, "1")
//?}
kotlin.runCatching {
// sync client language to the integrated server
config.language = I18n.setLanguage(MinecraftClient.getInstance().options.language)
Expand All @@ -160,7 +165,7 @@ object XBackup : ModInitializer {
val database = getDatabaseFromWorld(worldPath)
if (config.mirrorMode) {
val sourceConfig = kotlin.runCatching {
Json.decodeFromStream<Config>(
json.decodeFromStream<Config>(
Path(
config.mirrorFrom!!,
"config",
Expand Down
2 changes: 1 addition & 1 deletion stonecutter.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id("dev.kikugie.stonecutter")
id("fabric-loom") version "1.11-SNAPSHOT" apply false
id("fabric-loom") version "1.13.3" apply false

kotlin("jvm") version "2.0.21" apply false
kotlin("plugin.serialization") version "2.0.0" apply false
Expand Down
8 changes: 8 additions & 0 deletions versions/1.21.11/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# https://fabricmc.net/develop
deps.yarn_build=4
deps.fabric_api=0.141.1+1.21.11

mod.mc_dep=>=1.21.11 <=1.21.11
mod.mc_title=1.21.11
mod.mc_targets=1.21.11
deps.poly_lib=2111.1.1
Loading