Java rsocket bindings

This commit is contained in:
Alexander Nozik 2021-02-09 16:39:39 +03:00
parent b883bece48
commit cb22374da5
48 changed files with 242 additions and 151 deletions

View File

@ -31,7 +31,7 @@ Among other things, you can:
### `dataforge-control-core` module packages ### `dataforge-control-core` module packages
- `api` - defines API for device management. The main class here is - `api` - defines API for device management. The main class here is
[`Device`](dataforge-device-core/src/commonMain/kotlin/hep/dataforge/control/api/Device.kt). [`Device`](controls-core/src/commonMain/kotlin/hep/dataforge/control/api/Device.kt).
Generally, a Device has Properties that can be read and written. Also, some Actions Generally, a Device has Properties that can be read and written. Also, some Actions
can optionally be applied on a device (may or may not affect properties). can optionally be applied on a device (may or may not affect properties).

View File

@ -4,28 +4,26 @@ plugins {
kotlin("js") apply false kotlin("js") apply false
} }
val dataforgeVersion: String by extra("0.2.1-dev-2") val dataforgeVersion: String by extra("0.3.0")
val ktorVersion: String by extra("1.5.0") val ktorVersion: String by extra(ru.mipt.npm.gradle.KScienceVersions.ktorVersion)
val rsocketVersion by extra("0.12.0") val rsocketVersion by extra("0.12.0")
allprojects { allprojects {
repositories { repositories {
mavenLocal() mavenLocal()
//maven("https://dl.bintray.com/pdvrieze/maven")
//maven("http://maven.jzy3d.org/releases") //maven("http://maven.jzy3d.org/releases")
maven("https://kotlin.bintray.com/js-externals") maven("https://kotlin.bintray.com/js-externals")
maven("https://maven.pkg.github.com/altavir/kotlin-logging/") maven("https://dl.bintray.com/rsocket-admin/RSocket")
//maven("https://dl.bintray.com/rsocket-admin/RSocket")
//maven("https://maven.pkg.github.com/altavir/ktor-client-sse") //maven("https://maven.pkg.github.com/altavir/ktor-client-sse")
} }
group = "hep.dataforge" group = "ru.mipt.npm"
version = "0.1.0" version = "0.1.0"
} }
ksciencePublish { ksciencePublish {
githubProject = "controls.kt" githubProject = "controls.kt"
bintrayRepo = "dataforge" bintrayRepo = "kscience"
} }
apiValidation { apiValidation {

View File

@ -4,7 +4,6 @@ plugins {
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
val ktorVersion: String by rootProject.extra
kscience { kscience {
useCoroutines("1.4.1") useCoroutines("1.4.1")

View File

@ -4,7 +4,7 @@ import hep.dataforge.context.ContextAware
import hep.dataforge.control.api.Device.Companion.DEVICE_TARGET import hep.dataforge.control.api.Device.Companion.DEVICE_TARGET
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.provider.Type import hep.dataforge.misc.Type
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
@ -35,7 +35,7 @@ public interface Device : Closeable, ContextAware {
* Get the value of the property or throw error if property in not defined. * Get the value of the property or throw error if property in not defined.
* Suspend if property value is not available * Suspend if property value is not available
*/ */
public suspend fun getProperty(propertyName: String): MetaItem<*>? public suspend fun getProperty(propertyName: String): MetaItem?
/** /**
* Invalidate property and force recalculate * Invalidate property and force recalculate
@ -46,18 +46,18 @@ public interface Device : Closeable, ContextAware {
* Set property [value] for a property with name [propertyName]. * Set property [value] for a property with name [propertyName].
* In rare cases could suspend if the [Device] supports command queue and it is full at the moment. * In rare cases could suspend if the [Device] supports command queue and it is full at the moment.
*/ */
public suspend fun setProperty(propertyName: String, value: MetaItem<*>) public suspend fun setProperty(propertyName: String, value: MetaItem)
/** /**
* The [SharedFlow] of property changes * The [SharedFlow] of property changes
*/ */
public val propertyFlow: SharedFlow<Pair<String, MetaItem<*>>> public val propertyFlow: SharedFlow<Pair<String, MetaItem>>
/** /**
* Send an action request and suspend caller while request is being processed. * Send an action request and suspend caller while request is being processed.
* Could return null if request does not return a meaningful answer. * Could return null if request does not return a meaningful answer.
*/ */
public suspend fun execute(action: String, argument: MetaItem<*>? = null): MetaItem<*>? public suspend fun execute(action: String, argument: MetaItem? = null): MetaItem?
override fun close() { override fun close() {
scope.cancel("The device is closed") scope.cancel("The device is closed")
@ -74,4 +74,4 @@ public suspend fun Device.getState(): Meta = Meta{
} }
} }
//public suspend fun Device.execute(name: String, meta: Meta?): MetaItem<*>? = execute(name, meta?.let { MetaItem.NodeItem(it) }) //public suspend fun Device.execute(name: String, meta: Meta?): MetaItem? = execute(name, meta?.let { MetaItemNode(it) })

View File

@ -54,14 +54,14 @@ public operator fun DeviceHub.get(name: Name): Device? = when {
public operator fun DeviceHub.get(deviceName: String): Device? = get(deviceName.toName()) public operator fun DeviceHub.get(deviceName: String): Device? = get(deviceName.toName())
public suspend fun DeviceHub.getProperty(deviceName: Name, propertyName: String): MetaItem<*>? = public suspend fun DeviceHub.getProperty(deviceName: Name, propertyName: String): MetaItem? =
this[deviceName]?.getProperty(propertyName) this[deviceName]?.getProperty(propertyName)
public suspend fun DeviceHub.setProperty(deviceName: Name, propertyName: String, value: MetaItem<*>) { public suspend fun DeviceHub.setProperty(deviceName: Name, propertyName: String, value: MetaItem) {
this[deviceName]?.setProperty(propertyName, value) this[deviceName]?.setProperty(propertyName, value)
} }
public suspend fun DeviceHub.execute(deviceName: Name, command: String, argument: MetaItem<*>?): MetaItem<*>? = public suspend fun DeviceHub.execute(deviceName: Name, command: String, argument: MetaItem?): MetaItem? =
this[deviceName]?.execute(command, argument) this[deviceName]?.execute(command, argument)

View File

@ -8,7 +8,7 @@ import hep.dataforge.meta.asMetaItem
public interface DeviceAction { public interface DeviceAction {
public val name: String public val name: String
public val descriptor: ActionDescriptor public val descriptor: ActionDescriptor
public suspend operator fun invoke(arg: MetaItem<*>? = null): MetaItem<*>? public suspend operator fun invoke(arg: MetaItem? = null): MetaItem?
} }
public suspend operator fun DeviceAction.invoke(meta: Meta): MetaItem<*>? = invoke(meta.asMetaItem()) public suspend operator fun DeviceAction.invoke(meta: Meta): MetaItem? = invoke(meta.asMetaItem())

View File

@ -4,8 +4,8 @@ import hep.dataforge.context.Context
import hep.dataforge.control.api.ActionDescriptor import hep.dataforge.control.api.ActionDescriptor
import hep.dataforge.control.api.Device import hep.dataforge.control.api.Device
import hep.dataforge.control.api.PropertyDescriptor import hep.dataforge.control.api.PropertyDescriptor
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.misc.DFExperimental
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -29,9 +29,9 @@ public abstract class DeviceBase(override val context: Context) : Device {
private val _actions = HashMap<String, DeviceAction>() private val _actions = HashMap<String, DeviceAction>()
public val actions: Map<String, DeviceAction> get() = _actions public val actions: Map<String, DeviceAction> get() = _actions
private val sharedPropertyFlow = MutableSharedFlow<Pair<String, MetaItem<*>>>() private val sharedPropertyFlow = MutableSharedFlow<Pair<String, MetaItem>>()
override val propertyFlow: SharedFlow<Pair<String, MetaItem<*>>> get() = sharedPropertyFlow override val propertyFlow: SharedFlow<Pair<String, MetaItem>> get() = sharedPropertyFlow
private val sharedLogFlow = MutableSharedFlow<LogEntry>() private val sharedLogFlow = MutableSharedFlow<LogEntry>()
@ -62,47 +62,47 @@ public abstract class DeviceBase(override val context: Context) : Device {
_actions[name] = action _actions[name] = action
} }
override suspend fun getProperty(propertyName: String): MetaItem<*> = override suspend fun getProperty(propertyName: String): MetaItem =
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).read() (_properties[propertyName] ?: error("Property with name $propertyName not defined")).read()
override suspend fun invalidateProperty(propertyName: String) { override suspend fun invalidateProperty(propertyName: String) {
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).invalidate() (_properties[propertyName] ?: error("Property with name $propertyName not defined")).invalidate()
} }
override suspend fun setProperty(propertyName: String, value: MetaItem<*>) { override suspend fun setProperty(propertyName: String, value: MetaItem) {
(_properties[propertyName] as? DeviceProperty ?: error("Property with name $propertyName not defined")).write( (_properties[propertyName] as? DeviceProperty ?: error("Property with name $propertyName not defined")).write(
value value
) )
} }
override suspend fun execute(action: String, argument: MetaItem<*>?): MetaItem<*>? = override suspend fun execute(action: String, argument: MetaItem?): MetaItem? =
(_actions[action] ?: error("Request with name $action not defined")).invoke(argument) (_actions[action] ?: error("Request with name $action not defined")).invoke(argument)
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private open inner class BasicReadOnlyDeviceProperty( private open inner class BasicReadOnlyDeviceProperty(
override val name: String, override val name: String,
default: MetaItem<*>?, default: MetaItem?,
override val descriptor: PropertyDescriptor, override val descriptor: PropertyDescriptor,
private val getter: suspend (before: MetaItem<*>?) -> MetaItem<*>, private val getter: suspend (before: MetaItem?) -> MetaItem,
) : ReadOnlyDeviceProperty { ) : ReadOnlyDeviceProperty {
override val scope: CoroutineScope get() = this@DeviceBase.scope override val scope: CoroutineScope get() = this@DeviceBase.scope
private val state: MutableStateFlow<MetaItem<*>?> = MutableStateFlow(default) private val state: MutableStateFlow<MetaItem?> = MutableStateFlow(default)
override val value: MetaItem<*>? get() = state.value override val value: MetaItem? get() = state.value
override suspend fun invalidate() { override suspend fun invalidate() {
state.value = null state.value = null
} }
override fun updateLogical(item: MetaItem<*>) { override fun updateLogical(item: MetaItem) {
state.value = item state.value = item
scope.launch { scope.launch {
sharedPropertyFlow.emit(Pair(name, item)) sharedPropertyFlow.emit(Pair(name, item))
} }
} }
override suspend fun read(force: Boolean): MetaItem<*> { override suspend fun read(force: Boolean): MetaItem {
//backup current value //backup current value
val currentValue = value val currentValue = value
return if (force || currentValue == null) { return if (force || currentValue == null) {
@ -118,7 +118,7 @@ public abstract class DeviceBase(override val context: Context) : Device {
} }
} }
override fun flow(): StateFlow<MetaItem<*>?> = state override fun flow(): StateFlow<MetaItem?> = state
} }
/** /**
@ -126,9 +126,9 @@ public abstract class DeviceBase(override val context: Context) : Device {
*/ */
public fun createReadOnlyProperty( public fun createReadOnlyProperty(
name: String, name: String,
default: MetaItem<*>?, default: MetaItem?,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
getter: suspend (MetaItem<*>?) -> MetaItem<*>, getter: suspend (MetaItem?) -> MetaItem,
): ReadOnlyDeviceProperty { ): ReadOnlyDeviceProperty {
val property = BasicReadOnlyDeviceProperty( val property = BasicReadOnlyDeviceProperty(
name, name,
@ -143,13 +143,13 @@ public abstract class DeviceBase(override val context: Context) : Device {
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private inner class BasicDeviceProperty( private inner class BasicDeviceProperty(
name: String, name: String,
default: MetaItem<*>?, default: MetaItem?,
descriptor: PropertyDescriptor, descriptor: PropertyDescriptor,
getter: suspend (MetaItem<*>?) -> MetaItem<*>, getter: suspend (MetaItem?) -> MetaItem,
private val setter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>?, private val setter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem?,
) : BasicReadOnlyDeviceProperty(name, default, descriptor, getter), DeviceProperty { ) : BasicReadOnlyDeviceProperty(name, default, descriptor, getter), DeviceProperty {
override var value: MetaItem<*>? override var value: MetaItem?
get() = super.value get() = super.value
set(value) { set(value) {
scope.launch { scope.launch {
@ -163,7 +163,7 @@ public abstract class DeviceBase(override val context: Context) : Device {
private val writeLock = Mutex() private val writeLock = Mutex()
override suspend fun write(item: MetaItem<*>) { override suspend fun write(item: MetaItem) {
writeLock.withLock { writeLock.withLock {
//fast return if value is not changed //fast return if value is not changed
if (item == value) return@withLock if (item == value) return@withLock
@ -183,10 +183,10 @@ public abstract class DeviceBase(override val context: Context) : Device {
*/ */
internal fun createMutableProperty( internal fun createMutableProperty(
name: String, name: String,
default: MetaItem<*>?, default: MetaItem?,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
getter: suspend (MetaItem<*>?) -> MetaItem<*>, getter: suspend (MetaItem?) -> MetaItem,
setter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>?, setter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem?,
): DeviceProperty { ): DeviceProperty {
val property = BasicDeviceProperty( val property = BasicDeviceProperty(
name, name,
@ -205,9 +205,9 @@ public abstract class DeviceBase(override val context: Context) : Device {
private inner class BasicDeviceAction( private inner class BasicDeviceAction(
override val name: String, override val name: String,
override val descriptor: ActionDescriptor, override val descriptor: ActionDescriptor,
private val block: suspend (MetaItem<*>?) -> MetaItem<*>?, private val block: suspend (MetaItem?) -> MetaItem?,
) : DeviceAction { ) : DeviceAction {
override suspend fun invoke(arg: MetaItem<*>?): MetaItem<*>? = override suspend fun invoke(arg: MetaItem?): MetaItem? =
withContext(scope.coroutineContext + SupervisorJob(scope.coroutineContext[Job])) { withContext(scope.coroutineContext + SupervisorJob(scope.coroutineContext[Job])) {
block(arg) block(arg)
} }
@ -219,7 +219,7 @@ public abstract class DeviceBase(override val context: Context) : Device {
internal fun createAction( internal fun createAction(
name: String, name: String,
descriptorBuilder: ActionDescriptor.() -> Unit = {}, descriptorBuilder: ActionDescriptor.() -> Unit = {},
block: suspend (MetaItem<*>?) -> MetaItem<*>?, block: suspend (MetaItem?) -> MetaItem?,
): DeviceAction { ): DeviceAction {
val action = BasicDeviceAction(name, ActionDescriptor(name).apply(descriptorBuilder), block) val action = BasicDeviceAction(name, ActionDescriptor(name).apply(descriptorBuilder), block)
registerAction(name, action) registerAction(name, action)

View File

@ -30,24 +30,24 @@ public interface ReadOnlyDeviceProperty {
/** /**
* Directly update property logical value and notify listener without writing it to device * Directly update property logical value and notify listener without writing it to device
*/ */
public fun updateLogical(item: MetaItem<*>) public fun updateLogical(item: MetaItem)
/** /**
* Get cached value and return null if value is invalid or not initialized * Get cached value and return null if value is invalid or not initialized
*/ */
public val value: MetaItem<*>? public val value: MetaItem?
/** /**
* Read value either from cache if cache is valid or directly from physical device. * Read value either from cache if cache is valid or directly from physical device.
* If [force], reread from physical state even if the logical state is set. * If [force], reread from physical state even if the logical state is set.
*/ */
public suspend fun read(force: Boolean = false): MetaItem<*> public suspend fun read(force: Boolean = false): MetaItem
/** /**
* The [Flow] representing future logical states of the property. * The [Flow] representing future logical states of the property.
* Produces null when the state is invalidated * Produces null when the state is invalidated
*/ */
public fun flow(): Flow<MetaItem<*>?> public fun flow(): Flow<MetaItem?>
} }
@ -65,10 +65,10 @@ public fun ReadOnlyDeviceProperty.readEvery(duration: Duration): Job = scope.lau
* A writeable device property with non-suspended write * A writeable device property with non-suspended write
*/ */
public interface DeviceProperty : ReadOnlyDeviceProperty { public interface DeviceProperty : ReadOnlyDeviceProperty {
override var value: MetaItem<*>? override var value: MetaItem?
/** /**
* Write value to physical device. Invalidates logical value, but does not update it automatically * Write value to physical device. Invalidates logical value, but does not update it automatically
*/ */
public suspend fun write(item: MetaItem<*>) public suspend fun write(item: MetaItem)
} }

View File

@ -32,7 +32,7 @@ public class TypedDeviceProperty<T : Any>(
converter: MetaConverter<T>, converter: MetaConverter<T>,
) : TypedReadOnlyDeviceProperty<T>(property, converter), DeviceProperty { ) : TypedReadOnlyDeviceProperty<T>(property, converter), DeviceProperty {
override var value: MetaItem<*>? override var value: MetaItem?
get() = property.value get() = property.value
set(arg) { set(arg) {
property.value = arg property.value = arg
@ -44,7 +44,7 @@ public class TypedDeviceProperty<T : Any>(
property.value = arg?.let { converter.objectToMetaItem(arg) } property.value = arg?.let { converter.objectToMetaItem(arg) }
} }
override suspend fun write(item: MetaItem<*>) { override suspend fun write(item: MetaItem) {
property.write(item) property.write(item)
} }

View File

@ -3,6 +3,8 @@ package hep.dataforge.control.base
import hep.dataforge.control.api.ActionDescriptor import hep.dataforge.control.api.ActionDescriptor
import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MetaItemNode
import hep.dataforge.meta.MetaItemValue
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlin.properties.PropertyDelegateProvider import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
@ -20,7 +22,7 @@ public typealias ActionDelegate = ReadOnlyProperty<DeviceBase, DeviceAction>
private class ActionProvider<D : DeviceBase>( private class ActionProvider<D : DeviceBase>(
val owner: D, val owner: D,
val descriptorBuilder: ActionDescriptor.() -> Unit = {}, val descriptorBuilder: ActionDescriptor.() -> Unit = {},
val block: suspend (MetaItem<*>?) -> MetaItem<*>?, val block: suspend (MetaItem?) -> MetaItem?,
) : PropertyDelegateProvider<D, ActionDelegate> { ) : PropertyDelegateProvider<D, ActionDelegate> {
override operator fun provideDelegate(thisRef: D, property: KProperty<*>): ActionDelegate { override operator fun provideDelegate(thisRef: D, property: KProperty<*>): ActionDelegate {
val name = property.name val name = property.name
@ -31,28 +33,28 @@ private class ActionProvider<D : DeviceBase>(
public fun DeviceBase.requesting( public fun DeviceBase.requesting(
descriptorBuilder: ActionDescriptor.() -> Unit = {}, descriptorBuilder: ActionDescriptor.() -> Unit = {},
action: suspend (MetaItem<*>?) -> MetaItem<*>?, action: suspend (MetaItem?) -> MetaItem?,
): PropertyDelegateProvider<DeviceBase, ActionDelegate> = ActionProvider(this, descriptorBuilder, action) ): PropertyDelegateProvider<DeviceBase, ActionDelegate> = ActionProvider(this, descriptorBuilder, action)
public fun <D : DeviceBase> D.requestingValue( public fun <D : DeviceBase> D.requestingValue(
descriptorBuilder: ActionDescriptor.() -> Unit = {}, descriptorBuilder: ActionDescriptor.() -> Unit = {},
action: suspend (MetaItem<*>?) -> Any?, action: suspend (MetaItem?) -> Any?,
): PropertyDelegateProvider<D, ActionDelegate> = ActionProvider(this, descriptorBuilder) { ): PropertyDelegateProvider<D, ActionDelegate> = ActionProvider(this, descriptorBuilder) {
val res = action(it) val res = action(it)
MetaItem.ValueItem(Value.of(res)) MetaItemValue(Value.of(res))
} }
public fun <D : DeviceBase> D.requestingMeta( public fun <D : DeviceBase> D.requestingMeta(
descriptorBuilder: ActionDescriptor.() -> Unit = {}, descriptorBuilder: ActionDescriptor.() -> Unit = {},
action: suspend MetaBuilder.(MetaItem<*>?) -> Unit, action: suspend MetaBuilder.(MetaItem?) -> Unit,
): PropertyDelegateProvider<D, ActionDelegate> = ActionProvider(this, descriptorBuilder) { ): PropertyDelegateProvider<D, ActionDelegate> = ActionProvider(this, descriptorBuilder) {
val res = MetaBuilder().apply { action(it) } val res = MetaBuilder().apply { action(it) }
MetaItem.NodeItem(res) MetaItemNode(res)
} }
public fun DeviceBase.acting( public fun DeviceBase.acting(
descriptorBuilder: ActionDescriptor.() -> Unit = {}, descriptorBuilder: ActionDescriptor.() -> Unit = {},
action: suspend (MetaItem<*>?) -> Unit, action: suspend (MetaItem?) -> Unit,
): PropertyDelegateProvider<DeviceBase, ActionDelegate> = ActionProvider(this, descriptorBuilder) { ): PropertyDelegateProvider<DeviceBase, ActionDelegate> = ActionProvider(this, descriptorBuilder) {
action(it) action(it)
null null

View File

@ -29,9 +29,9 @@ public typealias TypedReadOnlyPropertyDelegate<T> = ReadOnlyProperty<DeviceBase,
private class ReadOnlyDevicePropertyProvider<D : DeviceBase>( private class ReadOnlyDevicePropertyProvider<D : DeviceBase>(
val owner: D, val owner: D,
val default: MetaItem<*>?, val default: MetaItem?,
val descriptorBuilder: PropertyDescriptor.() -> Unit = {}, val descriptorBuilder: PropertyDescriptor.() -> Unit = {},
private val getter: suspend (MetaItem<*>?) -> MetaItem<*>, private val getter: suspend (MetaItem?) -> MetaItem,
) : PropertyDelegateProvider<D, ReadOnlyPropertyDelegate> { ) : PropertyDelegateProvider<D, ReadOnlyPropertyDelegate> {
override operator fun provideDelegate(thisRef: D, property: KProperty<*>): ReadOnlyPropertyDelegate { override operator fun provideDelegate(thisRef: D, property: KProperty<*>): ReadOnlyPropertyDelegate {
@ -43,10 +43,10 @@ private class ReadOnlyDevicePropertyProvider<D : DeviceBase>(
private class TypedReadOnlyDevicePropertyProvider<D : DeviceBase, T : Any>( private class TypedReadOnlyDevicePropertyProvider<D : DeviceBase, T : Any>(
val owner: D, val owner: D,
val default: MetaItem<*>?, val default: MetaItem?,
val converter: MetaConverter<T>, val converter: MetaConverter<T>,
val descriptorBuilder: PropertyDescriptor.() -> Unit = {}, val descriptorBuilder: PropertyDescriptor.() -> Unit = {},
private val getter: suspend (MetaItem<*>?) -> MetaItem<*>, private val getter: suspend (MetaItem?) -> MetaItem,
) : PropertyDelegateProvider<D, TypedReadOnlyPropertyDelegate<T>> { ) : PropertyDelegateProvider<D, TypedReadOnlyPropertyDelegate<T>> {
override operator fun provideDelegate(thisRef: D, property: KProperty<*>): TypedReadOnlyPropertyDelegate<T> { override operator fun provideDelegate(thisRef: D, property: KProperty<*>): TypedReadOnlyPropertyDelegate<T> {
@ -57,9 +57,9 @@ private class TypedReadOnlyDevicePropertyProvider<D : DeviceBase, T : Any>(
} }
public fun DeviceBase.reading( public fun DeviceBase.reading(
default: MetaItem<*>? = null, default: MetaItem? = null,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
getter: suspend (MetaItem<*>?) -> MetaItem<*>, getter: suspend (MetaItem?) -> MetaItem,
): PropertyDelegateProvider<DeviceBase, ReadOnlyPropertyDelegate> = ReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, ReadOnlyPropertyDelegate> = ReadOnlyDevicePropertyProvider(
this, this,
default, default,
@ -73,9 +73,9 @@ public fun DeviceBase.readingValue(
getter: suspend () -> Any?, getter: suspend () -> Any?,
): PropertyDelegateProvider<DeviceBase, ReadOnlyPropertyDelegate> = ReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, ReadOnlyPropertyDelegate> = ReadOnlyDevicePropertyProvider(
this, this,
default?.let { MetaItem.ValueItem(it) }, default?.let { MetaItemValue(it) },
descriptorBuilder, descriptorBuilder,
getter = { MetaItem.ValueItem(Value.of(getter())) } getter = { MetaItemValue(Value.of(getter())) }
) )
public fun DeviceBase.readingNumber( public fun DeviceBase.readingNumber(
@ -84,12 +84,12 @@ public fun DeviceBase.readingNumber(
getter: suspend () -> Number, getter: suspend () -> Number,
): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Number>> = TypedReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Number>> = TypedReadOnlyDevicePropertyProvider(
this, this,
default?.let { MetaItem.ValueItem(it.asValue()) }, default?.let { MetaItemValue(it.asValue()) },
MetaConverter.number, MetaConverter.number,
descriptorBuilder, descriptorBuilder,
getter = { getter = {
val number = getter() val number = getter()
MetaItem.ValueItem(number.asValue()) MetaItemValue(number.asValue())
} }
) )
@ -99,12 +99,12 @@ public fun DeviceBase.readingDouble(
getter: suspend () -> Double, getter: suspend () -> Double,
): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Double>> = TypedReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Double>> = TypedReadOnlyDevicePropertyProvider(
this, this,
default?.let { MetaItem.ValueItem(it.asValue()) }, default?.let { MetaItemValue(it.asValue()) },
MetaConverter.double, MetaConverter.double,
descriptorBuilder, descriptorBuilder,
getter = { getter = {
val number = getter() val number = getter()
MetaItem.ValueItem(number.asValue()) MetaItemValue(number.asValue())
} }
) )
@ -114,12 +114,12 @@ public fun DeviceBase.readingString(
getter: suspend () -> String, getter: suspend () -> String,
): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<String>> = TypedReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<String>> = TypedReadOnlyDevicePropertyProvider(
this, this,
default?.let { MetaItem.ValueItem(it.asValue()) }, default?.let { MetaItemValue(it.asValue()) },
MetaConverter.string, MetaConverter.string,
descriptorBuilder, descriptorBuilder,
getter = { getter = {
val number = getter() val number = getter()
MetaItem.ValueItem(number.asValue()) MetaItemValue(number.asValue())
} }
) )
@ -129,12 +129,12 @@ public fun DeviceBase.readingBoolean(
getter: suspend () -> Boolean, getter: suspend () -> Boolean,
): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Boolean>> = TypedReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Boolean>> = TypedReadOnlyDevicePropertyProvider(
this, this,
default?.let { MetaItem.ValueItem(it.asValue()) }, default?.let { MetaItemValue(it.asValue()) },
MetaConverter.boolean, MetaConverter.boolean,
descriptorBuilder, descriptorBuilder,
getter = { getter = {
val boolean = getter() val boolean = getter()
MetaItem.ValueItem(boolean.asValue()) MetaItemValue(boolean.asValue())
} }
) )
@ -144,11 +144,11 @@ public fun DeviceBase.readingMeta(
getter: suspend MetaBuilder.() -> Unit, getter: suspend MetaBuilder.() -> Unit,
): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Meta>> = TypedReadOnlyDevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Meta>> = TypedReadOnlyDevicePropertyProvider(
this, this,
default?.let { MetaItem.NodeItem(it) }, default?.let { MetaItemNode(it) },
MetaConverter.meta, MetaConverter.meta,
descriptorBuilder, descriptorBuilder,
getter = { getter = {
MetaItem.NodeItem(MetaBuilder().apply { getter() }) MetaItemNode(MetaBuilder().apply { getter() })
} }
) )
@ -170,10 +170,10 @@ public typealias TypedPropertyDelegate<T> = ReadOnlyProperty<DeviceBase, TypedDe
private class DevicePropertyProvider<D : DeviceBase>( private class DevicePropertyProvider<D : DeviceBase>(
val owner: D, val owner: D,
val default: MetaItem<*>?, val default: MetaItem?,
val descriptorBuilder: PropertyDescriptor.() -> Unit = {}, val descriptorBuilder: PropertyDescriptor.() -> Unit = {},
private val getter: suspend (MetaItem<*>?) -> MetaItem<*>, private val getter: suspend (MetaItem?) -> MetaItem,
private val setter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>?, private val setter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem?,
) : PropertyDelegateProvider<D, PropertyDelegate> { ) : PropertyDelegateProvider<D, PropertyDelegate> {
override operator fun provideDelegate(thisRef: D, property: KProperty<*>): PropertyDelegate { override operator fun provideDelegate(thisRef: D, property: KProperty<*>): PropertyDelegate {
@ -185,11 +185,11 @@ private class DevicePropertyProvider<D : DeviceBase>(
private class TypedDevicePropertyProvider<D : DeviceBase, T : Any>( private class TypedDevicePropertyProvider<D : DeviceBase, T : Any>(
val owner: D, val owner: D,
val default: MetaItem<*>?, val default: MetaItem?,
val converter: MetaConverter<T>, val converter: MetaConverter<T>,
val descriptorBuilder: PropertyDescriptor.() -> Unit = {}, val descriptorBuilder: PropertyDescriptor.() -> Unit = {},
private val getter: suspend (MetaItem<*>?) -> MetaItem<*>, private val getter: suspend (MetaItem?) -> MetaItem,
private val setter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>?, private val setter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem?,
) : PropertyDelegateProvider<D, TypedPropertyDelegate<T>> { ) : PropertyDelegateProvider<D, TypedPropertyDelegate<T>> {
override operator fun provideDelegate(thisRef: D, property: KProperty<*>): TypedPropertyDelegate<T> { override operator fun provideDelegate(thisRef: D, property: KProperty<*>): TypedPropertyDelegate<T> {
@ -200,10 +200,10 @@ private class TypedDevicePropertyProvider<D : DeviceBase, T : Any>(
} }
public fun DeviceBase.writing( public fun DeviceBase.writing(
default: MetaItem<*>? = null, default: MetaItem? = null,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
getter: suspend (MetaItem<*>?) -> MetaItem<*>, getter: suspend (MetaItem?) -> MetaItem,
setter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>?, setter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem?,
): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = DevicePropertyProvider( ): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = DevicePropertyProvider(
this, this,
default, default,
@ -213,7 +213,7 @@ public fun DeviceBase.writing(
) )
public fun DeviceBase.writingVirtual( public fun DeviceBase.writingVirtual(
default: MetaItem<*>, default: MetaItem,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = writing( ): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = writing(
default, default,
@ -226,9 +226,9 @@ public fun DeviceBase.writingVirtual(
default: Value, default: Value,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = writing( ): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = writing(
MetaItem.ValueItem(default), MetaItemValue(default),
descriptorBuilder, descriptorBuilder,
getter = { it ?: MetaItem.ValueItem(default) }, getter = { it ?: MetaItemValue(default) },
setter = { _, newItem -> newItem } setter = { _, newItem -> newItem }
) )
@ -236,9 +236,9 @@ public fun DeviceBase.writingVirtual(
default: Meta, default: Meta,
descriptorBuilder: PropertyDescriptor.() -> Unit = {}, descriptorBuilder: PropertyDescriptor.() -> Unit = {},
): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = writing( ): PropertyDelegateProvider<DeviceBase, PropertyDelegate> = writing(
MetaItem.NodeItem(default), MetaItemNode(default),
descriptorBuilder, descriptorBuilder,
getter = { it ?: MetaItem.NodeItem(default) }, getter = { it ?: MetaItemNode(default) },
setter = { _, newItem -> newItem } setter = { _, newItem -> newItem }
) )
@ -247,17 +247,17 @@ public fun <D : DeviceBase> D.writingDouble(
getter: suspend (Double) -> Double, getter: suspend (Double) -> Double,
setter: suspend (oldValue: Double?, newValue: Double) -> Double?, setter: suspend (oldValue: Double?, newValue: Double) -> Double?,
): PropertyDelegateProvider<D, TypedPropertyDelegate<Double>> { ): PropertyDelegateProvider<D, TypedPropertyDelegate<Double>> {
val innerGetter: suspend (MetaItem<*>?) -> MetaItem<*> = { val innerGetter: suspend (MetaItem?) -> MetaItem = {
MetaItem.ValueItem(getter(it.double ?: Double.NaN).asValue()) MetaItemValue(getter(it.double ?: Double.NaN).asValue())
} }
val innerSetter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>? = { oldValue, newValue -> val innerSetter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem? = { oldValue, newValue ->
setter(oldValue.double, newValue.double ?: Double.NaN)?.asMetaItem() setter(oldValue.double, newValue.double ?: Double.NaN)?.asMetaItem()
} }
return TypedDevicePropertyProvider( return TypedDevicePropertyProvider(
this, this,
MetaItem.ValueItem(Double.NaN.asValue()), MetaItemValue(Double.NaN.asValue()),
MetaConverter.double, MetaConverter.double,
descriptorBuilder, descriptorBuilder,
innerGetter, innerGetter,
@ -270,18 +270,18 @@ public fun <D : DeviceBase> D.writingBoolean(
getter: suspend (Boolean?) -> Boolean, getter: suspend (Boolean?) -> Boolean,
setter: suspend (oldValue: Boolean?, newValue: Boolean) -> Boolean?, setter: suspend (oldValue: Boolean?, newValue: Boolean) -> Boolean?,
): PropertyDelegateProvider<D, TypedPropertyDelegate<Boolean>> { ): PropertyDelegateProvider<D, TypedPropertyDelegate<Boolean>> {
val innerGetter: suspend (MetaItem<*>?) -> MetaItem<*> = { val innerGetter: suspend (MetaItem?) -> MetaItem = {
MetaItem.ValueItem(getter(it.boolean).asValue()) MetaItemValue(getter(it.boolean).asValue())
} }
val innerSetter: suspend (oldValue: MetaItem<*>?, newValue: MetaItem<*>) -> MetaItem<*>? = { oldValue, newValue -> val innerSetter: suspend (oldValue: MetaItem?, newValue: MetaItem) -> MetaItem? = { oldValue, newValue ->
setter(oldValue.boolean, newValue.boolean ?: error("Can't convert $newValue to boolean"))?.asValue() setter(oldValue.boolean, newValue.boolean ?: error("Can't convert $newValue to boolean"))?.asValue()
?.asMetaItem() ?.asMetaItem()
} }
return TypedDevicePropertyProvider( return TypedDevicePropertyProvider(
this, this,
MetaItem.ValueItem(Null), MetaItemValue(Null),
MetaConverter.boolean, MetaConverter.boolean,
descriptorBuilder, descriptorBuilder,
innerGetter, innerGetter,

View File

@ -8,20 +8,20 @@ import kotlin.time.Duration
import kotlin.time.DurationUnit import kotlin.time.DurationUnit
import kotlin.time.toDuration import kotlin.time.toDuration
public fun Double.asMetaItem(): MetaItem.ValueItem = MetaItem.ValueItem(asValue()) public fun Double.asMetaItem(): MetaItemValue = MetaItemValue(asValue())
//TODO to be moved to DF //TODO to be moved to DF
public object DurationConverter : MetaConverter<Duration> { public object DurationConverter : MetaConverter<Duration> {
override fun itemToObject(item: MetaItem<*>): Duration = when (item) { override fun itemToObject(item: MetaItem): Duration = when (item) {
is MetaItem.NodeItem -> { is MetaItemNode -> {
val unit: DurationUnit = item.node["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS val unit: DurationUnit = item.node["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS
val value = item.node[Meta.VALUE_KEY].double ?: error("No value present for Duration") val value = item.node[Meta.VALUE_KEY].double ?: error("No value present for Duration")
value.toDuration(unit) value.toDuration(unit)
} }
is MetaItem.ValueItem -> item.value.double.toDuration(DurationUnit.SECONDS) is MetaItemValue -> item.value.double.toDuration(DurationUnit.SECONDS)
} }
override fun objectToMetaItem(obj: Duration): MetaItem<*> = obj.toDouble(DurationUnit.SECONDS).asMetaItem() override fun objectToMetaItem(obj: Duration): MetaItem = obj.toDouble(DurationUnit.SECONDS).asMetaItem()
} }
public val MetaConverter.Companion.duration: MetaConverter<Duration> get() = DurationConverter public val MetaConverter.Companion.duration: MetaConverter<Duration> get() = DurationConverter

View File

@ -4,9 +4,9 @@ import hep.dataforge.control.api.Device
import hep.dataforge.control.api.DeviceHub import hep.dataforge.control.api.DeviceHub
import hep.dataforge.control.api.get import hep.dataforge.control.api.get
import hep.dataforge.control.messages.* import hep.dataforge.control.messages.*
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -21,7 +21,7 @@ public class DeviceController(
public val deviceName: String, public val deviceName: String,
) { ) {
private val propertyChanges = device.propertyFlow.map { (propertyName: String, value: MetaItem<*>) -> private val propertyChanges = device.propertyFlow.map { (propertyName: String, value: MetaItem) ->
PropertyChangedMessage( PropertyChangedMessage(
sourceDevice = deviceName, sourceDevice = deviceName,
property = propertyName, property = propertyName,
@ -103,12 +103,12 @@ public class DeviceController(
val descriptionMeta = Meta { val descriptionMeta = Meta {
"properties" put { "properties" put {
device.propertyDescriptors.map { descriptor -> device.propertyDescriptors.map { descriptor ->
descriptor.name put descriptor.config descriptor.name put descriptor.toMeta()
} }
} }
"actions" put { "actions" put {
device.actionDescriptors.map { descriptor -> device.actionDescriptors.map { descriptor ->
descriptor.name put descriptor.config descriptor.name put descriptor.toMeta()
} }
} }
} }

View File

@ -3,7 +3,7 @@ package hep.dataforge.control.controllers
import hep.dataforge.control.api.DeviceHub import hep.dataforge.control.api.DeviceHub
import hep.dataforge.control.api.get import hep.dataforge.control.api.get
import hep.dataforge.control.messages.DeviceMessage import hep.dataforge.control.messages.DeviceMessage
import hep.dataforge.meta.DFExperimental import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
@ -33,7 +33,7 @@ public class HubController(
// private val listeners: Map<NameToken, DeviceListener> = hub.devices.mapValues { (deviceNameToken, device) -> // private val listeners: Map<NameToken, DeviceListener> = hub.devices.mapValues { (deviceNameToken, device) ->
// object : DeviceListener { // object : DeviceListener {
// override fun propertyChanged(propertyName: String, value: MetaItem<*>?) { // override fun propertyChanged(propertyName: String, value: MetaItem?) {
// if (value == null) return // if (value == null) return
// scope.launch { // scope.launch {
// val change = PropertyChangedMessage( // val change = PropertyChangedMessage(

View File

@ -42,7 +42,7 @@ public sealed class DeviceMessage {
@SerialName("property.changed") @SerialName("property.changed")
public data class PropertyChangedMessage( public data class PropertyChangedMessage(
public val property: String, public val property: String,
public val value: MetaItem<*>?, public val value: MetaItem?,
override val sourceDevice: String, override val sourceDevice: String,
override val targetDevice: String? = null, override val targetDevice: String? = null,
override val comment: String? = null, override val comment: String? = null,
@ -55,7 +55,7 @@ public data class PropertyChangedMessage(
@SerialName("property.set") @SerialName("property.set")
public data class PropertySetMessage( public data class PropertySetMessage(
public val property: String, public val property: String,
public val value: MetaItem<*>?, public val value: MetaItem?,
override val sourceDevice: String? = null, override val sourceDevice: String? = null,
override val targetDevice: String, override val targetDevice: String,
override val comment: String? = null, override val comment: String? = null,
@ -104,7 +104,7 @@ public data class DescriptionMessage(
@SerialName("action.execute") @SerialName("action.execute")
public data class ActionExecuteMessage( public data class ActionExecuteMessage(
public val action: String, public val action: String,
public val argument: MetaItem<*>?, public val argument: MetaItem?,
override val sourceDevice: String? = null, override val sourceDevice: String? = null,
override val targetDevice: String, override val targetDevice: String,
override val comment: String? = null, override val comment: String? = null,
@ -117,7 +117,7 @@ public data class ActionExecuteMessage(
@SerialName("action.result") @SerialName("action.result")
public data class ActionResultMessage( public data class ActionResultMessage(
public val action: String, public val action: String,
public val result: MetaItem<*>?, public val result: MetaItem?,
override val sourceDevice: String, override val sourceDevice: String,
override val targetDevice: String? = null, override val targetDevice: String? = null,
override val comment: String? = null, override val comment: String? = null,
@ -154,7 +154,7 @@ public data class EmptyDeviceMessage(
@SerialName("log") @SerialName("log")
public data class DeviceLogMessage( public data class DeviceLogMessage(
val message: String, val message: String,
val data: MetaItem<*>? = null, val data: MetaItem? = null,
override val sourceDevice: String? = null, override val sourceDevice: String? = null,
override val targetDevice: String? = null, override val targetDevice: String? = null,
override val comment: String? = null, override val comment: String? = null,

View File

@ -3,6 +3,7 @@ package hep.dataforge.control.ports
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.ContextAware import hep.dataforge.context.ContextAware
import hep.dataforge.context.Factory import hep.dataforge.context.Factory
import hep.dataforge.context.logger
import hep.dataforge.control.api.Socket import hep.dataforge.control.api.Socket
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel

View File

@ -3,6 +3,7 @@ package hep.dataforge.control.ports
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.ContextAware import hep.dataforge.context.ContextAware
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.context.logger
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect

View File

@ -1,7 +1,7 @@
package hep.dataforge.control.controllers package hep.dataforge.control.controllers
import hep.dataforge.control.base.* import hep.dataforge.control.base.*
import hep.dataforge.meta.* import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.transformations.MetaConverter import hep.dataforge.meta.transformations.MetaConverter
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
@ -12,7 +12,7 @@ import kotlin.time.Duration
/** /**
* Blocking read of the value * Blocking read of the value
*/ */
public operator fun ReadOnlyDeviceProperty.getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*> = public operator fun ReadOnlyDeviceProperty.getValue(thisRef: Any?, property: KProperty<*>): MetaItem =
runBlocking(scope.coroutineContext) { runBlocking(scope.coroutineContext) {
read() read()
} }
@ -22,7 +22,7 @@ public operator fun <T: Any> TypedReadOnlyDeviceProperty<T>.getValue(thisRef: An
readTyped() readTyped()
} }
public operator fun DeviceProperty.setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem<*>) { public operator fun DeviceProperty.setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem) {
this.value = value this.value = value
} }

View File

@ -1,6 +1,7 @@
package hep.dataforge.control.ports package hep.dataforge.control.ports
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.logger
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.int import hep.dataforge.meta.int

View File

@ -3,8 +3,6 @@ plugins {
id("ru.mipt.npm.publish") id("ru.mipt.npm.publish")
} }
val ktorVersion: String by rootProject.extra
kscience{ kscience{
useSerialization { useSerialization {
json() json()
@ -16,7 +14,7 @@ kotlin {
commonMain { commonMain {
dependencies { dependencies {
implementation(project(":magix:magix-service")) implementation(project(":magix:magix-service"))
implementation(project(":dataforge-device-core")) implementation(project(":controls-core"))
} }
} }
} }

View File

@ -1,5 +1,6 @@
package hep.dataforge.control.client package hep.dataforge.control.client
import hep.dataforge.context.logger
import hep.dataforge.control.controllers.DeviceManager import hep.dataforge.control.controllers.DeviceManager
import hep.dataforge.control.controllers.respondMessage import hep.dataforge.control.controllers.respondMessage
import hep.dataforge.control.messages.DeviceMessage import hep.dataforge.control.messages.DeviceMessage

View File

@ -4,6 +4,6 @@ plugins {
} }
dependencies{ dependencies{
api(project(":dataforge-device-core")) api(project(":controls-core"))
implementation("org.scream3r:jssc:2.8.0") implementation("org.scream3r:jssc:2.8.0")
} }

View File

@ -7,8 +7,8 @@ val dataforgeVersion: String by rootProject.extra
val ktorVersion: String by rootProject.extra val ktorVersion: String by rootProject.extra
dependencies{ dependencies{
implementation(project(":dataforge-device-core")) implementation(project(":controls-core"))
implementation(project(":dataforge-device-tcp")) implementation(project(":controls-tcp"))
implementation("io.ktor:ktor-server-cio:$ktorVersion") implementation("io.ktor:ktor-server-cio:$ktorVersion")
implementation("io.ktor:ktor-websockets:$ktorVersion") implementation("io.ktor:ktor-websockets:$ktorVersion")
implementation("io.ktor:ktor-serialization:$ktorVersion") implementation("io.ktor:ktor-serialization:$ktorVersion")

View File

@ -20,18 +20,19 @@ import io.ktor.http.HttpStatusCode
import io.ktor.request.receiveText import io.ktor.request.receiveText
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondRedirect import io.ktor.response.respondRedirect
import io.ktor.routing.* import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.route
import io.ktor.routing.routing
import io.ktor.server.cio.CIO import io.ktor.server.cio.CIO
import io.ktor.server.engine.ApplicationEngine import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.engine.embeddedServer import io.ktor.server.engine.embeddedServer
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
import io.ktor.util.getValue import io.ktor.util.getValue
import io.ktor.websocket.WebSockets import io.ktor.websocket.WebSockets
import io.ktor.websocket.webSocket
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.collect
import kotlinx.html.* import kotlinx.html.*
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -124,7 +125,7 @@ public fun Application.deviceModule(
li { li {
a(href = "../$deviceName/${property.name}/get") { +"${property.name}: " } a(href = "../$deviceName/${property.name}/get") { +"${property.name}: " }
code { code {
+property.config.toJson().toString() +property.toMeta().toJson().toString()
} }
} }
} }
@ -135,7 +136,7 @@ public fun Application.deviceModule(
li { li {
+("${action.name}: ") +("${action.name}: ")
code { code {
+action.config.toJson().toString() +action.toMeta().toJson().toString()
} }
} }
} }
@ -152,12 +153,12 @@ public fun Application.deviceModule(
put("target", name.toString()) put("target", name.toString())
put("properties", buildJsonArray { put("properties", buildJsonArray {
device.propertyDescriptors.forEach { descriptor -> device.propertyDescriptors.forEach { descriptor ->
add(descriptor.config.toJson()) add(descriptor.toMeta().toJson())
} }
}) })
put("actions", buildJsonArray { put("actions", buildJsonArray {
device.actionDescriptors.forEach { actionDescriptor -> device.actionDescriptors.forEach { actionDescriptor ->
add(actionDescriptor.config.toJson()) add(actionDescriptor.toMeta().toJson())
} }
}) })
} }

View File

@ -8,7 +8,7 @@ kotlin {
sourceSets { sourceSets {
commonMain { commonMain {
dependencies { dependencies {
api(project(":dataforge-device-core")) api(project(":controls-core"))
api("io.ktor:ktor-network:$ktorVersion") api("io.ktor:ktor-network:$ktorVersion")
} }
} }

View File

@ -17,9 +17,9 @@ repositories{
} }
dependencies{ dependencies{
implementation(project(":dataforge-device-core")) implementation(project(":controls-core"))
implementation(project(":dataforge-device-server")) implementation(project(":controls-server"))
implementation(project(":dataforge-magix-client")) implementation(project(":controls-magix-client"))
implementation("no.tornado:tornadofx:1.7.20") implementation("no.tornado:tornadofx:1.7.20")
implementation(kotlin("stdlib-jdk8")) implementation(kotlin("stdlib-jdk8"))
implementation("kscience.plotlykt:plotlykt-server:0.3.0") implementation("kscience.plotlykt:plotlykt-server:0.3.0")

View File

@ -2,6 +2,7 @@ package hep.dataforge.control.demo
import hep.dataforge.context.ContextAware import hep.dataforge.context.ContextAware
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.context.logger
import io.ktor.server.engine.ApplicationEngine import io.ktor.server.engine.ApplicationEngine
import javafx.scene.Parent import javafx.scene.Parent
import javafx.scene.control.Slider import javafx.scene.control.Slider

View File

@ -0,0 +1,10 @@
plugins {
java
id("ru.mipt.npm.jvm")
id("ru.mipt.npm.publish")
}
dependencies {
implementation(project(":magix:magix-service"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk9:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}")
}

View File

@ -0,0 +1,26 @@
package ru.mipt.npm.magix.client;
import hep.dataforge.magix.api.MagixMessage;
import kotlinx.serialization.json.JsonElement;
import java.io.IOException;
import java.util.concurrent.Flow;
/**
* See https://github.com/waltz-controls/rfc/tree/master/2
*
* @param <T>
*/
public interface MagixClient<T> {
void broadcast(MagixMessage<T> msg) throws IOException;
Flow.Publisher<MagixMessage<T>> subscribe();
static MagixClient<JsonElement> rSocketTcp(String host, int port) {
return ControlsMagixClient.Companion.rSocketTcp(host, port);
}
static MagixClient<JsonElement> rSocketWs(String host, int port, String path) {
return ControlsMagixClient.Companion.rSocketWs(host, port, path);
}
}

View File

@ -0,0 +1,42 @@
package ru.mipt.npm.magix.client
import hep.dataforge.magix.api.MagixEndpoint
import hep.dataforge.magix.api.MagixMessage
import hep.dataforge.magix.api.MagixMessageFilter
import hep.dataforge.magix.service.RSocketMagixEndpoint
import hep.dataforge.magix.service.withTcp
import kotlinx.coroutines.jdk9.asPublisher
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.JsonElement
import java.util.concurrent.Flow
public class ControlsMagixClient<T>(
private val endpoint: MagixEndpoint,
private val filter: MagixMessageFilter,
private val serializer: KSerializer<T>,
) : MagixClient<T> {
override fun broadcast(msg: MagixMessage<T>): Unit = runBlocking {
endpoint.broadcast(serializer, msg)
}
override fun subscribe(): Flow.Publisher<MagixMessage<T>> = endpoint.subscribe(serializer, filter).asPublisher()
public companion object {
public fun rSocketTcp(host: String, port: Int): ControlsMagixClient<JsonElement> {
val endpoint = runBlocking {
RSocketMagixEndpoint.withTcp(host, port)
}
return ControlsMagixClient(endpoint, MagixMessageFilter(), JsonElement.serializer())
}
public fun rSocketWs(host: String, port: Int, path: String = "/rsocket"): ControlsMagixClient<JsonElement> {
val endpoint = runBlocking {
RSocketMagixEndpoint.withWebSockets(host, port, path)
}
return ControlsMagixClient(endpoint, MagixMessageFilter(), JsonElement.serializer())
}
}
}

View File

@ -11,8 +11,8 @@ kscience {
} }
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
val ktorVersion: String by rootProject.extra
val rsocketVersion: String by rootProject.extra val rsocketVersion: String by rootProject.extra
val ktorVersion: String = ru.mipt.npm.gradle.KScienceVersions.ktorVersion
dependencies{ dependencies{
api(project(":magix:magix-api")) api(project(":magix:magix-api"))

View File

@ -25,6 +25,7 @@ public fun CoroutineScope.startMagixServer(
buffer, buffer,
extraBufferCapacity = buffer extraBufferCapacity = buffer
) )
val tcpTransport = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().serverTransport(port = rawSocketPort) val tcpTransport = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().serverTransport(port = rawSocketPort)
RSocketServer().bind(tcpTransport, magixAcceptor(magixFlow)) RSocketServer().bind(tcpTransport, magixAcceptor(magixFlow))

View File

@ -52,12 +52,14 @@ internal fun CoroutineScope.magixAcceptor(magixFlow: MutableSharedFlow<GenericMa
magixFlow.emit(message) magixFlow.emit(message)
} }
// bi-directional connection // bi-directional connection
requestChannel { _: Payload, input: Flow<Payload> -> requestChannel { request: Payload, input: Flow<Payload> ->
input.onEach { input.onEach {
magixFlow.emit(magixJson.decodeFromString(genericMessageSerializer, it.data.readText())) magixFlow.emit(magixJson.decodeFromString(genericMessageSerializer, it.data.readText()))
}.launchIn(this@magixAcceptor) }.launchIn(this@magixAcceptor)
magixFlow.map { message -> val filter = magixJson.decodeFromString(MagixMessageFilter.serializer(), request.data.readText())
magixFlow.filter(filter).map { message ->
val string = magixJson.encodeToString(genericMessageSerializer, message) val string = magixJson.encodeToString(genericMessageSerializer, message)
buildPayload { data(string) } buildPayload { data(string) }
} }

View File

@ -21,7 +21,7 @@ kscience{
val ktorVersion: String by rootProject.extra val ktorVersion: String by rootProject.extra
dependencies { dependencies {
implementation(project(":dataforge-device-tcp")) implementation(project(":controls-tcp"))
implementation(project(":dataforge-magix-client")) implementation(project(":controls-magix-client"))
implementation("no.tornado:tornadofx:1.7.20") implementation("no.tornado:tornadofx:1.7.20")
} }

View File

@ -3,6 +3,7 @@
package ru.mipt.npm.devices.pimotionmaster package ru.mipt.npm.devices.pimotionmaster
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.logger
import hep.dataforge.control.api.DeviceHub import hep.dataforge.control.api.DeviceHub
import hep.dataforge.control.api.PropertyDescriptor import hep.dataforge.control.api.PropertyDescriptor
import hep.dataforge.control.base.* import hep.dataforge.control.base.*

View File

@ -2,6 +2,7 @@ package ru.mipt.npm.devices.pimotionmaster
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.context.ContextAware import hep.dataforge.context.ContextAware
import hep.dataforge.context.logger
import hep.dataforge.control.api.Socket import hep.dataforge.control.api.Socket
import hep.dataforge.control.ports.AbstractPort import hep.dataforge.control.ports.AbstractPort
import hep.dataforge.control.ports.withDelimiter import hep.dataforge.control.ports.withDelimiter

View File

@ -1,9 +1,12 @@
package ru.mipt.npm.devices.pimotionmaster package ru.mipt.npm.devices.pimotionmaster
import hep.dataforge.context.logger
import hep.dataforge.control.api.Device import hep.dataforge.control.api.Device
import hep.dataforge.control.base.TypedDeviceProperty import hep.dataforge.control.base.TypedDeviceProperty
import hep.dataforge.control.base.TypedReadOnlyDeviceProperty import hep.dataforge.control.base.TypedReadOnlyDeviceProperty
import javafx.beans.property.* import javafx.beans.property.ObjectPropertyBase
import javafx.beans.property.Property
import javafx.beans.property.ReadOnlyProperty
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach

View File

@ -1,6 +1,6 @@
pluginManagement { pluginManagement {
val kotlinVersion = "1.4.21" val kotlinVersion = "1.4.30"
val toolsVersion = "0.7.1" val toolsVersion = "0.7.6"
repositories { repositories {
mavenLocal() mavenLocal()
@ -27,18 +27,20 @@ pluginManagement {
rootProject.name = "controls.kt" rootProject.name = "controls.kt"
include( include(
":dataforge-device-core", ":controls-core",
":dataforge-device-tcp", ":controls-tcp",
":dataforge-device-serial", ":controls-serial",
":dataforge-device-server", ":controls-server",
":demo", ":demo",
":magix", ":magix",
":magix:magix-api", ":magix:magix-api",
":magix:magix-server", ":magix:magix-server",
":magix:magix-service", ":magix:magix-service",
":dataforge-magix-client", ":magix:magix-java-client",
":controls-magix-client",
":motors" ":motors"
) )
//includeBuild("../dataforge-core") //includeBuild("../dataforge-core")
//includeBuild("../plotly.kt") //includeBuild("../plotly.kt")
include("magix-java-client")