Skip to content

Commit

Permalink
feat: improve LoxoneEndpoint constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
jimirocks committed Feb 26, 2024
1 parent 005f5c8 commit 28178eb
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 12 deletions.
2 changes: 1 addition & 1 deletion examples/java/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repositories {
}

dependencies {
implementation("cz.smarteon.loxone:loxone-client-kotlin:0.1.0-SNAPSHOT")
implementation("cz.smarteon.loxone:loxone-client-kotlin:0.1.1-SNAPSHOT")

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1")
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class LoxoneClientExample {
public static void main(String[] args) {
System.out.println("Test");

final var endpoint = new LoxoneEndpoint(args[0], 443);
final var endpoint = LoxoneEndpoint.fromUrl(args[0])
final LoxoneClient loxoneClient = new HttpLoxoneClient(
endpoint,
new LoxoneTokenAuthenticator(
Expand Down
2 changes: 1 addition & 1 deletion examples/kotlin/src/main/kotlin/LoxoneClientExample.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import cz.smarteon.loxone.message.ApiInfo


suspend fun main(args: Array<String>) {
val endpoint = LoxoneEndpoint(args[0], useSsl = true)
val endpoint = LoxoneEndpoint.fromUrl(args[0])
val loxoneClient: LoxoneClient = HttpLoxoneClient(
endpoint,
LoxoneTokenAuthenticator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import cz.smarteon.loxone.LoxoneEndpoint
import cz.smarteon.loxone.LoxoneProfile
import cz.smarteon.loxone.LoxoneTokenAuthenticator
import cz.smarteon.loxone.callForMsg
import cz.smarteon.loxone.ktor.HttpLoxoneClient
import cz.smarteon.loxone.ktor.WebsocketLoxoneClient
import cz.smarteon.loxone.message.ApiInfo


suspend fun main(args: Array<String>) {
val endpoint = LoxoneEndpoint(args[0], useSsl = false)
val endpoint = LoxoneEndpoint.FromUrl(args[0])
val loxoneClient: LoxoneClient = WebsocketLoxoneClient(
endpoint,
LoxoneTokenAuthenticator(
Expand Down
73 changes: 73 additions & 0 deletions src/commonMain/kotlin/LoxoneEndpoint.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package cz.smarteon.loxone

import io.ktor.http.*
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic

/**
* Loxone connection endpoint representation.
*
* @param host Loxone host name or IP address, without protocol prefix, port or path.
* @param port Loxone port, default is 443 (HTTPS).
* @param useSsl Whether to use SSL, default is true.
* @param path Loxone path, url encoded, default is empty string.
*/
data class LoxoneEndpoint @JvmOverloads constructor(
val host: String,
val port: Int = HTTPS_PORT,
val useSsl: Boolean = true,
val path: String = ""
) {

init {
require(host.isNotBlank()) { "Host must not be blank" }
require(!host.contains(":")) { "Host must not contain port or protocol" }
}
companion object {
private const val HTTP_PORT = 80
private const val HTTPS_PORT = 443

/**
* Creates Loxone endpoint by parsing URL.
* @param url Loxone URL.
*/
@JvmStatic
fun fromUrl(url: String): LoxoneEndpoint {
val parsed = URLBuilder().takeFrom(url)
val port = when {
parsed.port > 0 -> parsed.port
parsed.protocol.isSecure() -> HTTPS_PORT
else -> HTTP_PORT
}
println(parsed)
println(parsed.encodedPath)
return LoxoneEndpoint(parsed.host, port, parsed.protocol.isSecure(), parsed.encodedPath)
}

/**
* Creates Loxone endpoint for local connection.
*
* @param address Loxone IP address.
* @param port Loxone port, default is 80 (HTTP).
* @param path Loxone path, url encoded, default is empty string.
*/
@JvmStatic @JvmOverloads
fun local(address: String, port: Int = HTTP_PORT, path: String = ""): LoxoneEndpoint {
require(hostIsIp(address)) { "Local address must be IP" }
return LoxoneEndpoint(address, port, false, path)
}

/**
* Creates Loxone endpoint for public domain connection.
*
* @param domain Loxone host domain.
* @param port Loxone port, default is 443 (HTTPS).
* @param path Loxone path, url encoded, default is empty string.
*/
@JvmStatic @JvmOverloads
fun public(domain: String, port: Int = HTTPS_PORT, path: String = ""): LoxoneEndpoint {
require(!hostIsIp(domain)) { "Public domain must not be IP" }
return LoxoneEndpoint(domain, port, true, path)
}
}
}
7 changes: 0 additions & 7 deletions src/commonMain/kotlin/LoxoneProfile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ package cz.smarteon.loxone

import kotlin.jvm.JvmOverloads

data class LoxoneEndpoint @JvmOverloads constructor(
val host: String,
val port: Int = 80,
val useSsl: Boolean = true,
val path: String = ""
)

data class LoxoneCredentials @JvmOverloads constructor(
val username: String,
val password: String,
Expand Down
78 changes: 78 additions & 0 deletions src/commonTest/kotlin/LoxoneEndpointTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package cz.smarteon.loxone

import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.WordSpec
import io.kotest.datatest.withData
import io.kotest.matchers.shouldBe

class LoxoneEndpointTest : WordSpec({

"Loxone endpoint constructed" When {

"with default values" should {
LoxoneEndpoint("somehost").apply {
"have host" { host shouldBe "somehost"}
"have port" { port shouldBe 443 }
"have useSsl" { useSsl shouldBe true }
"have path" {path shouldBe "" }
}
}

withData(
nameFn = { (case, _) -> "with $case host" },
"empty" to "",
"contains port" to "host:123",
"contains protocol" to "http://host"
) { (_, host) ->
shouldThrow<IllegalArgumentException> {
LoxoneEndpoint(host)
}
}
}

"FromUrl endpoint constructed" When {
withData(
nameFn = { (url, _) -> url },
"http://some:7780/testPath" to LoxoneEndpoint("some", 7780, false, "/testPath"),
"http://some/testPath" to LoxoneEndpoint("some", 80, false, "/testPath"),
"https://some.smarteon.cz:7743/testPath" to LoxoneEndpoint("some.smarteon.cz", 7743, true, "/testPath"),
"https://some.smarteon.cz/testPath" to LoxoneEndpoint("some.smarteon.cz", 443, true, "/testPath")
) { (url, expected) ->
LoxoneEndpoint.fromUrl(url) shouldBe expected
}
}

"Local endpoint constructed" When {
"with default values" should {
LoxoneEndpoint.local("192.168.9.77").apply {
"have host" { host shouldBe "192.168.9.77" }
"have port" { port shouldBe 80 }
"have useSsl" { useSsl shouldBe false }
"have path" { path shouldBe "" }
}
}

"with non-IP address" should {
shouldThrow<IllegalArgumentException> {
LoxoneEndpoint.local("somehost")
}
}
}

"Public domain endpoint constructed" When {
"with default values" should {
LoxoneEndpoint.public("test.smarteon.cz").apply {
"have host" { host shouldBe "test.smarteon.cz" }
"have port" { port shouldBe 443 }
"have useSsl" { useSsl shouldBe true }
"have path" { path shouldBe "" }
}
}

"with non-IP address" should {
shouldThrow<IllegalArgumentException> {
LoxoneEndpoint.public("192.168.9.77")
}
}
}
})

0 comments on commit 28178eb

Please sign in to comment.