Fix scrollback: burst-proof stick-to-bottom, cap-proof layout wait, serialized buffer updates, atomic history saves
This commit is contained in:
@@ -3,6 +3,9 @@ package data
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.nio.file.AtomicMoveNotSupportedException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
/**
|
||||
* Persists each buffer's scrollback to a JSON file under rootDir/history/, so messages
|
||||
@@ -25,14 +28,31 @@ class MessageHistoryRepository(private val rootDir: File) {
|
||||
val arr = JSONArray(file.readText())
|
||||
(0 until arr.length()).map { i -> fromJson(arr.getJSONObject(i)) }
|
||||
} catch (e: Exception) {
|
||||
// Rename the bad file aside rather than silently returning empty - returning
|
||||
// empty here looks to the caller exactly like "no history yet", and the next
|
||||
// debounced save would then happily overwrite - and permanently lose - whatever
|
||||
// was in the corrupt file.
|
||||
file.renameTo(File(file.parentFile, "${file.name}.corrupt"))
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
// @Synchronized because flushAllSaves (on shutdown) calls this directly for every
|
||||
// buffer while a debounced save for the same key can still be in flight on its own
|
||||
// coroutine - without this, the two writes race and whichever's atomic move lands
|
||||
// second wins, which isn't necessarily the one with the more complete message list.
|
||||
@Synchronized
|
||||
fun saveMessages(key: BufferKey, messages: List<IrcMessage>) {
|
||||
val arr = JSONArray()
|
||||
messages.takeLast(500).forEach { arr.put(toJson(it)) }
|
||||
fileFor(key).writeText(arr.toString())
|
||||
val file = fileFor(key)
|
||||
val tmp = File(file.parentFile, "${file.name}.tmp")
|
||||
tmp.writeText(arr.toString())
|
||||
try {
|
||||
Files.move(tmp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE)
|
||||
} catch (e: AtomicMoveNotSupportedException) {
|
||||
Files.move(tmp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toJson(m: IrcMessage): JSONObject = JSONObject().apply {
|
||||
|
||||
Reference in New Issue
Block a user