Synchronize access to OcelotCardItem._entries

Fixes #129.
This commit is contained in:
Fingercomp 2024-01-18 19:53:29 +07:00
parent 05819d4eba
commit 117aa0d2d2
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
3 changed files with 22 additions and 22 deletions

View File

@ -18,7 +18,7 @@ import totoro.ocelot.brain.nbt.{NBT, NBTBase, NBTTagCompound, NBTTagString}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
import scala.collection.{IndexedSeqView, mutable}
import scala.collection.mutable
import scala.jdk.CollectionConverters.BufferHasAsJava
class OcelotCardItem(val ocelotCard: OcelotCard)
@ -31,10 +31,10 @@ class OcelotCardItem(val ocelotCard: OcelotCard)
private var _messageLimit: Int = 1000
// NOTE: access must be synchronized!
// ocelot.log() is a direct method, so it may push events even if the tick lock is not acquired
private val _entries = mutable.ArrayDeque.empty[LogEntry]
def entries: IndexedSeqView[LogEntry] = _entries.view
eventHandlers += {
case BrainEvent(OcelotCard.LogEvent(_, message, OcelotCard.LogDirection.CardToUser)) =>
addEntry(LogEntry.Rx(message))
@ -116,7 +116,7 @@ class OcelotCardItem(val ocelotCard: OcelotCard)
addEntries(entries.toSeq)
}
override def save(nbt: NBTTagCompound): Unit = {
override def save(nbt: NBTTagCompound): Unit = _entries.synchronized {
super.save(nbt)
nbt.setTagList(EntriesTag, _entries.map(saveEntry(_).asInstanceOf[NBTBase]).asJava)
@ -127,32 +127,36 @@ class OcelotCardItem(val ocelotCard: OcelotCard)
def messageLimit: Int = _messageLimit
def messageLimit_=(limit: Int): Unit = {
def messageLimit_=(limit: Int): Unit = _entries.synchronized {
require(limit > 0)
ensureFreeSpace(_entries.length - limit)
_messageLimit = limit
}
def clear(): Unit = {
def entryCount: Int = _entries.synchronized {
_entries.length
}
def clear(): Unit = _entries.synchronized {
val count = _entries.length
_entries.clear()
window.onMessagesRemoved(count)
}
private def addEntry(entry: LogEntry): Unit = {
private def addEntry(entry: LogEntry): Unit = _entries.synchronized {
ensureFreeSpace(1)
_entries += entry
window.onMessagesAdded(1)
window.onMessagesAdded(Some(entry))
}
private def addEntries(entries: Seq[LogEntry]): Unit = {
private def addEntries(entries: Seq[LogEntry]): Unit = _entries.synchronized {
ensureFreeSpace(entries.length)
val prevCount = _entries.length
_entries ++= entries.view.takeRight(messageLimit)
window.onMessagesAdded(_entries.length - prevCount)
window.onMessagesAdded(_entries.view.takeRight(_entries.length - prevCount))
}
private def ensureFreeSpace(n: Int): Unit = {
private def ensureFreeSpace(n: Int): Unit = _entries.synchronized {
val prevCount = _entries.length
_entries.takeRightInPlace(messageLimit - n)
val removedCount = prevCount - _entries.length

View File

@ -163,8 +163,6 @@ abstract class LogWidget extends Widget {
scrollView.scrollToEnd = value
}
protected def entries: Iterable[LogEntry]
protected def textWidth: Int
override def minimumSize: Size2D = Size2D(
@ -175,13 +173,13 @@ abstract class LogWidget extends Widget {
BorderThickness * 2, // outer border (top + bottom)
)
def onEntryAdded(count: Int): Unit = {
for (entry <- entries.view.takeRight(count)) {
def addEntries(entries: Iterable[LogEntry]): Unit = {
for (entry <- entries) {
MessageListWidget.addEntry(entry)
}
}
def onEntryRemoved(count: Int): Unit = {
def removeFirstEntries(count: Int): Unit = {
MessageListWidget.removeFirst(count)
}

View File

@ -12,9 +12,7 @@ class OcelotCardWindow(item: OcelotCardItem) extends PanelWindow {
override protected def title: String = s"Ocelot card ${item.component.node.address}"
private val logWidget: LogWidget = new LogWidget {
override protected def entries: Iterable[LogEntry] = item.entries
override protected def textWidth: Int = 50
override def minimumSize: Size2D = super.minimumSize.copy(height = 300)
override def maximumSize: Size2D = minimumSize
}
@ -32,7 +30,7 @@ class OcelotCardWindow(item: OcelotCardItem) extends PanelWindow {
}
children :+= new Label {
override def text: String = s"Messages: ${item.entries.length} / ${item.messageLimit}"
override def text: String = s"Messages: ${item.entryCount} / ${item.messageLimit}"
}
children :+= new Widget {
@ -87,12 +85,12 @@ class OcelotCardWindow(item: OcelotCardItem) extends PanelWindow {
item.clear()
}
def onMessagesAdded(count: Int): Unit = {
logWidget.onEntryAdded(count)
def onMessagesAdded(entries: Iterable[LogEntry]): Unit = {
logWidget.addEntries(entries)
}
def onMessagesRemoved(count: Int): Unit = {
logWidget.onEntryRemoved(count)
logWidget.removeFirstEntries(count)
}
def pushLine(line: String): Unit = {