multiple onConnect in sessions support

This commit is contained in:
Sergey Chernov 2024-11-19 18:20:53 +07:00
parent 1032eebbbe
commit f2d8330ccc
5 changed files with 43 additions and 11 deletions

View File

@ -156,8 +156,19 @@ class KiloClient<S>(
var secretIdKey: SigningKey? = null var secretIdKey: SigningKey? = null
/** /**
* Build local command implementations (remotely callable ones), exception * Build local command implementations, those callable from the server, exception
* class handlers, etc. * 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<S>.() -> Unit) { fun local(f: KiloInterface<S>.() -> Unit) {
interfaceBuilder = f interfaceBuilder = f

View File

@ -80,7 +80,7 @@ class KiloClientConnection<S>(
kiloRemoteInterface.complete( kiloRemoteInterface.complete(
KiloRemoteInterface(deferredParams, clientInterface) KiloRemoteInterface(deferredParams, clientInterface)
) )
clientInterface.onConnectHandler?.invoke(params.scope) clientInterface.onConnectHandlers.invokeAll(params.scope)
onConnectedStateChanged?.invoke(true) onConnectedStateChanged?.invoke(true)
job.join() job.join()
@ -104,4 +104,7 @@ class KiloClientConnection<S>(
override suspend fun <A> push(cmd: Command<A, Unit>, args: A) { override suspend fun <A> push(cmd: Command<A, Unit>, args: A) {
kiloRemoteInterface.await().push(cmd, args) kiloRemoteInterface.await().push(cmd, args)
} }
} }
internal fun <S>Collection<KiloHandler<S>>.invokeAll(scope: KiloScope<S>) =
forEach { runCatching { scope.it() } }

View File

@ -1,5 +1,6 @@
package net.sergeych.kiloparsec package net.sergeych.kiloparsec
typealias KiloHandler<S> = KiloScope<S>.()->Unit
/** /**
* The local interface to provide functions, register errors for Kiloparsec users. Use it * The local interface to provide functions, register errors for Kiloparsec users. Use it
* with [KiloClient], [KiloClientConnection], [KiloServerConnection], etc. * with [KiloClient], [KiloClientConnection], [KiloServerConnection], etc.
@ -14,9 +15,16 @@ package net.sergeych.kiloparsec
*/ */
open class KiloInterface<S> : LocalInterface<KiloScope<S>>() { open class KiloInterface<S> : LocalInterface<KiloScope<S>>() {
internal var onConnectHandler: (KiloScope<S>.()->Unit) ? = null internal val onConnectHandlers = mutableListOf<KiloHandler<S>>()
fun onConnected(f: KiloScope<S>.()->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<S>.()->Unit) {
if( addFirst ) onConnectHandlers.add(0, f) else onConnectHandlers += f
}
init { init {
registerError { RemoteInterface.UnknownCommand(it) } registerError { RemoteInterface.UnknownCommand(it) }

View File

@ -75,7 +75,7 @@ class KiloServerConnection<S>(
kiloRemoteInterface.complete( kiloRemoteInterface.complete(
KiloRemoteInterface(deferredParams, clientInterface) KiloRemoteInterface(deferredParams, clientInterface)
) )
clientInterface.onConnectHandler?.invoke(p.scope) clientInterface.onConnectHandlers.invokeAll(p.scope)
} }
} }

View File

@ -26,9 +26,11 @@ class InternetTest {
val cmdSave by command<String, Unit>() val cmdSave by command<String, Unit>()
val cmdLoad by command<Unit, String>() val cmdLoad by command<Unit, String>()
val cmdDrop by command<Unit, Unit>() val cmdDrop by command<Unit, Unit>()
val cmdPing by command<String, String>()
val cmdException by command<Unit, Unit>() val cmdException by command<Unit, Unit>()
val cmdCallClient by command<String, String>()
val cli = KiloInterface<Session>().apply { val serverInterface = KiloInterface<Session>().apply {
registerError { TestException() } registerError { TestException() }
onConnected { session.data = "start" } onConnected { session.data = "start" }
on(cmdSave) { session.data = it } on(cmdSave) { session.data = it }
@ -41,18 +43,26 @@ class InternetTest {
on(cmdDrop) { on(cmdDrop) {
throw LocalInterface.BreakConnectionException() throw LocalInterface.BreakConnectionException()
} }
on(cmdCallClient) {
remote.call(cmdPing, it)
}
} }
val server = KiloServer(cli, acceptTcpDevice(port)) { val server = KiloServer(serverInterface, acceptTcpDevice(port)) {
Session("unknown") Session("unknown")
} }
data class LocalSession(val localFoo: String) data class LocalSession(val localFoo: String)
val client = KiloClient { val client = KiloClient {
addErrors(cli) addErrors(serverInterface)
session { LocalSession("unknown") } session { LocalSession("unknown") }
// TODO: add register error variant // TODO: add register error variant
connect { connectTcpDevice("localhost:$port") } connect { connectTcpDevice("localhost:$port") }
local {
on(cmdPing) {
"pong! $it"
}
}
} }
assertEquals("start", client.call(cmdLoad)) assertEquals("start", client.call(cmdLoad))
@ -68,7 +78,7 @@ class InternetTest {
// reconnect? // reconnect?
assertEquals("start", client.call(cmdLoad)) assertEquals("start", client.call(cmdLoad))
assertEquals("pong! 42", client.call(cmdCallClient, "42"))
server.close() server.close()
} }