From 104e8f8f6fee3bfadfeaa67e2de5dfb55bad6f63 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 29 Dec 2021 20:00:03 +0300 Subject: [PATCH] Remove Ktor client --- build.gradle.kts | 2 - .../mipt/npm/root/serialization/jsonToRoot.kt | 1 + .../visionforge/gdml/demo/GDMLAppComponent.kt | 4 +- .../src/main/kotlin/gravityDemo.kt | 4 +- .../src/main/kotlin/markupComponent.kt | 4 +- .../src/main/kotlin/plotlyComponent.kt | 2 +- demo/muon-monitor/build.gradle.kts | 2 - .../mipt/npm/muon/monitor/MMAppComponent.kt | 31 ++- .../ru/mipt/npm/muon/monitor/MMDemoApp.kt | 13 +- .../main/kotlin/ru/mipt/npm/sat/satServer.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../visionforge/bootstrap/outputConfig.kt | 6 +- .../visionforge/bootstrap/tabComponent.kt | 4 +- .../visionforge/bootstrap/threeControls.kt | 6 +- .../kscience/visionforge/react/MetaViewer.kt | 4 +- .../ThreeViewWithControls.kt | 203 +++++++++--------- .../ringThreeControls.kt | 8 +- visionforge-core/build.gradle.kts | 2 +- visionforge-server/build.gradle.kts | 9 +- .../visionforge/three/server/VisionServer.kt | 57 ++++- 20 files changed, 199 insertions(+), 167 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 62f608e4..625efc2c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,5 @@ plugins { id("ru.mipt.npm.gradle.project") -// kotlin("multiplatform") version "1.5.30" apply false -// kotlin("js") version "1.5.30" apply false } val dataforgeVersion by extra("0.5.2") diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt index 94079ccd..5d338394 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/serialization/jsonToRoot.kt @@ -46,6 +46,7 @@ private object RootDecoder { private val refCache: List, ) : KSerializer by tSerializer { + @Suppress("UNCHECKED_CAST") override fun deserialize(decoder: Decoder): T { val input = decoder as JsonDecoder val element = input.decodeJsonElement() diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt index 156fedb0..e5787050 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GDMLAppComponent.kt @@ -9,7 +9,7 @@ import org.w3c.files.FileReader import org.w3c.files.get import react.Props import react.dom.h2 -import react.functionComponent +import react.fc import react.useMemo import react.useState import space.kscience.dataforge.context.Context @@ -34,7 +34,7 @@ external interface GDMLAppProps : Props { } @JsExport -val GDMLApp = functionComponent("GDMLApp") { props -> +val GDMLApp = fc("GDMLApp") { props -> val visionManager = useMemo(props.context) { props.context.fetch(Solids).visionManager } var deferredVision: Deferred by useState { CompletableDeferred(props.vision) diff --git a/demo/js-playground/src/main/kotlin/gravityDemo.kt b/demo/js-playground/src/main/kotlin/gravityDemo.kt index b2788b23..716cc2c3 100644 --- a/demo/js-playground/src/main/kotlin/gravityDemo.kt +++ b/demo/js-playground/src/main/kotlin/gravityDemo.kt @@ -3,7 +3,7 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.css.* import react.Props -import react.functionComponent +import react.fc import space.kscience.dataforge.context.Context import space.kscience.plotly.layout import space.kscience.plotly.models.Trace @@ -20,7 +20,7 @@ external interface DemoProps : Props { var context: Context } -val GravityDemo = functionComponent { props -> +val GravityDemo = fc { props -> val velocityTrace = Trace{ name = "velocity" } diff --git a/demo/js-playground/src/main/kotlin/markupComponent.kt b/demo/js-playground/src/main/kotlin/markupComponent.kt index 0cdb17d0..4bbe4b80 100644 --- a/demo/js-playground/src/main/kotlin/markupComponent.kt +++ b/demo/js-playground/src/main/kotlin/markupComponent.kt @@ -7,7 +7,7 @@ import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor import org.w3c.dom.Element import org.w3c.dom.HTMLElement import react.Props -import react.functionComponent +import react.fc import react.useEffect import react.useRef import space.kscience.visionforge.markup.VisionOfMarkup @@ -20,7 +20,7 @@ external interface MarkupProps : Props { var markup: VisionOfMarkup? } -val Markup = functionComponent("Markup") { props -> +val Markup = fc("Markup") { props -> val elementRef = useRef(null) useEffect(props.markup, elementRef) { diff --git a/demo/js-playground/src/main/kotlin/plotlyComponent.kt b/demo/js-playground/src/main/kotlin/plotlyComponent.kt index ee896df2..5a2c6a81 100644 --- a/demo/js-playground/src/main/kotlin/plotlyComponent.kt +++ b/demo/js-playground/src/main/kotlin/plotlyComponent.kt @@ -14,7 +14,7 @@ external interface PlotlyProps : Props { } -val Plotly = functionComponent("Plotly") { props -> +val Plotly = fc("Plotly") { props -> val elementRef = useRef(null) useEffect(props.plot, elementRef) { diff --git a/demo/muon-monitor/build.gradle.kts b/demo/muon-monitor/build.gradle.kts index 0ef8f166..d33cd455 100644 --- a/demo/muon-monitor/build.gradle.kts +++ b/demo/muon-monitor/build.gradle.kts @@ -52,8 +52,6 @@ kotlin { jsMain { dependencies { implementation(project(":ui:ring")) - implementation(npmlibs.ktor.client.js) - implementation(npmlibs.ktor.client.serialization) implementation(project(":visionforge-threejs")) //implementation(devNpm("webpack-bundle-analyzer", "4.4.0")) } diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt index 30a79315..879f6af7 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt @@ -1,17 +1,19 @@ package ru.mipt.npm.muon.monitor -import io.ktor.client.HttpClient -import io.ktor.client.request.get +import kotlinx.browser.window import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.await import kotlinx.coroutines.launch import kotlinx.css.* import kotlinx.html.js.onClickFunction +import kotlinx.serialization.json.Json +import org.w3c.fetch.RequestInit import react.Props import react.dom.attrs import react.dom.button import react.dom.p -import react.functionComponent +import react.fc import react.useMemo import react.useState import space.kscience.dataforge.context.Context @@ -31,13 +33,12 @@ import kotlin.math.PI external interface MMAppProps : Props { var model: Model var context: Context - var connection: HttpClient var selected: Name? } @OptIn(DelicateCoroutinesApi::class) @JsExport -val MMApp = functionComponent("Muon monitor") { props -> +val MMApp = fc("Muon monitor") { props -> val mmOptions = useMemo { Canvas3DOptions { @@ -75,9 +76,21 @@ val MMApp = functionComponent("Muon monitor") { props -> attrs { onClickFunction = { context.launch { - val event = props.connection.get( - "http://localhost:8080/event" - ) +// val event = props.connection.get( +// "http://localhost:8080/event" +// ) + val event = window.fetch( + "http://localhost:8080/event", + RequestInit("GET") + ).then { response -> + if (response.ok) { + response.text() + } else { + error("Failed to get event") + } + }.then { body -> + Json.decodeFromString(Event.serializer(), body) + }.await() events = events + event props.model.displayEvent(event) } @@ -102,7 +115,7 @@ val MMApp = functionComponent("Muon monitor") { props -> } +" : " styledSpan { - css{ + css { color = Color.blue } +event.hits.toString() diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt index f777d383..6b611146 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMDemoApp.kt @@ -1,10 +1,6 @@ package ru.mipt.npm.muon.monitor -import io.ktor.client.HttpClient -import io.ktor.client.features.json.JsonFeature -import io.ktor.client.features.json.serializer.KotlinxSerializer import kotlinx.browser.document -import react.child import react.dom.render import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.fetch @@ -15,15 +11,9 @@ import space.kscience.visionforge.startApplication private class MMDemoApp : Application { - private val connection = HttpClient { - install(JsonFeature) { - serializer = KotlinxSerializer() - } - } - override fun start(state: Map) { - val context = Context("MM-demo"){ + val context = Context("MM-demo") { plugin(ThreePlugin) } val visionManager = context.fetch(VisionManager) @@ -35,7 +25,6 @@ private class MMDemoApp : Application { child(MMApp) { attrs { this.model = model - this.connection = this@MMDemoApp.connection this.context = context } } diff --git a/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt b/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt index 3a360ce7..93f2ec7c 100644 --- a/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt +++ b/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt @@ -35,7 +35,7 @@ fun main() { } } - server.show() + server.openInBrowser() GlobalScope.launch { while (isActive) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102e..2e6e5897 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt index b20e2b0e..0d4e2dc7 100644 --- a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt +++ b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt @@ -9,12 +9,12 @@ import kotlinx.html.js.onClickFunction import org.w3c.dom.events.Event import org.w3c.files.Blob import org.w3c.files.BlobPropertyBag -import react.FunctionComponent +import react.FC import react.Props import react.RBuilder import react.dom.attrs import react.dom.button -import react.functionComponent +import react.fc import space.kscience.dataforge.meta.withDefault import space.kscience.visionforge.Vision import space.kscience.visionforge.encodeToString @@ -47,7 +47,7 @@ public external interface CanvasControlsProps : Props { public var vision: Vision? } -public val CanvasControls: FunctionComponent = functionComponent("CanvasControls") { props -> +public val CanvasControls: FC = fc("CanvasControls") { props -> flexColumn { flexRow { css { diff --git a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/tabComponent.kt b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/tabComponent.kt index fc58fed7..07bd9b55 100644 --- a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/tabComponent.kt +++ b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/tabComponent.kt @@ -18,7 +18,7 @@ public external interface TabProps : PropsWithChildren { } @JsExport -public val Tab: FunctionComponent = functionComponent { props -> +public val Tab: FC = fc { props -> props.children() } @@ -27,7 +27,7 @@ public external interface TabPaneProps : PropsWithChildren { } @JsExport -public val TabPane: FunctionComponent = functionComponent("TabPane") { props -> +public val TabPane: FC = fc("TabPane") { props -> var activeTab: String? by useState(props.activeTab) val children: Array = Children.map(props.children) { diff --git a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt index deda16d7..e7602b0e 100644 --- a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt +++ b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/threeControls.kt @@ -2,11 +2,11 @@ package space.kscience.visionforge.bootstrap import kotlinx.css.* import kotlinx.css.properties.border -import react.FunctionComponent +import react.FC import react.PropsWithChildren import react.RBuilder import react.dom.h2 -import react.functionComponent +import react.fc import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.isEmpty import space.kscience.visionforge.Vision @@ -24,7 +24,7 @@ public external interface ThreeControlsProps : PropsWithChildren { } @JsExport -public val ThreeControls: FunctionComponent = functionComponent { props -> +public val ThreeControls: FC = fc { props -> tabPane(if (props.selected != null) "Properties" else null) { tab("Canvas") { card("Canvas configuration") { diff --git a/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt b/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt index 7d41bde9..651c9d31 100644 --- a/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt +++ b/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt @@ -42,7 +42,7 @@ public external interface MetaViewerProps : Props { public var descriptor: MetaDescriptor? } -private val MetaViewerItem: FunctionComponent = functionComponent("MetaViewerItem") { props -> +private val MetaViewerItem: FC = fc("MetaViewerItem") { props -> metaViewerItem(props) } @@ -127,7 +127,7 @@ private fun RBuilder.metaViewerItem(props: MetaViewerProps) { } @JsExport -public val MetaViewer: FunctionComponent = functionComponent("MetaViewer") { props -> +public val MetaViewer: FC = fc("MetaViewer") { props -> child(MetaViewerItem) { attrs { this.key = "" diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt index 5dd44099..e9cf62bf 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt @@ -76,110 +76,109 @@ public fun RBuilder.nameCrumbs(name: Name?, link: (Name) -> Unit): Unit = styled } @JsExport -public val ThreeCanvasWithControls: FunctionComponent = - functionComponent("ThreeViewWithControls") { props -> - var selected by useState { props.selected } - var solid: Solid? by useState(null) +public val ThreeCanvasWithControls: FC = fc("ThreeViewWithControls") { props -> + var selected by useState { props.selected } + var solid: Solid? by useState(null) - useEffect { - props.context.launch { - solid = props.builderOfSolid.await().also { - it?.root(props.context.visionManager) - } - } - } - - val onSelect: (Name?) -> Unit = { - selected = it - } - - val options = useMemo(props.options) { - (props.options?: Canvas3DOptions()).apply { - this.onSelect = onSelect - } - } - - val selectedVision: Vision? = useMemo(props.builderOfSolid, selected) { - selected?.let { - when { - it.isEmpty() -> solid - else -> (solid as? VisionGroup)?.get(it) - } - } - } - - - flexRow { - css { - height = 100.pct - width = 100.pct - flexWrap = FlexWrap.wrap - alignItems = Align.stretch - alignContent = Align.stretch - } - - flexColumn { - css { - height = 100.pct - minWidth = 600.px - flex(10.0, 1.0, FlexBasis("600px")) - position = Position.relative - } - - if (solid == null) { - LoaderScreen { - attrs { - message = "Loading Three vision" - } - } - } else { - child(ThreeCanvasComponent) { - attrs { - this.context = props.context - this.solid = solid - this.selected = selected - this.options = options - } - } - } - - selectedVision?.let { vision -> - styledDiv { - css { - position = Position.absolute - top = 5.px - right = 5.px - width = 450.px - } - Island { - IslandHeader { - attrs { - border = true - } - nameCrumbs(selected) { selected = it } - } - IslandContent { - propertyEditor( - ownProperties = vision.meta, - allProperties = vision.computeProperties(), - descriptor = vision.descriptor, - key = selected - ) - } - } - } - } - } - flexColumn { - css { - padding(4.px) - minWidth = 400.px - height = 100.pct - overflowY = Overflow.auto - flex(1.0, 10.0, FlexBasis("300px")) - } - ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs) + useEffect { + props.context.launch { + solid = props.builderOfSolid.await().also { + it?.root(props.context.visionManager) } } } + val onSelect: (Name?) -> Unit = { + selected = it + } + + val options = useMemo(props.options) { + (props.options ?: Canvas3DOptions()).apply { + this.onSelect = onSelect + } + } + + val selectedVision: Vision? = useMemo(props.builderOfSolid, selected) { + selected?.let { + when { + it.isEmpty() -> solid + else -> (solid as? VisionGroup)?.get(it) + } + } + } + + + flexRow { + css { + height = 100.pct + width = 100.pct + flexWrap = FlexWrap.wrap + alignItems = Align.stretch + alignContent = Align.stretch + } + + flexColumn { + css { + height = 100.pct + minWidth = 600.px + flex(10.0, 1.0, FlexBasis("600px")) + position = Position.relative + } + + if (solid == null) { + LoaderScreen { + attrs { + message = "Loading Three vision" + } + } + } else { + child(ThreeCanvasComponent) { + attrs { + this.context = props.context + this.solid = solid + this.selected = selected + this.options = options + } + } + } + + selectedVision?.let { vision -> + styledDiv { + css { + position = Position.absolute + top = 5.px + right = 5.px + width = 450.px + } + Island { + IslandHeader { + attrs { + border = true + } + nameCrumbs(selected) { selected = it } + } + IslandContent { + propertyEditor( + ownProperties = vision.meta, + allProperties = vision.computeProperties(), + descriptor = vision.descriptor, + key = selected + ) + } + } + } + } + } + flexColumn { + css { + padding(4.px) + minWidth = 400.px + height = 100.pct + overflowY = Overflow.auto + flex(1.0, 10.0, FlexBasis("300px")) + } + ringThreeControls(options, solid, selected, onSelect, additionalTabs = props.additionalTabs) + } + } +} + diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt index eed656e6..68cc13b2 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt @@ -9,12 +9,12 @@ import kotlinx.html.js.onClickFunction import org.w3c.dom.events.Event import org.w3c.files.Blob import org.w3c.files.BlobPropertyBag -import react.FunctionComponent +import react.FC import react.Props import react.RBuilder import react.dom.attrs import react.dom.button -import react.functionComponent +import react.fc import ringui.Island import ringui.SmartTabs import ringui.Tab @@ -52,7 +52,7 @@ internal external interface CanvasControlsProps : Props { public var vision: Vision? } -internal val CanvasControls: FunctionComponent = functionComponent("CanvasControls") { props -> +internal val CanvasControls: FC = fc("CanvasControls") { props -> flexColumn { flexRow { css { @@ -94,7 +94,7 @@ public external interface ThreeControlsProps : Props { } @JsExport -public val ThreeControls: FunctionComponent = functionComponent { props -> +public val ThreeControls: FC = fc { props -> SmartTabs("Tree") { props.vision?.let { Tab("Tree") { diff --git a/visionforge-core/build.gradle.kts b/visionforge-core/build.gradle.kts index b411dee9..ecd14331 100644 --- a/visionforge-core/build.gradle.kts +++ b/visionforge-core/build.gradle.kts @@ -15,7 +15,7 @@ kotlin { commonMain { dependencies { api("space.kscience:dataforge-context:$dataforgeVersion") - api("org.jetbrains.kotlinx:kotlinx-html:${ru.mipt.npm.gradle.KScienceVersions.htmlVersion}") + api(npmlibs.kotlinx.html) api("org.jetbrains.kotlin-wrappers:kotlin-css") } } diff --git a/visionforge-server/build.gradle.kts b/visionforge-server/build.gradle.kts index 18fda1cf..ec77fa22 100644 --- a/visionforge-server/build.gradle.kts +++ b/visionforge-server/build.gradle.kts @@ -2,12 +2,9 @@ plugins { id("ru.mipt.npm.gradle.jvm") } -val ktorVersion = ru.mipt.npm.gradle.KScienceVersions.ktorVersion - dependencies { api(project(":visionforge-core")) - api("io.ktor:ktor-server-cio:$ktorVersion") - //api("io.ktor:ktor-server-netty:$ktorVersion") - api("io.ktor:ktor-html-builder:$ktorVersion") - api("io.ktor:ktor-websockets:$ktorVersion") + api(npmlibs.ktor.server.cio) + api(npmlibs.ktor.html.builder) + api(npmlibs.ktor.websockets) } \ No newline at end of file diff --git a/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt b/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt index 61c3fd84..82b27952 100644 --- a/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt +++ b/visionforge-server/src/main/kotlin/space/kscience/visionforge/three/server/VisionServer.kt @@ -38,10 +38,7 @@ import space.kscience.visionforge.html.* import space.kscience.visionforge.three.server.VisionServer.Companion.DEFAULT_PAGE import java.awt.Desktop import java.net.URI -import kotlin.collections.set -import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.ExperimentalTime /** @@ -53,10 +50,30 @@ public class VisionServer internal constructor( private val rootRoute: String, ) : Configurable, CoroutineScope by application { override val meta: ObservableMutableMeta = MutableMeta() + + /** + * Update minimal interval between updates in milliseconds (if there are no updates, push will not happen + */ public var updateInterval: Long by meta.long(300, key = UPDATE_INTERVAL_KEY) + + /** + * Cache page fragments. If false, pages will be reconstructed on each call. Default: `true` + */ public var cacheFragments: Boolean by meta.boolean(true) + + /** + * Embed the initial state of the vision inside its html tag. Default: `true` + */ public var dataEmbed: Boolean by meta.boolean(true, Name.parse("data.embed")) + + /** + * Fetch data on vision load. Overrides embedded data. Default: `false` + */ public var dataFetch: Boolean by meta.boolean(false, Name.parse("data.fetch")) + + /** + * Connect to server to get pushes. The address of the server is embedded in the tag. Default: `true` + */ public var dataConnect: Boolean by meta.boolean(true, Name.parse("data.connect")) /** @@ -64,6 +81,9 @@ public class VisionServer internal constructor( */ private val globalHeaders: ArrayList = ArrayList() + /** + * Add a header to all pages produced by this server + */ public fun header(block: TagConsumer<*>.() -> Unit) { globalHeaders.add(block) } @@ -73,7 +93,7 @@ public class VisionServer internal constructor( headers: List, visionFragment: HtmlVisionFragment, ): Map { - var visionMap: Map? = null + var visionMap: Map? = null head { meta { @@ -102,7 +122,7 @@ public class VisionServer internal constructor( * Server a map of visions without providing explicit html page for them */ @OptIn(DFExperimental::class) - public fun serveVisions(route: Route, visions: Map): Unit = route { + internal fun serveVisions(route: Route, visions: Map): Unit = route { application.log.info("Serving visions $visions at $route") //Update websocket @@ -158,8 +178,13 @@ public class VisionServer internal constructor( * Create a static html page and serve visions produced in the process */ @DFExperimental - public fun createHtmlAndServe(route: String, title: String, headers: List, visionFragment: HtmlVisionFragment): String{ - val htmlString = createHTML().apply { + public fun createHtmlAndServe( + route: String, + title: String, + headers: List, + visionFragment: HtmlVisionFragment, + ): String { + val htmlString = createHTML().apply { html { visionPage(title, headers, visionFragment).also { serveVisions(route, it) @@ -171,7 +196,7 @@ public class VisionServer internal constructor( } /** - * Serv visions in a given [route] without providing a page template + * Serve visions in a given [route] without providing a page template */ public fun serveVisions(route: String, visions: Map): Unit { application.routing { @@ -245,6 +270,9 @@ public inline fun VisionServer.useScript(src: String, crossinline block: SCRIPT. } } +/** + * Use css with given stylesheet link as a global header for all pages. + */ public inline fun VisionServer.useCss(href: String, crossinline block: LINK.() -> Unit = {}) { header { link { @@ -256,7 +284,7 @@ public inline fun VisionServer.useCss(href: String, crossinline block: LINK.() - } /** - * Attach plotly application to given server + * Attach VisionForge server application to given server */ public fun Application.visionServer(context: Context, route: String = DEFAULT_PAGE): VisionServer { if (featureOrNull(WebSockets) == null) { @@ -286,6 +314,9 @@ public fun Application.visionServer(context: Context, route: String = DEFAULT_PA return VisionServer(visionManager, this, route) } +/** + * Start a stand-alone VisionForge server at given host/port + */ public fun VisionManager.serve( host: String = "localhost", port: Int = 7777, @@ -294,10 +325,16 @@ public fun VisionManager.serve( visionServer(context).apply(block) }.start() -public fun ApplicationEngine.show() { +/** + * Connect to a given Ktor server using browser + */ +public fun ApplicationEngine.openInBrowser() { val connector = environment.connectors.first() val uri = URI("http", null, connector.host, connector.port, null, null, null) Desktop.getDesktop().browse(uri) } +/** + * Stop the server with default timeouts + */ public fun ApplicationEngine.close(): Unit = stop(1000, 5000) \ No newline at end of file