Refactor server API

This commit is contained in:
Alexander Nozik 2022-12-06 17:04:13 +03:00
parent fef1df3ab4
commit d28873e796
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
4 changed files with 20 additions and 38 deletions

View File

@ -31,7 +31,7 @@ fun main() {
val form = VisionOfHtmlForm("form").apply { val form = VisionOfHtmlForm("form").apply {
onPropertyChange(visionManager.context) { onPropertyChange(visionManager.context) {
println(this) println(values)
} }
} }
@ -71,7 +71,7 @@ fun main() {
value = "Submit" value = "Submit"
} }
} }
println(form.values)
vision(form) vision(form)
} }

View File

@ -55,6 +55,8 @@ public class VisionChangeBuilder : MutableVisionContainer<Vision> {
private var propertyChange = MutableMeta() private var propertyChange = MutableMeta()
private val children: HashMap<Name, VisionChangeBuilder> = HashMap() private val children: HashMap<Name, VisionChangeBuilder> = HashMap()
public operator fun get(name: Name): VisionChangeBuilder? = children[name]
public fun isEmpty(): Boolean = propertyChange.isEmpty() && propertyChange.isEmpty() && children.isEmpty() public fun isEmpty(): Boolean = propertyChange.isEmpty() && propertyChange.isEmpty() && children.isEmpty()
@Synchronized @Synchronized
@ -153,7 +155,7 @@ private fun CoroutineScope.collectChange(
*/ */
public fun Vision.flowChanges( public fun Vision.flowChanges(
collectionDuration: Duration, collectionDuration: Duration,
sendInitial: Boolean = false sendInitial: Boolean = false,
): Flow<VisionChange> = flow { ): Flow<VisionChange> = flow {
val manager = manager ?: error("Orphan vision could not collect changes") val manager = manager ?: error("Orphan vision could not collect changes")
coroutineScope { coroutineScope {
@ -161,7 +163,7 @@ public fun Vision.flowChanges(
val mutex = Mutex() val mutex = Mutex()
collectChange(Name.EMPTY, this@flowChanges, mutex, collector) collectChange(Name.EMPTY, this@flowChanges, mutex, collector)
if(sendInitial) { if (sendInitial) {
//Send initial vision state //Send initial vision state
val initialChange = VisionChange(vision = deepCopy(manager)) val initialChange = VisionChange(vision = deepCopy(manager))
emit(initialChange) emit(initialChange)

View File

@ -69,9 +69,9 @@ public class VisionClient : AbstractPlugin() {
changeCollector.propertyChanged(visionName, propertyName, item) changeCollector.propertyChanged(visionName, propertyName, item)
} }
public fun visionChanged(name: Name?, child: Vision?) { // public fun visionChanged(name: Name?, child: Vision?) {
changeCollector.setChild(name, child) // changeCollector.setChild(name, child)
} // }
private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) { private fun renderVision(element: Element, name: Name, vision: Vision, outputMeta: Meta) {
vision.setAsRoot(visionManager) vision.setAsRoot(visionManager)
@ -79,7 +79,7 @@ public class VisionClient : AbstractPlugin() {
renderer.render(element, name, vision, outputMeta) renderer.render(element, name, vision, outputMeta)
} }
private fun updateVision(element: Element, name: Name, vision: Vision?, outputMeta: Meta) { private fun startVisionUpdate(element: Element, name: Name, vision: Vision?, outputMeta: Meta) {
element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr -> element.attributes[OUTPUT_CONNECT_ATTRIBUTE]?.let { attr ->
val wsUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) { val wsUrl = if (attr.value.isBlank() || attr.value == VisionTagConsumer.AUTO_DATA_ATTRIBUTE) {
val endpoint = resolveEndpoint(element) val endpoint = resolveEndpoint(element)
@ -130,9 +130,10 @@ public class VisionClient : AbstractPlugin() {
feedbackJob = visionManager.context.launch { feedbackJob = visionManager.context.launch {
while (isActive) { while (isActive) {
delay(feedbackAggregationTime.milliseconds) delay(feedbackAggregationTime.milliseconds)
if (!changeCollector.isEmpty()) { val change = changeCollector[name] ?: continue
send(visionManager.encodeToString(changeCollector.deepCopy(visionManager))) if (!change.isEmpty()) {
changeCollector.reset() send(visionManager.encodeToString(change.deepCopy(visionManager)))
change.reset()
} }
} }
} }
@ -192,7 +193,7 @@ public class VisionClient : AbstractPlugin() {
response.text().then { text -> response.text().then { text ->
val vision = visionManager.decodeFromString(text) val vision = visionManager.decodeFromString(text)
renderVision(element, name, vision, outputMeta) renderVision(element, name, vision, outputMeta)
updateVision(element, name, vision, outputMeta) startVisionUpdate(element, name, vision, outputMeta)
} }
} else { } else {
logger.error { "Failed to fetch initial vision state from $fetchUrl" } logger.error { "Failed to fetch initial vision state from $fetchUrl" }
@ -208,12 +209,12 @@ public class VisionClient : AbstractPlugin() {
} }
logger.info { "Found embedded vision for output with name $name" } logger.info { "Found embedded vision for output with name $name" }
renderVision(element, name, embeddedVision, outputMeta) renderVision(element, name, embeddedVision, outputMeta)
updateVision(element, name, embeddedVision, outputMeta) startVisionUpdate(element, name, embeddedVision, outputMeta)
} }
//Try to load vision via websocket //Try to load vision via websocket
element.attributes[OUTPUT_CONNECT_ATTRIBUTE] != null -> { element.attributes[OUTPUT_CONNECT_ATTRIBUTE] != null -> {
updateVision(element, name, null, outputMeta) startVisionUpdate(element, name, null, outputMeta)
} }
else -> error("No embedded vision data / fetch url for $name") else -> error("No embedded vision data / fetch url for $name")

View File

@ -93,12 +93,12 @@ public fun Application.serveVisionData(
webSocket("ws") { webSocket("ws") {
val name: String = call.request.queryParameters.getOrFail("name") val name: String = call.request.queryParameters.getOrFail("name")
application.log.debug("Opened server socket for $name") application.log.debug("Opened server socket for $name")
val vision: Vision = resolveVision(Name.parse(name)) ?: error("Plot with id='$name' not registered") val vision: Vision = resolveVision(Name.parse(name)) ?: error("Vision with id='$name' not registered")
launch { launch {
for(frame in incoming) { for(frame in incoming) {
val data = frame.data.decodeToString() val data = frame.data.decodeToString()
application.log.debug("Received update: \n$data") application.log.debug("Received update for $name: \n$data")
val change = configuration.visionManager.jsonFormat.decodeFromString( val change = configuration.visionManager.jsonFormat.decodeFromString(
VisionChange.serializer(), data VisionChange.serializer(), data
) )
@ -113,7 +113,7 @@ public fun Application.serveVisionData(
VisionChange.serializer(), VisionChange.serializer(),
update update
) )
application.log.debug("Sending update: \n$json") application.log.debug("Sending update for $name: \n$json")
outgoing.send(Frame.Text(json)) outgoing.send(Frame.Text(json))
}.collect() }.collect()
} }
@ -145,27 +145,6 @@ public fun Application.serveVisionData(
data: Map<Name, Vision>, data: Map<Name, Vision>,
): Unit = serveVisionData(configuration) { data[it] } ): Unit = serveVisionData(configuration) { data[it] }
//
///**
// * Compile a fragment to string and serve visions from it
// */
//public fun Route.serveVisionsFromFragment(
// consumer: TagConsumer<*>,
// sererPageUrl: Url,
// visionManager: VisionManager,
// fragment: HtmlVisionFragment,
//): Unit {
// val visions = consumer.visionFragment(
// visionManager.context,
// embedData = true,
// fetchUpdatesUrl = "$serverUrl$route/ws",
// fragment = fragment
// )
//
// serveVisionData(visionManager, visions)
//}
/** /**
* Serve a page, potentially containing any number of visions at a given [route] with given [header]. * Serve a page, potentially containing any number of visions at a given [route] with given [header].
*/ */