Skip to content
Snippets Groups Projects
Verified Commit c65606fb authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Implement all syncables

parent 06382958
No related branches found
No related tags found
No related merge requests found
Showing
with 1268 additions and 12 deletions
......@@ -8,4 +8,6 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.protocol.syncables.state
package de.justjanne.libquassel.client.exceptions
class IrcListException(message: String) : Exception(message)
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.client.syncables
import de.justjanne.bitflags.of
import de.justjanne.libquassel.protocol.models.flags.MessageFlag
import de.justjanne.libquassel.protocol.models.flags.MessageFlags
import de.justjanne.libquassel.protocol.models.flags.MessageType
import de.justjanne.libquassel.protocol.models.flags.MessageTypes
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.MsgId
import de.justjanne.libquassel.protocol.syncables.BacklogManager
import de.justjanne.libquassel.protocol.syncables.Session
import de.justjanne.libquassel.protocol.variant.QVariantList
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class ClientBacklogManager(
session: Session
) : BacklogManager(session) {
private val bufferListeners =
mutableMapOf<BacklogData.Buffer, Continuation<BacklogData.Buffer>>()
private val bufferFilteredListeners =
mutableMapOf<BacklogData.BufferFiltered, Continuation<BacklogData.BufferFiltered>>()
private val allListeners =
mutableMapOf<BacklogData.All, Continuation<BacklogData.All>>()
private val allFilteredListeners =
mutableMapOf<BacklogData.AllFiltered, Continuation<BacklogData.AllFiltered>>()
suspend fun backlog(
bufferId: BufferId,
first: MsgId = MsgId(-1),
last: MsgId = MsgId(-1),
limit: Int = -1,
additional: Int = 0
) = suspendCoroutine<BacklogData.Buffer> {
val data = BacklogData.Buffer(bufferId, first, last, limit, additional)
bufferListeners[data] = it
}
suspend fun backlogFiltered(
bufferId: BufferId,
first: MsgId = MsgId(-1),
last: MsgId = MsgId(-1),
limit: Int = -1,
additional: Int = 0,
type: MessageTypes = MessageType.all,
flags: MessageFlags = MessageFlag.all
) = suspendCoroutine<BacklogData.BufferFiltered> {
val data = BacklogData.BufferFiltered(bufferId, first, last, limit, additional, type, flags)
bufferFilteredListeners[data] = it
}
suspend fun backlogAll(
first: MsgId = MsgId(-1),
last: MsgId = MsgId(-1),
limit: Int = -1,
additional: Int = 0
) = suspendCoroutine<BacklogData.All> {
val data = BacklogData.All(first, last, limit, additional)
allListeners[data] = it
}
suspend fun backlogAllFiltered(
first: MsgId = MsgId(-1),
last: MsgId = MsgId(-1),
limit: Int = -1,
additional: Int = 0,
type: MessageTypes = MessageType.all,
flags: MessageFlags = MessageFlag.all
) = suspendCoroutine<BacklogData.AllFiltered> {
val data = BacklogData.AllFiltered(first, last, limit, additional, type, flags)
allFilteredListeners[data] = it
}
override fun receiveBacklog(
bufferId: BufferId,
first: MsgId,
last: MsgId,
limit: Int,
additional: Int,
messages: QVariantList
) {
val data = BacklogData.Buffer(
bufferId,
first,
last,
limit,
additional
)
bufferListeners[data]?.resume(data.copy(messages = messages))
super.receiveBacklog(bufferId, first, last, limit, additional, messages)
}
override fun receiveBacklogFiltered(
bufferId: BufferId,
first: MsgId,
last: MsgId,
limit: Int,
additional: Int,
type: Int,
flags: Int,
messages: QVariantList
) {
val data = BacklogData.BufferFiltered(
bufferId,
first,
last,
limit,
additional,
MessageType.of(type.toUInt()),
MessageFlag.of(flags.toUInt())
)
bufferFilteredListeners[data]?.resume(data.copy(messages = messages))
super.receiveBacklogFiltered(bufferId, first, last, limit, additional, type, flags, messages)
}
override fun receiveBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList) {
val data = BacklogData.All(
first,
last,
limit,
additional
)
allListeners[data]?.resume(data.copy(messages = messages))
super.receiveBacklogAll(first, last, limit, additional, messages)
}
override fun receiveBacklogAllFiltered(
first: MsgId,
last: MsgId,
limit: Int,
additional: Int,
type: Int,
flags: Int,
messages: QVariantList
) {
val data = BacklogData.AllFiltered(
first,
last,
limit,
additional,
MessageType.of(type.toUInt()),
MessageFlag.of(flags.toUInt()),
)
allFilteredListeners[data]?.resume(data.copy(messages = messages))
super.receiveBacklogAllFiltered(first, last, limit, additional, type, flags, messages)
}
sealed class BacklogData {
data class Buffer(
val bufferId: BufferId,
val first: MsgId = MsgId(-1),
val last: MsgId = MsgId(-1),
val limit: Int = -1,
val additional: Int = 0,
val messages: QVariantList = emptyList()
) : BacklogData()
data class BufferFiltered(
val bufferId: BufferId,
val first: MsgId = MsgId(-1),
val last: MsgId = MsgId(-1),
val limit: Int = -1,
val additional: Int = 0,
val type: MessageTypes = MessageType.all,
val flags: MessageFlags = MessageFlag.all,
val messages: QVariantList = emptyList()
) : BacklogData()
data class All(
val first: MsgId = MsgId(-1),
val last: MsgId = MsgId(-1),
val limit: Int = -1,
val additional: Int = 0,
val messages: QVariantList = emptyList()
) : BacklogData()
data class AllFiltered(
val first: MsgId = MsgId(-1),
val last: MsgId = MsgId(-1),
val limit: Int = -1,
val additional: Int = 0,
val type: MessageTypes = MessageType.all,
val flags: MessageFlags = MessageFlag.all,
val messages: QVariantList = emptyList()
) : BacklogData()
}
}
/*
* libquassel
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
package de.justjanne.libquassel.client.syncables
import de.justjanne.libquassel.client.exceptions.IrcListException
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.ids.NetworkId
import de.justjanne.libquassel.protocol.syncables.IrcListHelper
import de.justjanne.libquassel.protocol.syncables.Session
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.into
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class ClientIrcListHelper(
session: Session
) : IrcListHelper(session) {
private val waitingContinuations = mutableMapOf<NetworkId, Continuation<List<ChannelDescription>>>()
private val readyContinuations = mutableMapOf<NetworkId, Continuation<List<ChannelDescription>>>()
suspend fun channelList(
networkId: NetworkId,
channelFilters: List<String>
) = suspendCoroutine<List<ChannelDescription>> {
waitingContinuations[networkId] = it
requestChannelList(networkId, channelFilters)
}
override fun reportFinishedList(netId: NetworkId) {
val continuation = waitingContinuations.remove(netId)
if (continuation != null) {
readyContinuations[netId] = continuation
requestChannelList(netId, emptyList())
}
super.reportFinishedList(netId)
}
override fun reportError(error: String?) {
for (continuation in waitingContinuations.values + readyContinuations.values) {
continuation.resumeWith(Result.failure(IrcListException(error ?: "Unknown Error")))
}
super.reportError(error)
}
override fun receiveChannelList(netId: NetworkId, channelFilters: QStringList, channels: QVariantList) {
readyContinuations[netId]?.resume(
channels.mapNotNull {
val list = it.into<QVariantList>().orEmpty()
if (list.size == 3) {
ChannelDescription(
netId,
list[0].into(""),
list[1].into(0u),
list[2].into(""),
)
} else {
null
}
}
)
super.receiveChannelList(netId, channelFilters, channels)
}
data class ChannelDescription(
val netId: NetworkId,
val channelName: String,
val userCount: UInt,
val topic: String
)
}
......@@ -23,7 +23,7 @@ import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
class AliasManager constructor(
open class AliasManager(
session: Session
) : SyncableObject(session, "AliasManager"), AliasManagerStub {
override fun toVariantMap(): QVariantMap = mapOf(
......
......@@ -9,3 +9,15 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.syncables.stubs.BacklogManagerStub
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.QVariant_
open class BacklogManager(
session: Session
) : SyncableObject(session, "BacklogManager"), BacklogManagerStub {
override fun fromVariantMap(properties: QVariantMap) = Unit
override fun toVariantMap() = mapOf<String, QVariant_>()
}
......@@ -9,3 +9,210 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.bitflags.none
import de.justjanne.bitflags.of
import de.justjanne.bitflags.toBits
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.flags.MessageType
import de.justjanne.libquassel.protocol.models.flags.MessageTypes
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.MsgId
import de.justjanne.libquassel.protocol.models.ids.isValid
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.syncables.state.BufferSyncerState
import de.justjanne.libquassel.protocol.syncables.stubs.BufferSyncerStub
import de.justjanne.libquassel.protocol.util.pairs
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
open class BufferSyncer(
session: Session
) : SyncableObject(session, "BufferSyncer"), BufferSyncerStub {
override fun toVariantMap() = mapOf(
"Activities" to qVariant(
state().activities.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value.toBits(), QtType.UInt)
)
},
QtType.QVariantList
),
"HighlightCounts" to qVariant(
state().highlightCounts.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value, QtType.Int)
)
},
QtType.QVariantList
),
"LastSeenMsg" to qVariant(
state().lastSeenMsg.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value, QuasselType.MsgId)
)
},
QtType.QVariantList
),
"MarkerLines" to qVariant(
state().markerLines.flatMap { (key, value) ->
listOf(
qVariant(key, QuasselType.BufferId),
qVariant(value, QuasselType.MsgId)
)
},
QtType.QVariantList
),
)
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
activities = properties["Activities"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
MessageType.of(b.into<UInt>() ?: return@pairs null)
)
}?.filterNotNull()?.toMap().orEmpty(),
highlightCounts = properties["HighlightCounts"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
b.into<Int>() ?: return@pairs null
)
}?.filterNotNull()?.toMap().orEmpty(),
lastSeenMsg = properties["LastSeenMsg"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
b.into<MsgId>() ?: return@pairs null
)
}?.filterNotNull()?.toMap().orEmpty(),
markerLines = properties["MarkerLines"].into<QVariantList>()?.pairs { a, b ->
Pair(
a.into<BufferId>() ?: return@pairs null,
b.into<MsgId>() ?: return@pairs null
)
}?.filterNotNull()?.toMap().orEmpty()
)
}
}
fun lastSeenMsg(buffer: BufferId): MsgId = state().lastSeenMsg[buffer] ?: MsgId(0)
fun markerLine(buffer: BufferId): MsgId = state().markerLines[buffer] ?: MsgId(0)
fun activity(buffer: BufferId): MessageTypes =
state().activities[buffer] ?: MessageType.none()
fun highlightCount(buffer: BufferId): Int = state().highlightCounts[buffer] ?: 0
fun bufferInfo(bufferId: BufferId) = state().bufferInfos[bufferId]
fun bufferInfos(): Collection<BufferInfo> = state().bufferInfos.values.toList()
override fun mergeBuffersPermanently(buffer: BufferId, buffer2: BufferId) {
removeBuffer(buffer2)
super.mergeBuffersPermanently(buffer, buffer2)
}
override fun removeBuffer(buffer: BufferId) {
state.update {
copy(
activities = activities - buffer,
lastSeenMsg = lastSeenMsg - buffer,
markerLines = markerLines - buffer,
highlightCounts = highlightCounts - buffer,
bufferInfos = bufferInfos - buffer
)
}
super.removeBuffer(buffer)
}
override fun setLastSeenMsg(buffer: BufferId, msgId: MsgId) {
if (!msgId.isValid() || lastSeenMsg(buffer) >= msgId) {
return
}
state.update {
copy(lastSeenMsg = lastSeenMsg + Pair(buffer, msgId))
}
super.setLastSeenMsg(buffer, msgId)
}
override fun setMarkerLine(buffer: BufferId, msgId: MsgId) {
if (!msgId.isValid() || markerLine(buffer) >= msgId) {
return
}
state.update {
copy(markerLines = markerLines + Pair(buffer, msgId))
}
super.setMarkerLine(buffer, msgId)
}
override fun setBufferActivity(buffer: BufferId, types: Int) {
state.update {
copy(activities = activities + Pair(buffer, MessageType.of(types.toUInt())))
}
super.setBufferActivity(buffer, types)
}
fun setBufferActivity(buffer: BufferId, types: MessageTypes) {
val oldTypes = activity(buffer)
state.update {
copy(activities = activities + Pair(buffer, types))
}
if ((types - oldTypes).isNotEmpty()) {
val bufferInfo = bufferInfo(buffer)
if (bufferInfo != null) {
session.bufferViewManager().handleBuffer(bufferInfo, true)
}
}
super.setBufferActivity(buffer, types.toBits().toInt())
}
override fun setHighlightCount(buffer: BufferId, count: Int) {
state.update {
copy(highlightCounts = highlightCounts + Pair(buffer, count))
}
super.setHighlightCount(buffer, count)
}
fun bufferInfoUpdated(info: BufferInfo) {
val oldInfo = bufferInfo(info.bufferId)
if (info != oldInfo) {
state.update {
copy(bufferInfos = bufferInfos + Pair(info.bufferId, info))
}
if (oldInfo != null) {
session.bufferViewManager().handleBuffer(info)
}
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun state() = flow().value
@Suppress("NOTHING_TO_INLINE")
inline fun flow() = state
@PublishedApi
internal val state = MutableStateFlow(
BufferSyncerState()
)
}
......@@ -9,3 +9,269 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.bitflags.of
import de.justjanne.bitflags.toBits
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.flags.BufferActivity
import de.justjanne.libquassel.protocol.models.flags.BufferType
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.NetworkId
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
import de.justjanne.libquassel.protocol.syncables.stubs.BufferViewConfigStub
import de.justjanne.libquassel.protocol.util.insert
import de.justjanne.libquassel.protocol.util.move
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
open class BufferViewConfig(
bufferViewId: Int,
session: Session
) : SyncableObject(session, "BufferViewConfig"), BufferViewConfigStub {
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
buffers = properties["BufferList"].into<QVariantList>()
?.mapNotNull { it.into<BufferId>() }
.orEmpty(),
removedBuffers = properties["RemovedBuffers"].into<QVariantList>()
?.mapNotNull { it.into<BufferId>() }
?.toSet()
.orEmpty(),
temporarilyRemovedBuffers = properties["TemporarilyRemovedBuffers"].into<QVariantList>()
?.mapNotNull { it.into<BufferId>() }
?.toSet()
.orEmpty(),
bufferViewName = properties["bufferViewName"].into(bufferViewName()),
networkId = properties["networkId"].into(networkId()),
addNewBuffersAutomatically = properties["addNewBuffersAutomatically"].into(addNewBuffersAutomatically()),
sortAlphabetically = properties["sortAlphabetically"].into(sortAlphabetically()),
hideInactiveBuffers = properties["hideInactiveBuffers"].into(hideInactiveBuffers()),
hideInactiveNetworks = properties["hideInactiveNetworks"].into(hideInactiveNetworks()),
disableDecoration = properties["disableDecoration"].into(disableDecoration()),
allowedBufferTypes = properties["allowedBufferTypes"].into(allowedBufferTypes()),
minimumActivity = properties["minimumActivity"].into(minimumActivity()),
showSearch = properties["showSearch"].into(showSearch()),
)
}
}
override fun toVariantMap() = mapOf(
"BufferList" to qVariant(
buffers().map {
qVariant(it, QuasselType.BufferId)
},
QtType.QVariantList
),
"RemovedBuffers" to qVariant(
removedBuffers().map {
qVariant(it, QuasselType.BufferId)
},
QtType.QVariantList
),
"TemporarilyRemovedBuffers" to qVariant(
temporarilyRemovedBuffers().map {
qVariant(it, QuasselType.BufferId)
},
QtType.QVariantList
),
"bufferViewName" to qVariant(bufferViewName(), QtType.QString),
"networkId" to qVariant(networkId(), QuasselType.NetworkId),
"addNewBuffersAutomatically" to qVariant(addNewBuffersAutomatically(), QtType.Bool),
"sortAlphabetically" to qVariant(sortAlphabetically(), QtType.Bool),
"hideInactiveBuffers" to qVariant(hideInactiveBuffers(), QtType.Bool),
"hideInactiveNetworks" to qVariant(hideInactiveNetworks(), QtType.Bool),
"disableDecoration" to qVariant(disableDecoration(), QtType.Bool),
"allowedBufferTypes" to qVariant(allowedBufferTypes().toBits().toInt(), QtType.Int),
"minimumActivity" to qVariant(minimumActivity().toBits().toInt(), QtType.Int),
"showSearch" to qVariant(showSearch(), QtType.Bool)
)
fun bufferViewId() = state().bufferViewId
fun bufferViewName() = state().bufferViewName
fun networkId() = state().networkId
fun addNewBuffersAutomatically() = state().addNewBuffersAutomatically
fun sortAlphabetically() = state().sortAlphabetically
fun hideInactiveBuffers() = state().hideInactiveBuffers
fun hideInactiveNetworks() = state().hideInactiveNetworks
fun disableDecoration() = state().disableDecoration
fun allowedBufferTypes() = state().allowedBufferTypes
fun minimumActivity() = state().minimumActivity
fun showSearch() = state().showSearch
fun buffers() = state().buffers
fun removedBuffers() = state().removedBuffers
fun temporarilyRemovedBuffers() = state().temporarilyRemovedBuffers
override fun addBuffer(buffer: BufferId, pos: Int) {
state.update {
copy(
buffers = buffers.insert(buffer, pos),
removedBuffers = removedBuffers - buffer,
temporarilyRemovedBuffers = temporarilyRemovedBuffers - buffer
)
}
super.addBuffer(buffer, pos)
}
override fun removeBuffer(buffer: BufferId) {
state.update {
copy(
buffers = buffers - buffer,
removedBuffers = removedBuffers - buffer,
temporarilyRemovedBuffers = temporarilyRemovedBuffers + buffer
)
}
super.removeBuffer(buffer)
}
override fun removeBufferPermanently(buffer: BufferId) {
state.update {
copy(
buffers = buffers - buffer,
removedBuffers = removedBuffers + buffer,
temporarilyRemovedBuffers = temporarilyRemovedBuffers - buffer
)
}
super.removeBufferPermanently(buffer)
}
override fun moveBuffer(buffer: BufferId, pos: Int) {
if (!buffers().contains(buffer)) {
return
}
state.update {
copy(
buffers = buffers.move(buffer, pos),
removedBuffers = removedBuffers - buffer,
temporarilyRemovedBuffers = temporarilyRemovedBuffers - buffer
)
}
super.moveBuffer(buffer, pos)
}
override fun setBufferViewName(value: String) {
state.update {
copy(bufferViewName = value)
}
super.setBufferViewName(value)
}
override fun setAddNewBuffersAutomatically(value: Boolean) {
state.update {
copy(addNewBuffersAutomatically = value)
}
super.setAddNewBuffersAutomatically(value)
}
override fun setAllowedBufferTypes(value: Int) {
state.update {
copy(allowedBufferTypes = BufferType.of(value.toUShort()))
}
super.setAllowedBufferTypes(value)
}
override fun setDisableDecoration(value: Boolean) {
state.update {
copy(disableDecoration = value)
}
super.setDisableDecoration(value)
}
override fun setHideInactiveBuffers(value: Boolean) {
state.update {
copy(hideInactiveBuffers = value)
}
super.setHideInactiveBuffers(value)
}
override fun setHideInactiveNetworks(value: Boolean) {
state.update {
copy(hideInactiveNetworks = value)
}
super.setHideInactiveNetworks(value)
}
override fun setMinimumActivity(value: Int) {
state.update {
copy(minimumActivity = BufferActivity.of(value.toUInt()))
}
super.setMinimumActivity(value)
}
override fun setNetworkId(value: NetworkId) {
state.update {
copy(networkId = value)
}
super.setNetworkId(value)
}
override fun setShowSearch(value: Boolean) {
state.update {
copy(showSearch = value)
}
super.setShowSearch(value)
}
override fun setSortAlphabetically(value: Boolean) {
state.update {
copy(sortAlphabetically = value)
}
super.setSortAlphabetically(value)
}
fun insertBufferSorted(info: BufferInfo) {
requestAddBuffer(
info.bufferId,
buffers()
.asSequence()
.map(session.bufferSyncer()::bufferInfo)
.withIndex()
.mapNotNull { (index, value) -> IndexedValue(index, value ?: return@mapNotNull null) }
.filter { (_, value) -> value.networkId == info.networkId }
.find { (_, value) ->
String.CASE_INSENSITIVE_ORDER.compare(value.bufferName, info.bufferName) > 0
}?.index ?: buffers().size
)
}
fun handleBuffer(info: BufferInfo, unhide: Boolean = false) {
if (addNewBuffersAutomatically() &&
!buffers().contains(info.bufferId) &&
!temporarilyRemovedBuffers().contains(info.bufferId) &&
!removedBuffers().contains(info.bufferId) &&
!info.type.contains(BufferType.Status)
) {
insertBufferSorted(info)
} else if (unhide &&
!buffers().contains(info.bufferId) &&
temporarilyRemovedBuffers().contains(info.bufferId)
) {
insertBufferSorted(info)
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun state() = flow().value
@Suppress("NOTHING_TO_INLINE")
inline fun flow() = state
@PublishedApi
internal val state = MutableStateFlow(
BufferViewConfigState(
bufferViewId = bufferViewId
)
)
}
......@@ -9,3 +9,69 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.syncables.state.BufferViewManagerState
import de.justjanne.libquassel.protocol.syncables.stubs.BufferViewManagerStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantList
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.QVariant_
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
open class BufferViewManager(
session: Session
) : SyncableObject(session, "BufferViewManager"), BufferViewManagerStub {
override fun fromVariantMap(properties: QVariantMap) {
properties["BufferViewIds"].into<QVariantList>()
?.mapNotNull<QVariant_, Int>(QVariant_::into)
?.forEach(this::addBufferViewConfig)
}
override fun toVariantMap() = mapOf(
"BufferViewIds" to qVariant(
state().bufferViewConfigs.map {
qVariant(it.key, QtType.Int)
},
QtType.QVariantList
)
)
fun contains(bufferViewId: Int) = state().contains(bufferViewId)
fun bufferViewConfig(bufferViewId: Int) = state().bufferViewConfig(bufferViewId)
fun bufferViewConfigs() = state().bufferViewConfigs()
override fun addBufferViewConfig(bufferViewConfigId: Int) {
if (contains(bufferViewConfigId)) {
return
}
val config = BufferViewConfig(bufferViewConfigId, session)
session.synchronize(config)
state.update {
copy(bufferViewConfigs = bufferViewConfigs + Pair(bufferViewConfigId, config))
}
super.addBufferViewConfig(bufferViewConfigId)
}
fun handleBuffer(info: BufferInfo, unhide: Boolean = false) {
for (bufferViewConfig in bufferViewConfigs()) {
bufferViewConfig.handleBuffer(info, unhide)
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun state() = flow().value
@Suppress("NOTHING_TO_INLINE")
inline fun flow() = state
@PublishedApi
internal val state = MutableStateFlow(
BufferViewManagerState()
)
}
......@@ -29,7 +29,7 @@ import java.security.PrivateKey
import java.security.cert.Certificate
import java.security.cert.CertificateFactory
class CertManager(
open class CertManager(
identityId: IdentityId,
session: Session
) : SyncableObject(session, "CertManager"), CertManagerStub {
......
......@@ -23,7 +23,7 @@ import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
import org.threeten.bp.Instant
class CoreInfo constructor(
open class CoreInfo(
session: Session
) : SyncableObject(session, "CoreInfo"), CoreInfoStub {
override fun fromVariantMap(properties: QVariantMap) {
......
......@@ -23,7 +23,7 @@ import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
import java.net.InetAddress
class DccConfig constructor(
open class DccConfig(
session: Session
) : SyncableObject(session, "DccConfig"), DccConfigStub {
override fun init() {
......
......@@ -23,7 +23,7 @@ import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
class HighlightRuleManager(
open class HighlightRuleManager(
session: Session
) : SyncableObject(session, "HighlightRuleManager"), HighlightRuleManagerStub {
override fun fromVariantMap(properties: QVariantMap) {
......
......@@ -9,3 +9,235 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.models.QStringList
import de.justjanne.libquassel.protocol.models.ids.IdentityId
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.models.types.QuasselType
import de.justjanne.libquassel.protocol.syncables.state.IdentityState
import de.justjanne.libquassel.protocol.syncables.stubs.IdentityStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
open class Identity(
session: Session
) : SyncableObject(session, "Identity"), IdentityStub {
override fun init() {
renameObject(state().identifier())
}
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
identityId = properties["identityId"].into(identityId),
identityName = properties["identityName"].into(identityName),
realName = properties["realName"].into(realName),
nicks = properties["nicks"].into(nicks),
awayNick = properties["awayNick"].into(awayNick),
awayNickEnabled = properties["awayNickEnabled"].into(awayNickEnabled),
awayReason = properties["awayReason"].into(awayReason),
awayReasonEnabled = properties["awayReasonEnabled"].into(awayReasonEnabled),
autoAwayEnabled = properties["autoAwayEnabled"].into(autoAwayEnabled),
autoAwayTime = properties["autoAwayTime"].into(autoAwayTime),
autoAwayReason = properties["autoAwayReason"].into(autoAwayReason),
autoAwayReasonEnabled = properties["autoAwayReasonEnabled"].into(autoAwayReasonEnabled),
detachAwayEnabled = properties["detachAwayEnabled"].into(detachAwayEnabled),
detachAwayReason = properties["detachAwayReason"].into(detachAwayReason),
detachAwayReasonEnabled = properties["detachAwayReasonEnabled"].into(detachAwayReasonEnabled),
ident = properties["ident"].into(ident),
kickReason = properties["kickReason"].into(kickReason),
partReason = properties["partReason"].into(partReason),
quitReason = properties["quitReason"].into(quitReason),
)
}
}
override fun toVariantMap() = mapOf(
"identityId" to qVariant(id(), QuasselType.IdentityId),
"identityName" to qVariant(identityName(), QtType.QString),
"realName" to qVariant(realName(), QtType.QString),
"nicks" to qVariant(nicks(), QtType.QStringList),
"awayNick" to qVariant(awayNick(), QtType.QString),
"awayNickEnabled" to qVariant(awayNickEnabled(), QtType.Bool),
"awayReason" to qVariant(awayReason(), QtType.QString),
"awayReasonEnabled" to qVariant(awayReasonEnabled(), QtType.Bool),
"autoAwayEnabled" to qVariant(autoAwayEnabled(), QtType.Bool),
"autoAwayTime" to qVariant(autoAwayTime(), QtType.Int),
"autoAwayReason" to qVariant(autoAwayReason(), QtType.QString),
"autoAwayReasonEnabled" to qVariant(autoAwayReasonEnabled(), QtType.Bool),
"detachAwayEnabled" to qVariant(detachAwayEnabled(), QtType.Bool),
"detachAwayReason" to qVariant(detachAwayReason(), QtType.QString),
"detachAwayReasonEnabled" to qVariant(detachAwayReasonEnabled(), QtType.Bool),
"ident" to qVariant(ident(), QtType.QString),
"kickReason" to qVariant(kickReason(), QtType.QString),
"partReason" to qVariant(partReason(), QtType.QString),
"quitReason" to qVariant(quitReason(), QtType.QString)
)
fun id() = state().identityId
fun identityName() = state().identityName
fun realName() = state().realName
fun nicks() = state().nicks
fun awayNick() = state().awayNick
fun awayNickEnabled() = state().awayNickEnabled
fun awayReason() = state().awayReason
fun awayReasonEnabled() = state().awayReasonEnabled
fun autoAwayEnabled() = state().autoAwayEnabled
fun autoAwayTime() = state().autoAwayTime
fun autoAwayReason() = state().autoAwayReason
fun autoAwayReasonEnabled() = state().autoAwayReasonEnabled
fun detachAwayEnabled() = state().detachAwayEnabled
fun detachAwayReason() = state().detachAwayReason
fun detachAwayReasonEnabled() = state().detachAwayReasonEnabled
fun ident() = state().ident
fun kickReason() = state().kickReason
fun partReason() = state().partReason
fun quitReason() = state().quitReason
override fun setAutoAwayEnabled(enabled: Boolean) {
state.update {
copy(autoAwayEnabled = enabled)
}
super.setAutoAwayEnabled(enabled)
}
override fun setAutoAwayReason(reason: String?) {
state.update {
copy(autoAwayReason = reason ?: "")
}
super.setAutoAwayReason(reason)
}
override fun setAutoAwayReasonEnabled(enabled: Boolean) {
state.update {
copy(autoAwayReasonEnabled = enabled)
}
super.setAutoAwayReasonEnabled(enabled)
}
override fun setAutoAwayTime(time: Int) {
state.update {
copy(autoAwayTime = time)
}
super.setAutoAwayTime(time)
}
override fun setAwayNick(awayNick: String?) {
state.update {
copy(awayNick = awayNick ?: "")
}
super.setAwayNick(awayNick)
}
override fun setAwayNickEnabled(enabled: Boolean) {
state.update {
copy(awayNickEnabled = enabled)
}
super.setAwayNickEnabled(enabled)
}
override fun setAwayReason(awayReason: String?) {
state.update {
copy(awayReason = awayReason ?: "")
}
super.setAwayReason(awayReason)
}
override fun setAwayReasonEnabled(enabled: Boolean) {
state.update {
copy(awayReasonEnabled = enabled)
}
super.setAwayReasonEnabled(enabled)
}
override fun setDetachAwayEnabled(enabled: Boolean) {
state.update {
copy(detachAwayEnabled = enabled)
}
super.setDetachAwayEnabled(enabled)
}
override fun setDetachAwayReason(reason: String?) {
state.update {
copy(detachAwayReason = reason ?: "")
}
super.setDetachAwayReason(reason)
}
override fun setDetachAwayReasonEnabled(enabled: Boolean) {
state.update {
copy(detachAwayReasonEnabled = enabled)
}
super.setDetachAwayReasonEnabled(enabled)
}
override fun setId(id: IdentityId) {
state.update {
copy(identityId = id)
}
super.setId(id)
}
override fun setIdent(ident: String?) {
state.update {
copy(ident = ident ?: "")
}
super.setIdent(ident)
}
override fun setIdentityName(name: String?) {
state.update {
copy(identityName = name ?: "")
}
super.setIdentityName(name)
}
override fun setKickReason(reason: String?) {
state.update {
copy(kickReason = reason ?: "")
}
super.setKickReason(reason)
}
override fun setNicks(nicks: QStringList) {
state.update {
copy(nicks = nicks.map { it ?: "" })
}
super.setNicks(nicks)
}
override fun setPartReason(reason: String?) {
state.update {
copy(partReason = reason ?: "")
}
super.setPartReason(reason)
}
override fun setQuitReason(reason: String?) {
state.update {
copy(quitReason = reason ?: "")
}
super.setQuitReason(reason)
}
override fun setRealName(realName: String?) {
state.update {
copy(realName = realName ?: "")
}
super.setRealName(realName)
}
@Suppress("NOTHING_TO_INLINE")
inline fun state() = flow().value
@Suppress("NOTHING_TO_INLINE")
inline fun flow() = state
@PublishedApi
internal val state = MutableStateFlow(
IdentityState()
)
}
......@@ -24,7 +24,7 @@ import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
class IrcChannel(
open class IrcChannel(
name: String,
network: NetworkId,
session: Session
......
......@@ -9,3 +9,14 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.syncables.stubs.IrcListHelperStub
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.QVariant_
open class IrcListHelper(
session: Session
) : SyncableObject(session, "IrcListHelper"), IrcListHelperStub {
override fun fromVariantMap(properties: QVariantMap) = Unit
override fun toVariantMap() = emptyMap<String, QVariant_>()
}
......@@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import org.threeten.bp.Instant
import org.threeten.bp.temporal.Temporal
class IrcUser(
open class IrcUser(
hostmask: String,
network: NetworkId,
session: Session
......
......@@ -34,7 +34,7 @@ import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
import java.nio.ByteBuffer
class Network constructor(
open class Network(
networkId: NetworkId,
session: Session
) : SyncableObject(session, "Network"), NetworkStub {
......
......@@ -9,3 +9,122 @@
*/
package de.justjanne.libquassel.protocol.syncables
import de.justjanne.libquassel.protocol.models.types.QtType
import de.justjanne.libquassel.protocol.syncables.state.NetworkConfigState
import de.justjanne.libquassel.protocol.syncables.stubs.NetworkConfigStub
import de.justjanne.libquassel.protocol.util.update
import de.justjanne.libquassel.protocol.variant.QVariantMap
import de.justjanne.libquassel.protocol.variant.into
import de.justjanne.libquassel.protocol.variant.qVariant
import kotlinx.coroutines.flow.MutableStateFlow
open class NetworkConfig(
session: Session
) : SyncableObject(session, "NetworkConfig"), NetworkConfigStub {
override fun init() {
renameObject("GlobalNetworkConfig")
}
override fun fromVariantMap(properties: QVariantMap) {
state.update {
copy(
pingTimeoutEnabled = properties["pingTimeoutEnabled"].into(pingTimeoutEnabled),
pingInterval = properties["pingInterval"].into(pingInterval),
maxPingCount = properties["maxPingCount"].into(maxPingCount),
autoWhoEnabled = properties["autoWhoEnabled"].into(autoWhoEnabled),
autoWhoInterval = properties["autoWhoInterval"].into(autoWhoInterval),
autoWhoNickLimit = properties["autoWhoNickLimit"].into(autoWhoNickLimit),
autoWhoDelay = properties["autoWhoDelay"].into(autoWhoDelay),
standardCtcp = properties["standardCtcp"].into(standardCtcp),
)
}
}
override fun toVariantMap() = mapOf(
"pingTimeoutEnabled" to qVariant(pingTimeoutEnabled(), QtType.Bool),
"pingInterval" to qVariant(pingInterval(), QtType.Int),
"maxPingCount" to qVariant(maxPingCount(), QtType.Int),
"autoWhoEnabled" to qVariant(autoWhoEnabled(), QtType.Bool),
"autoWhoInterval" to qVariant(autoWhoInterval(), QtType.Int),
"autoWhoNickLimit" to qVariant(autoWhoNickLimit(), QtType.Int),
"autoWhoDelay" to qVariant(autoWhoDelay(), QtType.Int),
"standardCtcp" to qVariant(standardCtcp(), QtType.Bool)
)
fun pingTimeoutEnabled() = state().pingTimeoutEnabled
fun pingInterval() = state().pingInterval
fun maxPingCount() = state().maxPingCount
fun autoWhoEnabled() = state().autoWhoEnabled
fun autoWhoInterval() = state().autoWhoInterval
fun autoWhoNickLimit() = state().autoWhoNickLimit
fun autoWhoDelay() = state().autoWhoDelay
fun standardCtcp() = state().standardCtcp
override fun setAutoWhoDelay(delay: Int) {
state.update {
copy(autoWhoDelay = delay)
}
super.setAutoWhoDelay(delay)
}
override fun setAutoWhoEnabled(enabled: Boolean) {
state.update {
copy(autoWhoEnabled = enabled)
}
super.setAutoWhoEnabled(enabled)
}
override fun setAutoWhoInterval(interval: Int) {
state.update {
copy(autoWhoInterval = interval)
}
super.setAutoWhoInterval(interval)
}
override fun setAutoWhoNickLimit(limit: Int) {
state.update {
copy(autoWhoNickLimit = limit)
}
super.setAutoWhoNickLimit(limit)
}
override fun setMaxPingCount(count: Int) {
state.update {
copy(maxPingCount = count)
}
super.setMaxPingCount(count)
}
override fun setPingInterval(interval: Int) {
state.update {
copy(pingInterval = interval)
}
super.setPingInterval(interval)
}
override fun setPingTimeoutEnabled(enabled: Boolean) {
state.update {
copy(pingTimeoutEnabled = enabled)
}
super.setPingTimeoutEnabled(enabled)
}
override fun setStandardCtcp(enabled: Boolean) {
state.update {
copy(standardCtcp = enabled)
}
super.setStandardCtcp(enabled)
}
@Suppress("NOTHING_TO_INLINE")
inline fun state() = flow().value
@Suppress("NOTHING_TO_INLINE")
inline fun flow() = state
@PublishedApi
internal val state = MutableStateFlow(
NetworkConfigState()
)
}
......@@ -14,17 +14,30 @@ import de.justjanne.libquassel.annotations.ProtocolSide
import de.justjanne.libquassel.protocol.models.SignalProxyMessage
import de.justjanne.libquassel.protocol.models.ids.IdentityId
import de.justjanne.libquassel.protocol.models.ids.NetworkId
import de.justjanne.libquassel.protocol.syncables.stubs.IdentityStub
import de.justjanne.libquassel.protocol.syncables.stubs.BacklogManagerStub
import de.justjanne.libquassel.protocol.syncables.stubs.IgnoreListManagerStub
import de.justjanne.libquassel.protocol.syncables.stubs.IrcListHelperStub
import de.justjanne.libquassel.protocol.syncables.stubs.RpcHandlerStub
import de.justjanne.libquassel.protocol.variant.QVariantList
interface Session : RpcHandlerStub {
val protocolSide: ProtocolSide
val objectRepository: ObjectRepository
fun network(id: NetworkId): Network?
fun identity(id: IdentityId): IdentityStub
fun identity(id: IdentityId): Identity
fun aliasManager(): AliasManager
fun bufferSyncer(): BufferSyncer
fun backlogManager(): BacklogManagerStub
fun bufferViewManager(): BufferViewManager
fun ignoreListManager(): IgnoreListManagerStub
fun highlightRuleManager(): HighlightRuleManager
fun ircListHelper(): IrcListHelperStub
fun coreInfo(): CoreInfo
fun dccConfig(): DccConfig
fun networkConfig(): NetworkConfig
fun synchronize(it: SyncableObject)
fun stopSynchronize(it: SyncableObject)
......
......@@ -9,3 +9,54 @@
*/
package de.justjanne.libquassel.protocol.syncables.state
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.flags.BufferTypes
import de.justjanne.libquassel.protocol.models.flags.MessageTypes
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.MsgId
import de.justjanne.libquassel.protocol.models.ids.NetworkId
data class BufferSyncerState(
val activities: Map<BufferId, MessageTypes> = emptyMap(),
val highlightCounts: Map<BufferId, Int> = emptyMap(),
val lastSeenMsg: Map<BufferId, MsgId> = emptyMap(),
val markerLines: Map<BufferId, MsgId> = emptyMap(),
val bufferInfos: Map<BufferId, BufferInfo> = emptyMap()
) {
fun where(
bufferName: String? = null,
bufferId: BufferId? = null,
networkId: NetworkId? = null,
type: BufferTypes? = null,
groupId: Int? = null,
networkState: NetworkState? = null
) = bufferInfos.values.asSequence()
.filter {
bufferName == null ||
networkState == null ||
networkState.caseMapper().equalsIgnoreCase(it.bufferName, bufferName)
}
.filter { bufferId == null || it.bufferId == bufferId }
.filter { networkId == null || it.networkId == networkId }
.filter { type == null || it.type == type }
.filter { groupId == null || it.groupId == groupId }
fun find(
bufferName: String? = null,
bufferId: BufferId? = null,
networkId: NetworkId? = null,
type: BufferTypes? = null,
groupId: Int? = null,
networkState: NetworkState? = null
) = where(bufferName, bufferId, networkId, type, groupId, networkState).firstOrNull()
fun all(
bufferName: String? = null,
bufferId: BufferId? = null,
networkId: NetworkId? = null,
type: BufferTypes? = null,
groupId: Int? = null,
networkState: NetworkState? = null
) = where(bufferName, bufferId, networkId, type, groupId, networkState).toList()
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment