mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 02:59:19 +01:00
172 lines
5.0 KiB
Scala
172 lines
5.0 KiB
Scala
package ocelot.desktop.util
|
|
|
|
import ocelot.desktop.entity.traits.OcelotInterface
|
|
import ocelot.desktop.ui.event.{BrainEvent, EventAware}
|
|
import ocelot.desktop.ui.widget.LogWidget.{LogEntry, TextLogEntry}
|
|
import ocelot.desktop.ui.widget.window.Windowed
|
|
import ocelot.desktop.util.OcelotInterfaceLogStorage._
|
|
import ocelot.desktop.windows.OcelotInterfaceWindow
|
|
import totoro.ocelot.brain.nbt.ExtendedNBT.extendNBTTagList
|
|
import totoro.ocelot.brain.nbt.{NBT, NBTBase, NBTTagCompound, NBTTagString}
|
|
|
|
import scala.collection.mutable
|
|
import scala.jdk.CollectionConverters.BufferHasAsJava
|
|
|
|
trait OcelotInterfaceLogStorage extends EventAware with Persistable with Windowed[OcelotInterfaceWindow] with Logging {
|
|
|
|
def ocelotInterface: OcelotInterface
|
|
|
|
def name: String
|
|
|
|
override def createWindow(): OcelotInterfaceWindow = new OcelotInterfaceWindow(this)
|
|
|
|
private var _messageLimit: Int = 1000
|
|
|
|
private val _entries = mutable.ArrayDeque.empty[LogEntry]
|
|
|
|
eventHandlers += {
|
|
case BrainEvent(OcelotInterface.LogEvent.Clear(_)) =>
|
|
clear()
|
|
|
|
case BrainEvent(OcelotInterface.LogEvent.CardToUser(_, message)) =>
|
|
addEntry(LogEntry.Rx(message))
|
|
|
|
case BrainEvent(OcelotInterface.LogEvent.UserToCard(_, message)) =>
|
|
addEntry(LogEntry.Tx(message))
|
|
}
|
|
|
|
private def loadEntry(nbt: NBTTagCompound): Either[String, LogEntry] = {
|
|
nbt.getString(EntryKindTag) match {
|
|
case EntryKindRx => Right(LogEntry.Rx(nbt.getString(EntryMessageTag)))
|
|
case EntryKindTx => Right(LogEntry.Tx(nbt.getString(EntryMessageTag)))
|
|
|
|
case "" => Left("entry kind not set")
|
|
case k => Left(s"unknown entry kind: $k")
|
|
}
|
|
}
|
|
|
|
private def saveEntry(entry: LogEntry): NBTTagCompound = {
|
|
val result = new NBTTagCompound()
|
|
|
|
entry match {
|
|
case LogEntry.Rx(message) =>
|
|
result.setString(EntryKindTag, EntryKindRx)
|
|
result.setString(EntryMessageTag, message)
|
|
|
|
case LogEntry.Tx(message) =>
|
|
result.setString(EntryKindTag, EntryKindTx)
|
|
result.setString(EntryMessageTag, message)
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
override def load(nbt: NBTTagCompound): Unit = {
|
|
super.load(nbt)
|
|
|
|
clear()
|
|
|
|
if (nbt.hasKey(MessageLimitTag)) {
|
|
messageLimit = nbt.getInteger(MessageLimitTag)
|
|
}
|
|
|
|
val entries = if (nbt.hasKey(EntriesTag)) {
|
|
nbt.getTagList(EntriesTag, NBT.TAG_COMPOUND).iterator[NBTTagCompound].zipWithIndex.flatMap {
|
|
case (entryNbt, idx) =>
|
|
loadEntry(entryNbt) match {
|
|
case Left(err) =>
|
|
logger.warn(
|
|
s"Could not restore log entry (idx $idx) of ocelot interface ${ocelotInterface.node.address}:" +
|
|
s" $err"
|
|
)
|
|
|
|
None
|
|
|
|
case Right(entry) => Some(entry)
|
|
}
|
|
}
|
|
} else {
|
|
// old save format: plain messages
|
|
nbt
|
|
.getTagList(MessagesTag, NBT.TAG_STRING)
|
|
.iterator[NBTTagString]
|
|
.map(entryNbt => LogEntry.Rx(entryNbt.getString))
|
|
}
|
|
|
|
addEntries(entries.toSeq)
|
|
}
|
|
|
|
override def save(nbt: NBTTagCompound): Unit = {
|
|
super.save(nbt)
|
|
|
|
nbt.setTagList(EntriesTag, _entries.map(saveEntry(_).asInstanceOf[NBTBase]).asJava)
|
|
nbt.setInteger(MessageLimitTag, _messageLimit)
|
|
}
|
|
|
|
def messageLimit: Int = _messageLimit
|
|
|
|
def messageLimit_=(limit: Int): Unit = {
|
|
require(limit > 0)
|
|
ensureFreeSpace(_entries.length - limit)
|
|
_messageLimit = limit
|
|
}
|
|
|
|
def entryCount: Int = {
|
|
_entries.length
|
|
}
|
|
|
|
def clear(): Unit = {
|
|
val count = _entries.length
|
|
_entries.clear()
|
|
window.onMessagesRemoved(count)
|
|
}
|
|
|
|
def getEntry(index: Int): LogEntry = _entries(index)
|
|
|
|
def findFirstTextEntry(exclude: String, start: Int): Int = {
|
|
_entries.indexWhere(it => it.isInstanceOf[TextLogEntry] && it.asInstanceOf[TextLogEntry].message != exclude, start)
|
|
}
|
|
|
|
def findLastTextEntry(exclude: String, end: Int): Int = {
|
|
_entries.lastIndexWhere(it => it.isInstanceOf[TextLogEntry] && it.asInstanceOf[TextLogEntry].message != exclude, end)
|
|
}
|
|
|
|
private def addEntry(entry: LogEntry): Unit = {
|
|
ensureFreeSpace(1)
|
|
_entries += entry
|
|
onMessagesAdded(Some(entry))
|
|
}
|
|
|
|
private def addEntries(entries: Seq[LogEntry]): Unit = {
|
|
ensureFreeSpace(entries.length)
|
|
val prevCount = _entries.length
|
|
_entries ++= entries.view.takeRight(messageLimit)
|
|
onMessagesAdded(_entries.view.takeRight(_entries.length - prevCount))
|
|
}
|
|
|
|
private def ensureFreeSpace(n: Int): Unit = {
|
|
val prevCount = _entries.length
|
|
_entries.takeRightInPlace(messageLimit - n)
|
|
val removedCount = prevCount - _entries.length
|
|
|
|
if (removedCount > 0) {
|
|
window.onMessagesRemoved(removedCount)
|
|
}
|
|
}
|
|
|
|
protected def onMessagesAdded(entries: => Iterable[LogEntry]): Unit = {
|
|
window.onMessagesAdded(entries)
|
|
}
|
|
}
|
|
|
|
object OcelotInterfaceLogStorage {
|
|
private val MessagesTag = "messages"
|
|
private val EntriesTag = "entries"
|
|
private val MessageLimitTag = "limit"
|
|
|
|
private val EntryKindTag = "kind"
|
|
private val EntryKindRx = "rx"
|
|
private val EntryKindTx = "tx"
|
|
private val EntryMessageTag = "msg"
|
|
}
|