Skip to content

Commit 076a0fe

Browse files
committed
(draft) fix script caching / checksum calculation
1 parent 880f570 commit 076a0fe

File tree

2 files changed

+57
-21
lines changed

2 files changed

+57
-21
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package dev.echonine.kite.scripting.cache
2+
3+
import com.google.gson.GsonBuilder
4+
import com.google.gson.reflect.TypeToken
5+
import dev.echonine.kite.Kite
6+
import kotlinx.coroutines.sync.Mutex
7+
import kotlinx.coroutines.sync.withLock
8+
import java.io.File
9+
10+
typealias DependencyTree = List<String>
11+
12+
class ImportsCache {
13+
14+
private val mutex = Mutex()
15+
private val gson = GsonBuilder().setPrettyPrinting().create()
16+
private val file = Kite.instance!!.dataFolder.resolve("cache" + File.separator + ".imports")
17+
18+
private val typeToken = object : TypeToken<MutableMap<String, DependencyTree>>() { /* TYPE MARKER */ }
19+
20+
var cache: MutableMap<String, DependencyTree> = mutableMapOf()
21+
private set
22+
23+
suspend fun write(name: String, dependencies: List<String>) = mutex.withLock {
24+
if (!file.exists()) {
25+
file.parentFile.mkdirs()
26+
file.createNewFile()
27+
}
28+
// Reading file contents.
29+
cache = file.bufferedReader().use { gson.fromJson(it, typeToken) } ?: mutableMapOf()
30+
// Putting list of dependencies / imports to the map.
31+
cache[name] = dependencies
32+
// Saving contents to the file.
33+
file.bufferedWriter().use { gson.toJson(cache, typeToken.type, it) }
34+
}
35+
36+
}

src/main/kotlin/dev/echonine/kite/scripting/configuration/KiteCompilationConfiguration.kt

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ import dev.echonine.kite.api.annotations.Repository
88
import dev.echonine.kite.scripting.configuration.compat.DynamicServerJarCompat
99
import dev.echonine.kite.scripting.Script
1010
import dev.echonine.kite.scripting.ScriptContext
11+
import dev.echonine.kite.scripting.cache.ImportsCache
12+
import kotlinx.coroutines.CoroutineScope
13+
import kotlinx.coroutines.Dispatchers
14+
import kotlinx.coroutines.launch
1115
import org.bukkit.Server
1216
import org.bukkit.plugin.java.JavaPlugin
1317
import revxrsal.zapper.DependencyManager
1418
import revxrsal.zapper.classloader.URLClassLoaderWrapper
1519
import java.io.File
1620
import java.net.URLClassLoader
1721
import java.security.MessageDigest
22+
import kotlin.coroutines.CoroutineContext
1823
import kotlin.script.experimental.api.*
1924
import kotlin.script.experimental.host.FileBasedScriptSource
2025
import kotlin.script.experimental.host.FileScriptSource
@@ -54,6 +59,10 @@ val cacheDirectory by lazy {
5459
File(Kite.instance?.dataFolder?.path ?: System.getProperty("user.dir", "."), "cache")
5560
}
5661

62+
val importsCache by lazy {
63+
ImportsCache()
64+
}
65+
5766
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
5867
object KiteCompilationConfiguration : ScriptCompilationConfiguration({
5968
// Adding Bukkit APIs and Kite to default imports.
@@ -132,6 +141,10 @@ object KiteCompilationConfiguration : ScriptCompilationConfiguration({
132141
dependencies.append(JvmDependency(scriptDependencies.map { File(libsDirectory, it) }.filter { it.exists() }))
133142
// Appending imported sources to the script.
134143
importedSources.takeUnless { it.isEmpty() }?.let { importScripts.append(it) }
144+
CoroutineScope(Dispatchers.Default).launch {
145+
importsCache.write(context.compilationConfiguration[displayName]!!, importedSources.map { it.file.path }.toList())
146+
}
147+
135148
}.asSuccess()
136149
})
137150
}
@@ -146,31 +159,18 @@ object KiteCompilationConfiguration : ScriptCompilationConfiguration({
146159
if (cacheDirectory.isDirectory || cacheDirectory.mkdirs()) {
147160
// Configuring compilation cache.
148161
compilationCache(CompiledScriptJarsCache { script, compilationConfiguration ->
162+
val name = compilationConfiguration[displayName]
163+
val checksum = MessageDigest.getInstance("MD5")
149164
// Getting the MD5 checksum and including it in the file name.
150165
// MD5 checksum acts as a file identifier here.
151-
val mainScriptHash = script.text.toByteArray().let {
152-
val md = MessageDigest.getInstance("MD5")
153-
md.update(it)
154-
md.digest().joinToString("") { byte -> "%02x".format(byte) }
166+
checksum.update(script.text.toByteArray())
167+
// ...
168+
importsCache.cache[name]?.forEach {
169+
checksum.update(File(it).readBytes())
155170
}
156-
// Also hash the imported scripts
157-
val importsHash = (compilationConfiguration[importScripts]
158-
?: emptyList<FileScriptSource>()).joinToString("") { importedScript ->
159-
importedScript.text.toByteArray().let {
160-
val md = MessageDigest.getInstance("MD5")
161-
md.update(it)
162-
md.digest().joinToString("") { byte -> "%02x".format(byte) }
163-
}
164-
}
165-
166-
// Creating the final hash by combining the main script hash and imports hash
167-
val hash = MessageDigest.getInstance("MD5").apply {
168-
update(mainScriptHash.toByteArray())
169-
update(importsHash.toByteArray())
170-
}.digest().joinToString("") { byte -> "%02x".format(byte) }
171-
171+
// ...
172+
val hash = checksum.digest().joinToString("") { "%02x".format(it) }
172173
val cacheFileName = "${compilationConfiguration[displayName]}.${hash}.cache.jar"
173-
174174
// Purging old cache files with different hashes (not the current one).
175175
cacheDirectory.listFiles()
176176
?.filter {

0 commit comments

Comments
 (0)