diff --git a/.idea/misc.xml b/.idea/misc.xml index 61efd00..45281f7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt index 6e5a41e..27952d1 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloClient.kt @@ -2,6 +2,7 @@ package net.sergeych.kiloparsec import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.isActive @@ -52,10 +53,12 @@ class KiloClient( debug { "client run finished" } } catch (_: RemoteInterface.ClosedException) { debug { "remote closed" } + delay(1000) } catch (_: CancellationException) { debug { "cancelled" } } catch (t: Throwable) { exception { "unexpected exception" to t } + delay(1000) } _state.value = false if (deferredClient.isActive) diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServer.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServer.kt index 78c6080..c96b87a 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServer.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServer.kt @@ -1,22 +1,40 @@ package net.sergeych.kiloparsec +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import net.sergeych.crypto.Key +import net.sergeych.kiloparsec.adapter.InetTransportDevice +import net.sergeych.mp_logger.LogTag +import net.sergeych.mp_logger.debug +import net.sergeych.mp_logger.exception +import net.sergeych.mp_logger.info import net.sergeych.mp_tools.globalLaunch +import net.sergeych.tools.AtomicCounter +private val instances = AtomicCounter() @Suppress("unused") class KiloServer( private val clientInterface: KiloInterface, - private val connections: Flow, + private val connections: Flow, private val serverSigningKey: Key.Signing? = null, private val sessionBuilder: ()->S, - ) { + ): LogTag("KS:${instances.incrementAndGet()}") { private val job = globalLaunch { connections.collect { device -> launch { - KiloServerConnection(clientInterface,device,sessionBuilder(), serverSigningKey).run() + try { + info { "connected ${device}" } + KiloServerConnection(clientInterface, device, sessionBuilder(), serverSigningKey) + .apply { debug { "server connection is ready" }} + .run() + } + catch(_: CancellationException) { + } + catch (t: Throwable) { + exception { "unexpected while creating kiloclient" to t } + } } } } diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt index 5d5c41d..ee634a2 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/KiloServerConnection.kt @@ -89,7 +89,7 @@ class KiloServerConnection( val transport = Transport(device, l0Interface, Unit) deferredTransport.complete(transport) kiloRemoteInterface.complete(KiloRemoteInterface(deferredParams,clientInterface)) - debug { "starintg the transport"} + debug { "starting the transport"} transport.run() debug { "server transport finished" } } diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/InetTransportDevice.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/InetTransportDevice.kt index 0110fbe..66fb08a 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/InetTransportDevice.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/InetTransportDevice.kt @@ -12,4 +12,6 @@ class InetTransportDevice( val remoteAddress: NetworkAddress, val flush: suspend ()->Unit = {}, doClose: suspend ()->Unit = {} -) : ProxyDevice(inputChannel, outputChannel, doClose) \ No newline at end of file +) : ProxyDevice(inputChannel, outputChannel, doClose) { + override fun toString(): String = "@$remoteAddress" +} \ No newline at end of file diff --git a/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.kt b/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.kt index 2b9bf95..50af716 100644 --- a/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.kt +++ b/src/commonMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.kt @@ -44,7 +44,7 @@ interface DatagramConnector: AutoCloseable { expect fun NetworkAddress(host: String,port: Int): NetworkAddress -fun CharSequence.toNetworkAddress() : NetworkAddress { +fun String.toNetworkAddress() : NetworkAddress { val (host, port) = this.split(":").map { it.trim()} return NetworkAddress(host, port.toInt()) } diff --git a/src/commonMain/kotlin/net/sergeych/tools/AtomicCounter.kt b/src/commonMain/kotlin/net/sergeych/tools/AtomicCounter.kt new file mode 100644 index 0000000..a70892a --- /dev/null +++ b/src/commonMain/kotlin/net/sergeych/tools/AtomicCounter.kt @@ -0,0 +1,9 @@ +package net.sergeych.tools + +class AtomicCounter(initialValue: Long = 0) { + private val op = ProtectedOp() + var value: Long = initialValue + private set + + fun incrementAndGet(): Long = op { ++value } +} \ No newline at end of file diff --git a/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.jvm.kt b/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.jvm.kt index ac2d830..3e165f9 100644 --- a/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.jvm.kt +++ b/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/NetworkProvider.jvm.kt @@ -18,7 +18,7 @@ actual fun acceptTcpDevice(port: Int): Flow { return flow { val socket = withContext(Dispatchers.IO) { AsynchronousServerSocketChannel.open().also { - it.bind(InetSocketAddress(InetAddress.getLocalHost(), port)) + it.bind(InetSocketAddress(port)) } } while (true) { @@ -33,6 +33,8 @@ actual fun acceptTcpDevice(port: Int): Flow { } } +suspend fun connectTcpDevice(address: String) = connectTcpDevice(address.toNetworkAddress()) +suspend fun connectTcpDevice(host: String, port: Int) = connectTcpDevice(NetworkAddress(host,port)) actual suspend fun connectTcpDevice(address: NetworkAddress): InetTransportDevice { address as JvmNetworkAddress val socket = withContext(Dispatchers.IO) { diff --git a/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/UdpServer.kt b/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/UdpServer.kt index 2a3ce76..60f5b07 100644 --- a/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/UdpServer.kt +++ b/src/jvmMain/kotlin/net/sergeych/kiloparsec/adapter/UdpServer.kt @@ -13,7 +13,7 @@ import java.util.concurrent.atomic.AtomicInteger private val counter = AtomicInteger(0) class JvmNetworkAddress(val inetAddress: InetAddress, override val port: Int) : NetworkAddress { - override val host: String by lazy { inetAddress.hostName } + override val host: String by lazy { inetAddress.canonicalHostName } override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is JvmNetworkAddress) return false @@ -32,6 +32,7 @@ class JvmNetworkAddress(val inetAddress: InetAddress, override val port: Int) : return result } + override fun toString(): String = "$host:$port" } class UdpDatagram(override val message: UByteArray, val inetAddress: InetAddress, val port: Int) : Datagram { diff --git a/src/jvmTest/kotlin/net/sergeych/kiloparsec/ClientTest.kt b/src/jvmTest/kotlin/net/sergeych/kiloparsec/ClientTest.kt index eeb5866..85a846c 100644 --- a/src/jvmTest/kotlin/net/sergeych/kiloparsec/ClientTest.kt +++ b/src/jvmTest/kotlin/net/sergeych/kiloparsec/ClientTest.kt @@ -1,10 +1,51 @@ package net.sergeych.kiloparsec +import kotlinx.coroutines.test.runTest +import net.sergeych.crypto.initCrypto +import net.sergeych.kiloparsec.adapter.acceptTcpDevice +import net.sergeych.kiloparsec.adapter.connectTcpDevice +import net.sergeych.mp_logger.Log +import java.net.InetAddress import kotlin.test.Test +import kotlin.test.assertEquals class ClientTest { + @Test - fun testClient() { - // Todo + fun testAddresses() { + println(InetAddress.getLocalHost()) + println(InetAddress.getByName("localhost")) + println(InetAddress.getByName("127.0.0.1")) + println(InetAddress.getByName("mail.ru")) + } + @Test + fun testClient() = runTest { + initCrypto() + Log.connectConsole(Log.Level.DEBUG) + data class Session( + var data: String + ) + + val cmdSave by command() + val cmdLoad by command() + + val cli = KiloInterface().apply { + on(cmdSave) { session.data = it } + on(cmdLoad) { + println("load!") + session.data } + } + val server = KiloServer(cli, acceptTcpDevice(17101)) { Session("unknown")} + val client = KiloClient { + connect { connectTcpDevice("localhost:17101") } + } + println(client.call(cmdLoad)) + + assertEquals("unknown", client.call(cmdLoad)) + client.call(cmdSave, "foobar") + assertEquals("foobar", client.call(cmdLoad)) + server.close() +// client.close() + // Todo } } \ No newline at end of file