diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt index f07ca4b..77ce6a9 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt @@ -156,8 +156,19 @@ class KiloClient( var secretIdKey: SigningKey? = null /** - * Build local command implementations (remotely callable ones), exception - * class handlers, etc. + * Build local command implementations, those callable from the server, exception + * class handlers, and anything else [KiloInterface] allows. Usage sample: + * + * ```kotlin + * val client = KiloClient { + * connect { connectTcpDevice("localhost:$port") } + * local { + * on(cmdPing) { + * "pong! $it" + * } + * } + * } + * ``` */ fun local(f: KiloInterface.() -> Unit) { interfaceBuilder = f diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClientConnection.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClientConnection.kt index 476ac28..5de824d 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClientConnection.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClientConnection.kt @@ -80,7 +80,7 @@ class KiloClientConnection( kiloRemoteInterface.complete( KiloRemoteInterface(deferredParams, clientInterface) ) - clientInterface.onConnectHandler?.invoke(params.scope) + clientInterface.onConnectHandlers.invokeAll(params.scope) onConnectedStateChanged?.invoke(true) job.join() @@ -104,4 +104,7 @@ class KiloClientConnection( override suspend fun push(cmd: Command, args: A) { kiloRemoteInterface.await().push(cmd, args) } -} \ No newline at end of file +} + +internal fun Collection>.invokeAll(scope: KiloScope) = + forEach { runCatching { scope.it() } } \ No newline at end of file diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloInterface.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloInterface.kt index 89ff162..ce62928 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloInterface.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloInterface.kt @@ -1,5 +1,6 @@ package net.sergeych.kiloparsec +typealias KiloHandler = KiloScope.()->Unit /** * The local interface to provide functions, register errors for Kiloparsec users. Use it * with [KiloClient], [KiloClientConnection], [KiloServerConnection], etc. @@ -14,9 +15,16 @@ package net.sergeych.kiloparsec */ open class KiloInterface : LocalInterface>() { - internal var onConnectHandler: (KiloScope.()->Unit) ? = null + internal val onConnectHandlers = mutableListOf>() - fun onConnected(f: KiloScope.()->Unit) { onConnectHandler = f } + /** + * Registers handler [f] for [onConnected] event, to the head or the end of handler list. + * + * @param addFirst if true, [f] will be added to the beginning of the list of handlers + */ + fun onConnected(addFirst: Boolean = false, f: KiloScope.()->Unit) { + if( addFirst ) onConnectHandlers.add(0, f) else onConnectHandlers += f + } init { registerError { RemoteInterface.UnknownCommand(it) } diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt index 5944dde..92596e3 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt @@ -75,7 +75,7 @@ class KiloServerConnection( kiloRemoteInterface.complete( KiloRemoteInterface(deferredParams, clientInterface) ) - clientInterface.onConnectHandler?.invoke(p.scope) + clientInterface.onConnectHandlers.invokeAll(p.scope) } } diff --git a/src/ktorSocketTest/kotlin/net/sergeych/kiloparsec/adapter/InternetTest.kt b/src/ktorSocketTest/kotlin/net/sergeych/kiloparsec/adapter/InternetTest.kt index a127a56..b651a15 100644 --- a/src/ktorSocketTest/kotlin/net/sergeych/kiloparsec/adapter/InternetTest.kt +++ b/src/ktorSocketTest/kotlin/net/sergeych/kiloparsec/adapter/InternetTest.kt @@ -26,9 +26,11 @@ class InternetTest { val cmdSave by command() val cmdLoad by command() val cmdDrop by command() + val cmdPing by command() val cmdException by command() + val cmdCallClient by command() - val cli = KiloInterface().apply { + val serverInterface = KiloInterface().apply { registerError { TestException() } onConnected { session.data = "start" } on(cmdSave) { session.data = it } @@ -41,18 +43,26 @@ class InternetTest { on(cmdDrop) { throw LocalInterface.BreakConnectionException() } + on(cmdCallClient) { + remote.call(cmdPing, it) + } } - val server = KiloServer(cli, acceptTcpDevice(port)) { + val server = KiloServer(serverInterface, acceptTcpDevice(port)) { Session("unknown") } data class LocalSession(val localFoo: String) val client = KiloClient { - addErrors(cli) + addErrors(serverInterface) session { LocalSession("unknown") } // TODO: add register error variant connect { connectTcpDevice("localhost:$port") } + local { + on(cmdPing) { + "pong! $it" + } + } } assertEquals("start", client.call(cmdLoad)) @@ -68,7 +78,7 @@ class InternetTest { // reconnect? assertEquals("start", client.call(cmdLoad)) - + assertEquals("pong! 42", client.call(cmdCallClient, "42")) server.close() }