diff --git a/kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolServer.kt b/kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolServer.kt index bb7aca5..d8962c8 100644 --- a/kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolServer.kt +++ b/kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolServer.kt @@ -44,12 +44,12 @@ open class HttpProtocolServer( private val wait: Boolean = false, private val bindHost: String = "0.0.0.0", private val bindPort: Int = 8080, + private var baseUrls: List = listOf("http://localhost:8080"), private val createServer: (host: String, port: Int, servient: Servient) -> EmbeddedServer<*, *> = ::defaultServer ) : ProtocolServer { val things: MutableMap = mutableMapOf() var started = false private var server: EmbeddedServer<*, *>? = null - private var actualAddresses: List = listOf("http://$bindHost:$bindPort") companion object { private val log = LoggerFactory.getLogger(HttpProtocolServer::class.java) @@ -77,27 +77,27 @@ open class HttpProtocolServer( log.info("Exposing thing '{}' on HttpProtocolServer", thing.id) things[thing.id] = thing - for (address in actualAddresses) { + for (baseUrl in baseUrls) { for (contentType in ContentManager.offeredMediaTypes) { // make reporting of all properties optional? - val href = "$address/${thing.id}/all/properties" + val href = "$baseUrl/${thing.id}/all/properties" val form = Form(href = href, contentType = contentType, op = listOf( Operation.READ_ALL_PROPERTIES, Operation.READ_MULTIPLE_PROPERTIES)) thing.forms += form log.debug("Assign '{}' for reading all properties", href) - exposeProperties(thing, address, contentType) - exposeActions(thing, address, contentType) - exposeEvents(thing, address, contentType) + exposeProperties(thing, baseUrl, contentType) + exposeActions(thing, baseUrl, contentType) + exposeEvents(thing, baseUrl, contentType) } } } - internal fun exposeProperties(thing: ExposedThing, address: String, contentType: String) { + internal fun exposeProperties(thing: ExposedThing, baseUrl: String, contentType: String) { thing.properties.forEach { (name, property) -> - val href = getHrefWithVariablePattern(address, thing, "properties", name, property) + val href = getHrefWithVariablePattern(baseUrl, thing, "properties", name, property) // Determine the operations based on readOnly/writeOnly status val operations = when { @@ -138,9 +138,9 @@ open class HttpProtocolServer( } } - internal fun exposeActions(thing: ExposedThing, address: String, contentType: String) { + internal fun exposeActions(thing: ExposedThing, baseUrl: String, contentType: String) { thing.actions.forEach { (name, action) -> - val href: String = getHrefWithVariablePattern(address, thing, "actions", name, action) + val href: String = getHrefWithVariablePattern(baseUrl, thing, "actions", name, action) // Initialize the form using named parameters val form = Form( href = href, @@ -154,9 +154,9 @@ open class HttpProtocolServer( } } - internal fun exposeEvents(thing: ExposedThing, address: String, contentType: String) { + internal fun exposeEvents(thing: ExposedThing, baseUrl: String, contentType: String) { thing.events.forEach { (name, event) -> - val href = getHrefWithVariablePattern(address, thing, "events", name, event) + val href = getHrefWithVariablePattern(baseUrl, thing, "events", name, event) // Create the form using named parameters directly val form = Form( @@ -173,7 +173,7 @@ open class HttpProtocolServer( } private fun getHrefWithVariablePattern( - address: String, + baseUrl: String, thing: ExposedThing, type: String, interactionName: String, @@ -184,7 +184,7 @@ open class HttpProtocolServer( if (!uriVariables.isNullOrEmpty()) { variables = "{?" + java.lang.String.join(",", uriVariables) + "}" } - return "$address/${thing.id}/$type/$interactionName$variables" + return "$baseUrl/${thing.id}/$type/$interactionName$variables" } // Destroy a thing diff --git a/kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolServerTest.kt b/kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolServerTest.kt index e295cd7..fc451c9 100644 --- a/kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolServerTest.kt +++ b/kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolServerTest.kt @@ -395,7 +395,7 @@ class HttpProtocolServerTest { // Assert assertTrue(exposedThing.forms.isNotEmpty(), "Expected forms to be added to thing") - val expectedHref = "http://0.0.0.0:8080/${exposedThing.id}/all/properties" + val expectedHref = "http://localhost:8080/${exposedThing.id}/all/properties" val form = exposedThing.forms.find { it.href == expectedHref } assertNotNull(form, "Expected form for reading all properties to be added") assertEquals(CONTENT_TYPE, form.contentType) @@ -406,12 +406,12 @@ class HttpProtocolServerTest { fun `exposeProperties should add forms for read write properties`() { // Arrange server.started = true - val address = "http://0.0.0.0:8080" + val baseUrl = "http://localhost:8080" // Act - server.exposeProperties(exposedThing, address, CONTENT_TYPE) + server.exposeProperties(exposedThing, baseUrl, CONTENT_TYPE) // Assert - val expectedHref = "$address/${exposedThing.id}/properties/$PROPERTY_NAME" + val expectedHref = "$baseUrl/${exposedThing.id}/properties/$PROPERTY_NAME" val form = exposedThing.properties[PROPERTY_NAME]?.forms?.find { it.href == expectedHref } assertNotNull(form, "Expected form for property '$PROPERTY_NAME' to be added") @@ -422,12 +422,12 @@ class HttpProtocolServerTest { fun `exposeActions should add form for action`() { // Arrange server.started = true - val address = "http://0.0.0.0:8080" + val baseUrl = "http://localhost:8080" // Act - server.exposeActions(exposedThing, address, CONTENT_TYPE) + server.exposeActions(exposedThing, baseUrl, CONTENT_TYPE) // Assert - val expectedHref = "$address/${exposedThing.id}/actions/$ACTION_NAME" + val expectedHref = "$baseUrl/${exposedThing.id}/actions/$ACTION_NAME" val form = exposedThing.actions[ACTION_NAME]?.forms?.find { it.href == expectedHref } assertNotNull(form, "Expected form for action 'action1' to be added") assertEquals(CONTENT_TYPE, form.contentType, "Content type should match") @@ -439,12 +439,12 @@ class HttpProtocolServerTest { fun `exposeEvents should add form for event`() { // Arrange server.started = true - val address = "http://0.0.0.0:8080" + val baseUrl = "http://localhost:8080" // Act - server.exposeEvents(exposedThing, address, CONTENT_TYPE) + server.exposeEvents(exposedThing, baseUrl, CONTENT_TYPE) // Assert - val expectedHref = "$address/${exposedThing.id}/events/$EVENT_NAME" + val expectedHref = "$baseUrl/${exposedThing.id}/events/$EVENT_NAME" val form = exposedThing.events[EVENT_NAME]?.forms?.find { it.href == expectedHref } assertNotNull(form, "Expected form for action 'action1' to be added") assertEquals(CONTENT_TYPE, form.contentType, "Content type should match") diff --git a/kotlin-wot-binding-websocket/src/main/kotlin/websocket/WebSocketProtocolServer.kt b/kotlin-wot-binding-websocket/src/main/kotlin/websocket/WebSocketProtocolServer.kt index b5b379d..903ac68 100644 --- a/kotlin-wot-binding-websocket/src/main/kotlin/websocket/WebSocketProtocolServer.kt +++ b/kotlin-wot-binding-websocket/src/main/kotlin/websocket/WebSocketProtocolServer.kt @@ -40,13 +40,13 @@ class WebSocketProtocolServer( private val wait: Boolean = false, private val bindHost: String = "0.0.0.0", private val bindPort: Int = 8080, + private var baseUrls: List = listOf("ws://localhost:8080"), private val createServer: (host: String, port: Int, servient: Servient) -> EmbeddedServer<*, *> = ::defaultWebSocketServer ) : ProtocolServer { private val things: MutableMap = mutableMapOf() var started = false private var server: EmbeddedServer<*, *>? = null - private var actualAddresses: List = listOf("ws://$bindHost:$bindPort") companion object { private val log = LoggerFactory.getLogger(WebSocketProtocolServer::class.java) @@ -70,10 +70,10 @@ class WebSocketProtocolServer( log.info("Exposing thing '{}'", thing.id) things[thing.id] = thing - for (address in actualAddresses) { - exposeProperties(thing, address) - exposeActions(thing, address) - exposeEvents(thing, address) + for (baseUrl in baseUrls) { + exposeProperties(thing, baseUrl) + exposeActions(thing, baseUrl) + exposeEvents(thing, baseUrl) } } @@ -82,10 +82,10 @@ class WebSocketProtocolServer( things.remove(thing.id) } - internal fun exposeProperties(thing: ExposedThing, address: String) { + internal fun exposeProperties(thing: ExposedThing, baseUrl: String) { thing.properties.forEach { (name, property) -> - val href = "$address/ws" + val href = "$baseUrl/ws" // Combine all operations (read, write, observe, unobserve) into a single form val operations = mutableListOf() @@ -113,10 +113,10 @@ class WebSocketProtocolServer( } } - internal fun exposeActions(thing: ExposedThing, address: String) { + internal fun exposeActions(thing: ExposedThing, baseUrl: String) { thing.actions.forEach { (name, action) -> // Construct the href for the action - val href = "$address/ws" // WebSocket path for actions + val href = "$baseUrl/ws" // WebSocket path for actions // Create a form for invoking the action val form = Form( @@ -132,10 +132,10 @@ class WebSocketProtocolServer( } } - internal fun exposeEvents(thing: ExposedThing, address: String) { + internal fun exposeEvents(thing: ExposedThing, baseUrl: String) { thing.events.forEach { (name, event) -> // Construct the href for the event - val href = "$address/ws" // WebSocket path for events + val href = "$baseUrl/ws" // WebSocket path for events // Create a form for subscribing to the event val form = Form( diff --git a/kotlin-wot-integration-tests/src/main/resources/application.yaml b/kotlin-wot-integration-tests/src/main/resources/application.yaml index 2540014..a522148 100644 --- a/kotlin-wot-integration-tests/src/main/resources/application.yaml +++ b/kotlin-wot-integration-tests/src/main/resources/application.yaml @@ -18,12 +18,15 @@ wot: server: enabled: true host: localhost - port: 8080 + port: 8181 http: server: - enabled: false + enabled: true host: localhost port: 8080 + baseUrls: + - http://localhost:8080 + - http://not-existing-external-url:8080 mqtt: server: enabled: false diff --git a/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/HttpProperties.kt b/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/HttpProperties.kt index 5982593..92c78a7 100644 --- a/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/HttpProperties.kt +++ b/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/HttpProperties.kt @@ -3,10 +3,21 @@ package ai.ancf.lmos.wot.spring import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.validation.annotation.Validated +open class ServerProperties( + var enabled: Boolean = true, + var host: String = "0.0.0.0", + var port: Int = 8080, + var baseUrls: List +) + @ConfigurationProperties(prefix = "wot.servient.http.server", ignoreUnknownFields = true) @Validated -data class HttpServerProperties( - var enabled: Boolean = true, - var host: String = "localhost", - var port: Int = 8080 +class HttpServerProperties : ServerProperties( + baseUrls = listOf("http://localhost:8080") +) + +@ConfigurationProperties(prefix = "wot.servient.websocket.server", ignoreUnknownFields = true) +@Validated +class WebsocketProperties : ServerProperties( + baseUrls = listOf("ws://localhost:8080") ) \ No newline at end of file diff --git a/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/ServientAutoConfiguration.kt b/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/ServientAutoConfiguration.kt index fb2cc10..545d232 100644 --- a/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/ServientAutoConfiguration.kt +++ b/kotlin-wot-spring-boot-starter/src/main/kotlin/spring/ServientAutoConfiguration.kt @@ -22,7 +22,13 @@ import org.springframework.context.annotation.Configuration @AutoConfiguration -@EnableConfigurationProperties(CredentialsProperties::class, HttpServerProperties::class, MqttServerProperties::class, MqttClientProperties::class) +@EnableConfigurationProperties( + CredentialsProperties::class, + HttpServerProperties::class, + WebsocketProperties::class, + MqttServerProperties::class, + MqttClientProperties::class +) class ServientAutoConfiguration { @Bean @@ -55,8 +61,12 @@ class ServientAutoConfiguration { havingValue = "true", matchIfMissing = true // By default, enable the server ) - fun webSocketProtocolServer(httpServerProperties: HttpServerProperties): WebSocketProtocolServer { - return WebSocketProtocolServer(bindHost = httpServerProperties.host, bindPort = httpServerProperties.port) + fun webSocketProtocolServer(websocketProperties: WebsocketProperties): WebSocketProtocolServer { + return WebSocketProtocolServer( + bindHost = websocketProperties.host, + bindPort = websocketProperties.port, + baseUrls = websocketProperties.baseUrls + ) } @Bean @@ -83,7 +93,11 @@ class ServientAutoConfiguration { matchIfMissing = true // By default, enable the server ) fun httpProtocolServer(httpServerProperties: HttpServerProperties): HttpProtocolServer { - return HttpProtocolServer(bindHost = httpServerProperties.host, bindPort = httpServerProperties.port) + return HttpProtocolServer( + bindHost = httpServerProperties.host, + bindPort = httpServerProperties.port, + baseUrls = httpServerProperties.baseUrls + ) } @Bean