forked from kscience/visionforge
Add direct event processing to Vision
This commit is contained in:
parent
1ea5ef86e6
commit
c7d4bdfa5f
@ -45,7 +45,7 @@ include(
|
|||||||
":ui:ring",
|
":ui:ring",
|
||||||
// ":ui:material",
|
// ":ui:material",
|
||||||
":ui:bootstrap",
|
":ui:bootstrap",
|
||||||
":ui:compose",
|
// ":ui:compose",
|
||||||
":visionforge-core",
|
":visionforge-core",
|
||||||
":visionforge-solid",
|
":visionforge-solid",
|
||||||
// ":visionforge-fx",
|
// ":visionforge-fx",
|
||||||
|
@ -11,7 +11,6 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
|||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.dataforge.names.isEmpty
|
|
||||||
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
||||||
import space.kscience.visionforge.Vision.Companion.TYPE
|
import space.kscience.visionforge.Vision.Companion.TYPE
|
||||||
|
|
||||||
@ -50,14 +49,10 @@ public interface Vision : Described {
|
|||||||
* Receive and process a generic [VisionEvent].
|
* Receive and process a generic [VisionEvent].
|
||||||
*/
|
*/
|
||||||
public fun receiveEvent(event: VisionEvent) {
|
public fun receiveEvent(event: VisionEvent) {
|
||||||
if(event.targetName.isEmpty()) {
|
|
||||||
when (event) {
|
when (event) {
|
||||||
is VisionChangeEvent -> receiveChange(event.change)
|
is VisionChange -> receiveChange(event)
|
||||||
else -> TODO()
|
else -> TODO()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
error("Vision is not a group and can't process an event with non-empty target")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val descriptor: MetaDescriptor?
|
override val descriptor: MetaDescriptor?
|
||||||
|
@ -63,8 +63,7 @@ public data class VisionChange(
|
|||||||
public val vision: Vision? = null,
|
public val vision: Vision? = null,
|
||||||
public val properties: Meta? = null,
|
public val properties: Meta? = null,
|
||||||
public val children: Map<Name, VisionChange>? = null,
|
public val children: Map<Name, VisionChange>? = null,
|
||||||
)
|
) : VisionEvent
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An update for a [Vision]
|
* An update for a [Vision]
|
||||||
|
@ -13,7 +13,7 @@ import space.kscience.dataforge.names.parseAsName
|
|||||||
public interface VisionClient: Plugin {
|
public interface VisionClient: Plugin {
|
||||||
public val visionManager: VisionManager
|
public val visionManager: VisionManager
|
||||||
|
|
||||||
public suspend fun sendEvent(event: VisionEvent)
|
public suspend fun sendEvent(targetName: Name, event: VisionEvent)
|
||||||
|
|
||||||
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?)
|
public fun notifyPropertyChanged(visionName: Name, propertyName: Name, item: Meta?)
|
||||||
}
|
}
|
||||||
@ -35,8 +35,8 @@ public fun VisionClient.notifyPropertyChanged(visionName: Name, propertyName: St
|
|||||||
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
notifyPropertyChanged(visionName, propertyName.parseAsName(true), Meta(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun VisionClient.sendEvent(visionName: Name, event: MetaRepr): Unit {
|
public fun VisionClient.sendEvent(targetName: Name, payload: MetaRepr): Unit {
|
||||||
context.launch {
|
context.launch {
|
||||||
sendEvent(VisionMetaEvent(visionName, event.toMeta()))
|
sendEvent(targetName, VisionMetaEvent(payload.toMeta()))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,13 +12,6 @@ import space.kscience.dataforge.names.Name
|
|||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
public sealed interface VisionEvent {
|
public sealed interface VisionEvent {
|
||||||
public val targetName: Name
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a copy of this event with the same type and content, but different [targetName]
|
|
||||||
*/
|
|
||||||
public fun changeTarget(newTarget: Name): VisionEvent
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
|
public val CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
|
||||||
}
|
}
|
||||||
@ -29,15 +22,8 @@ public sealed interface VisionEvent {
|
|||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("meta")
|
@SerialName("meta")
|
||||||
public data class VisionMetaEvent(override val targetName: Name, public val meta: Meta) : VisionEvent {
|
public class VisionMetaEvent(public val meta: Meta) : VisionEvent
|
||||||
override fun changeTarget(newTarget: Name): VisionMetaEvent = VisionMetaEvent(newTarget, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
@SerialName("change")
|
|
||||||
public data class VisionChangeEvent(override val targetName: Name, public val change: VisionChange) : VisionEvent {
|
|
||||||
override fun changeTarget(newTarget: Name): VisionChangeEvent = VisionChangeEvent(newTarget, change)
|
|
||||||
}
|
|
||||||
|
|
||||||
public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
|
public val Vision.Companion.CLICK_EVENT_KEY: Name get() = Name.of("events", "click", "payload")
|
||||||
|
|
||||||
|
@ -6,7 +6,10 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import space.kscience.dataforge.meta.ValueType
|
import space.kscience.dataforge.meta.ValueType
|
||||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.value
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.NameToken
|
||||||
|
import space.kscience.dataforge.names.parseAsName
|
||||||
|
import space.kscience.dataforge.names.plus
|
||||||
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
||||||
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
import space.kscience.visionforge.Vision.Companion.STYLE_KEY
|
||||||
|
|
||||||
@ -26,15 +29,6 @@ public interface VisionGroup : Vision {
|
|||||||
updateProperties(it, Name.EMPTY)
|
updateProperties(it, Name.EMPTY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receiveEvent(event: VisionEvent) {
|
|
||||||
if (event.targetName.isEmpty()) {
|
|
||||||
super.receiveEvent(event)
|
|
||||||
} else {
|
|
||||||
val target = children[event.targetName] ?: error("Child vision with name ${event.targetName} not found")
|
|
||||||
target.receiveEvent(event.changeTarget(Name.EMPTY))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface MutableVisionGroup : VisionGroup {
|
public interface MutableVisionGroup : VisionGroup {
|
||||||
|
@ -20,7 +20,6 @@ import space.kscience.dataforge.meta.MetaSerializer
|
|||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.isEmpty
|
|
||||||
import space.kscience.dataforge.names.parseAsName
|
import space.kscience.dataforge.names.parseAsName
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer
|
import space.kscience.visionforge.html.VisionTagConsumer
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
import space.kscience.visionforge.html.VisionTagConsumer.Companion.OUTPUT_CONNECT_ATTRIBUTE
|
||||||
@ -82,15 +81,14 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val eventCollector by lazy {
|
private val eventCollector by lazy {
|
||||||
MutableSharedFlow<VisionEvent>(meta["feedback.eventCache"].int ?: 100)
|
MutableSharedFlow<Pair<Name, VisionEvent>>(meta["feedback.eventCache"].int ?: 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a custom feedback event
|
* Send a custom feedback event
|
||||||
*/
|
*/
|
||||||
override suspend fun sendEvent(event: VisionEvent) {
|
override suspend fun sendEvent(targetName: Name, event: VisionEvent) {
|
||||||
eventCollector.emit(event)
|
eventCollector.emit(targetName to event)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) {
|
private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) {
|
||||||
@ -127,8 +125,8 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// If change contains root vision replacement, do it
|
// If change contains root vision replacement, do it
|
||||||
if(event is VisionChangeEvent && event.targetName.isEmpty()) {
|
if(event is VisionChange) {
|
||||||
event.change.vision?.let { vision ->
|
event.vision?.let { vision ->
|
||||||
renderVision(element, name, vision, outputMeta)
|
renderVision(element, name, vision, outputMeta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,8 +148,8 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
|
|
||||||
onopen = {
|
onopen = {
|
||||||
feedbackJob = visionManager.context.launch {
|
feedbackJob = visionManager.context.launch {
|
||||||
eventCollector.filter { it.targetName == name }.onEach {
|
eventCollector.filter { it.first == name }.onEach {
|
||||||
send(visionManager.jsonFormat.encodeToString(VisionEvent.serializer(), it))
|
send(visionManager.jsonFormat.encodeToString(VisionEvent.serializer(), it.second))
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
|
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
@ -159,7 +157,7 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
val change = changeCollector[name] ?: continue
|
val change = changeCollector[name] ?: continue
|
||||||
if (!change.isEmpty()) {
|
if (!change.isEmpty()) {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
eventCollector.emit(VisionChangeEvent(name, change.deepCopy(visionManager)))
|
eventCollector.emit(name to change.deepCopy(visionManager))
|
||||||
change.reset()
|
change.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,8 +107,7 @@ public fun Application.serveVisionData(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
withContext(configuration.context.coroutineContext) {
|
withContext(configuration.context.coroutineContext) {
|
||||||
vision.flowChanges(configuration.updateInterval.milliseconds).onEach { update ->
|
vision.flowChanges(configuration.updateInterval.milliseconds).onEach { event ->
|
||||||
val event = VisionChangeEvent(Name.EMPTY, update)
|
|
||||||
val json = configuration.visionManager.jsonFormat.encodeToString(
|
val json = configuration.visionManager.jsonFormat.encodeToString(
|
||||||
VisionEvent.serializer(),
|
VisionEvent.serializer(),
|
||||||
event
|
event
|
||||||
|
Loading…
Reference in New Issue
Block a user