Server is alive!

This commit is contained in:
Alexander Nozik 2020-12-09 19:06:17 +03:00
parent faddb8a393
commit 6a742658af
10 changed files with 45 additions and 36 deletions

View File

@ -2,7 +2,7 @@ plugins {
id("ru.mipt.npm.project") id("ru.mipt.npm.project")
} }
val dataforgeVersion by extra("0.2.0") val dataforgeVersion by extra("0.2.1-dev-4")
val ktorVersion by extra("1.4.2") val ktorVersion by extra("1.4.2")
val htmlVersion by extra("0.7.2") val htmlVersion by extra("0.7.2")
val kotlinWrappersVersion by extra("pre.129-kotlin-1.4.20") val kotlinWrappersVersion by extra("pre.129-kotlin-1.4.20")

View File

@ -3,8 +3,8 @@ package ru.mipt.npm.sat
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName
import hep.dataforge.vision.VisionManager import hep.dataforge.vision.VisionManager
import hep.dataforge.vision.get
import hep.dataforge.vision.server.close import hep.dataforge.vision.server.close
import hep.dataforge.vision.server.serve import hep.dataforge.vision.server.serve
import hep.dataforge.vision.server.show import hep.dataforge.vision.server.show
@ -40,11 +40,12 @@ fun main() {
vision("main".asName(), sat) vision("main".asName(), sat)
} }
launch { launch {
delay(1000)
while (isActive) { while (isActive) {
val currentLayer = Random.nextInt(10) val target = "layer[${Random.nextInt(1,10)}].segment[${Random.nextInt(3)},${Random.nextInt(3)}]".toName()
(sat["layer[$currentLayer]"] as? Solid)?.color(123) (sat[target] as? Solid)?.color("red")
delay(300) delay(300)
(sat["layer[$currentLayer]"] as? Solid)?.color = null (sat[target] as? Solid)?.color = "green"
} }
} }
} }

View File

@ -1,11 +1,11 @@
package hep.dataforge.vision package hep.dataforge.vision
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.number import hep.dataforge.meta.number
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.int import hep.dataforge.values.int
import hep.dataforge.values.string
import kotlin.math.max import kotlin.math.max
/** /**

View File

@ -3,10 +3,9 @@ package hep.dataforge.vision
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.plus import hep.dataforge.names.plus
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.* import kotlinx.serialization.*
@ -15,7 +14,7 @@ import kotlin.time.Duration
/** /**
* An update for a [Vision] or a [VisionGroup] * An update for a [Vision] or a [VisionGroup]
*/ */
public class VisionChangeBuilder: VisionContainerBuilder<Vision> { public class VisionChangeBuilder : VisionContainerBuilder<Vision> {
private val propertyChange = HashMap<Name, Config>() private val propertyChange = HashMap<Name, Config>()
private val childrenChange = HashMap<Name, Vision?>() private val childrenChange = HashMap<Name, Vision?>()
@ -47,7 +46,8 @@ private fun Vision.isolate(manager: VisionManager): Vision {
@Serializable @Serializable
public data class VisionChange( public data class VisionChange(
val propertyChange: Map<Name, @Serializable(MetaSerializer::class) Meta>, val propertyChange: Map<Name, @Serializable(MetaSerializer::class) Meta>,
val childrenChange: Map<Name, Vision?>) { val childrenChange: Map<Name, Vision?>,
) {
public fun isEmpty(): Boolean = propertyChange.isEmpty() && childrenChange.isEmpty() public fun isEmpty(): Boolean = propertyChange.isEmpty() && childrenChange.isEmpty()
/** /**
@ -64,7 +64,7 @@ private fun CoroutineScope.collectChange(
name: Name, name: Name,
source: Vision, source: Vision,
mutex: Mutex, mutex: Mutex,
collector: ()->VisionChangeBuilder, collector: () -> VisionChangeBuilder,
) { ) {
//Collect properties change //Collect properties change
source.config.onChange(mutex) { propertyName, oldItem, newItem -> source.config.onChange(mutex) { propertyName, oldItem, newItem ->
@ -107,17 +107,19 @@ public fun Vision.flowChanges(
val mutex = Mutex() val mutex = Mutex()
var collector = VisionChangeBuilder() var collector = VisionChangeBuilder()
scope.collectChange(Name.EMPTY, this@flowChanges, mutex){collector} scope.collectChange(Name.EMPTY, this@flowChanges, mutex) { collector }
while (true) { while (currentCoroutineContext().isActive) {
//Wait for changes to accumulate //Wait for changes to accumulate
kotlinx.coroutines.delay(collectionDuration) delay(collectionDuration)
//Propagate updates only if something is changed //Propagate updates only if something is changed
if (!collector.isEmpty()) { if (!collector.isEmpty()) {
//emit changes //emit changes
mutex.withLock {
emit(collector.isolate(manager)) emit(collector.isolate(manager))
//Reset the collector //Reset the collector
collector = VisionChangeBuilder() collector = VisionChangeBuilder()
} }
} }
}
} }

View File

@ -6,6 +6,7 @@ import hep.dataforge.names.asName
import hep.dataforge.values.Null import hep.dataforge.values.Null
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.values.asValue import hep.dataforge.values.asValue
import hep.dataforge.values.string
import javafx.scene.control.ColorPicker import javafx.scene.control.ColorPicker
import javafx.scene.paint.Color import javafx.scene.paint.Color
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -22,7 +23,7 @@ public class ColorValueChooser : ValueChooserBase<ColorPicker>() {
this.value = Color.valueOf(value.string) this.value = Color.valueOf(value.string)
} }
} catch (ex: Exception) { } catch (ex: Exception) {
LoggerFactory.getLogger(javaClass).warn("Invalid color field value: " + value.string) LoggerFactory.getLogger(javaClass).warn("Invalid color field value: $value")
} }
} }
} }

View File

@ -12,6 +12,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.values.Value import hep.dataforge.values.Value
import hep.dataforge.values.parseValue import hep.dataforge.values.parseValue
import hep.dataforge.values.string
import javafx.collections.FXCollections import javafx.collections.FXCollections
import javafx.scene.control.ComboBox import javafx.scene.control.ComboBox
import javafx.util.StringConverter import javafx.util.StringConverter

View File

@ -17,6 +17,7 @@
package hep.dataforge.vision.editor package hep.dataforge.vision.editor
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.values.string
import hep.dataforge.vision.dfIconView import hep.dataforge.vision.dfIconView
import javafx.beans.property.SimpleStringProperty import javafx.beans.property.SimpleStringProperty
import javafx.scene.control.TreeItem import javafx.scene.control.TreeItem

View File

@ -5,38 +5,40 @@ import hep.dataforge.meta.double
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.int import hep.dataforge.meta.int
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.int
import hep.dataforge.values.string
import hep.dataforge.vision.Colors import hep.dataforge.vision.Colors
import javafx.scene.paint.Color import javafx.scene.paint.Color
import javafx.scene.paint.Material import javafx.scene.paint.Material
import javafx.scene.paint.PhongMaterial import javafx.scene.paint.PhongMaterial
object FXMaterials { public object FXMaterials {
val RED = PhongMaterial().apply { public val RED: PhongMaterial = PhongMaterial().apply {
diffuseColor = Color.DARKRED diffuseColor = Color.DARKRED
specularColor = Color.WHITE specularColor = Color.WHITE
} }
val WHITE = PhongMaterial().apply { public val WHITE: PhongMaterial = PhongMaterial().apply {
diffuseColor = Color.WHITE diffuseColor = Color.WHITE
specularColor = Color.LIGHTBLUE specularColor = Color.LIGHTBLUE
} }
val GREY = PhongMaterial().apply { public val GREY: PhongMaterial = PhongMaterial().apply {
diffuseColor = Color.DARKGREY diffuseColor = Color.DARKGREY
specularColor = Color.WHITE specularColor = Color.WHITE
} }
val BLUE = PhongMaterial(Color.BLUE) public val BLUE: PhongMaterial = PhongMaterial(Color.BLUE)
} }
/** /**
* Infer color based on meta item * Infer color based on meta item
* @param opacity default opacity * @param opacity default opacity
*/ */
fun MetaItem<*>.color(opacity: Double = 1.0): Color { public fun MetaItem<*>.color(opacity: Double = 1.0): Color {
return when (this) { return when (this) {
is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) { is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) {
val int = value.number.toInt() val int = value.int
val red = int and 0x00ff0000 shr 16 val red = int and 0x00ff0000 shr 16
val green = int and 0x0000ff00 shr 8 val green = int and 0x0000ff00 shr 8
val blue = int and 0x000000ff val blue = int and 0x000000ff

View File

@ -37,7 +37,9 @@ import io.ktor.util.error
import io.ktor.websocket.WebSockets import io.ktor.websocket.WebSockets
import io.ktor.websocket.webSocket import io.ktor.websocket.webSocket
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.html.* import kotlinx.html.*
import kotlinx.html.stream.createHTML import kotlinx.html.stream.createHTML
import java.awt.Desktop import java.awt.Desktop
@ -115,15 +117,12 @@ public class VisionServer internal constructor(
application.log.debug("Opened server socket for $name") application.log.debug("Opened server socket for $name")
val vision: Vision = visions[name.toName()] ?: error("Plot with id='$name' not registered") val vision: Vision = visions[name.toName()] ?: error("Plot with id='$name' not registered")
try { vision.flowChanges(visionManager, updateInterval.milliseconds).onEach { update ->
vision.flowChanges(visionManager, updateInterval.milliseconds).collect { update ->
val json = VisionManager.defaultJson.encodeToString(VisionChange.serializer(), update) val json = VisionManager.defaultJson.encodeToString(VisionChange.serializer(), update)
outgoing.send(Frame.Text(json)) outgoing.send(Frame.Text(json))
} }.catch { ex ->
} catch (ex: Throwable) {
application.log.error("Closed server socket for $name with exception $ex")
application.log.error(ex) application.log.error(ex)
} }.launchIn(visionManager.context).join()
} }
//Plots in their json representation //Plots in their json representation
get("vision") { get("vision") {
@ -208,7 +207,7 @@ public fun Application.visionModule(context: Context, route: String = DEFAULT_PA
public fun VisionManager.serve( public fun VisionManager.serve(
host: String = "localhost", host: String = "localhost",
port: Int = 7777, port: Int = 7777,
block: VisionServer.()->Unit block: VisionServer.() -> Unit,
): ApplicationEngine = context.embeddedServer(CIO, port, host) { ): ApplicationEngine = context.embeddedServer(CIO, port, host) {
visionModule(context).apply(block) visionModule(context).apply(block)
}.start() }.start()

View File

@ -2,6 +2,8 @@ package hep.dataforge.vision.solid.three
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.int
import hep.dataforge.values.string
import hep.dataforge.vision.Colors import hep.dataforge.vision.Colors
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
@ -90,7 +92,7 @@ public object ThreeMaterials {
public fun MetaItem<*>.getColor(): Color { public fun MetaItem<*>.getColor(): Color {
return when (this) { return when (this) {
is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) { is MetaItem.ValueItem -> if (this.value.type == ValueType.NUMBER) {
val int = value.number.toInt() val int = value.int
Color(int) Color(int)
} else { } else {
Color(this.value.string) Color(this.value.string)