docs
This commit is contained in:
parent
439e229294
commit
8a21a836e5
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,8 +23,7 @@ out/
|
|||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
.springBeans
|
.springBeans
|
||||||
.sts4-cache
|
.sts4-caches
|
||||||
bin/
|
|
||||||
!**/src/main/**/bin/
|
!**/src/main/**/bin/
|
||||||
!**/src/test/**/bin/
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
|
@ -146,6 +146,11 @@ val ns: NettyApplicationEngine = embeddedServer(Netty, port = 8080, host = "0.0.
|
|||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
## See also:
|
||||||
|
|
||||||
|
- [Source documentation](https://code.sergeych.net/docs/kiloparsec/)
|
||||||
|
- [Project's WIKI](https://gitea.sergeych.net/sergeych/kiloparsec/wiki)
|
||||||
|
|
||||||
# Details
|
# Details
|
||||||
|
|
||||||
It is not compatible with parsec family and no more based on an Universa crypto library. To better fit
|
It is not compatible with parsec family and no more based on an Universa crypto library. To better fit
|
||||||
|
@ -2,6 +2,7 @@ plugins {
|
|||||||
kotlin("multiplatform") version "2.0.0"
|
kotlin("multiplatform") version "2.0.0"
|
||||||
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0"
|
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0"
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
|
id("org.jetbrains.dokka") version "1.9.20"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
@ -135,3 +136,13 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.dokkaHtml.configure {
|
||||||
|
outputDirectory.set(buildDir.resolve("dokka"))
|
||||||
|
dokkaSourceSets {
|
||||||
|
configureEach {
|
||||||
|
// includes.from("docs/bipack.md")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,91 @@ import net.sergeych.mp_tools.globalLaunch
|
|||||||
import net.sergeych.tools.AtomicCounter
|
import net.sergeych.tools.AtomicCounter
|
||||||
|
|
||||||
private val instances = AtomicCounter()
|
private val instances = AtomicCounter()
|
||||||
@Suppress("unused")
|
|
||||||
|
/**
|
||||||
|
* The Kiloparsec server.
|
||||||
|
* Server accepts incoming connections and serves them using the same [clientInterface].
|
||||||
|
*
|
||||||
|
* ## Incoming connections
|
||||||
|
*
|
||||||
|
* Server collecting incoming connections provided by [connections] `Flow`. For each incoming connection
|
||||||
|
* the Kiloparsec handshake is performed, then the session object is created, see below, and connection is
|
||||||
|
* served with [clientInterface] until closed.
|
||||||
|
*
|
||||||
|
* ## Session param [S]
|
||||||
|
*
|
||||||
|
* After the successful handshake server creates new session for each connection calling the [sessionBuilder].
|
||||||
|
* Then it creates a [KiloScope] so [KiloScope.session] holds this connection-specific instance. Then
|
||||||
|
* [KiloInterface.onConnected] is called with this scope. Session can be used to hold connection state. Session
|
||||||
|
* objects are not persistent, but could be initialized in [KiloInterface.onConnected] where the remote side
|
||||||
|
* [KiloScope.remoteIdentity] is already verified and set.
|
||||||
|
*
|
||||||
|
* ## Usage:
|
||||||
|
*
|
||||||
|
* Create a shared library between you server and clients, to specify the interface (otherwise you can
|
||||||
|
* share sources).
|
||||||
|
*
|
||||||
|
* Suppose we have session with a state:
|
||||||
|
* ```kotlin
|
||||||
|
* data class Session(
|
||||||
|
* var data: String,
|
||||||
|
* )
|
||||||
|
*```
|
||||||
|
*
|
||||||
|
* And some commands to access and change it, in the shared library too:
|
||||||
|
*
|
||||||
|
* ```kotlin
|
||||||
|
* val cmdSave by command<String, Unit>()
|
||||||
|
* val cmdLoad by command<Unit, String>()
|
||||||
|
* val cmdDrop by command<Unit, Unit>()
|
||||||
|
* val cmdException by command<Unit, Unit>()
|
||||||
|
* ```
|
||||||
|
* Then the server code (TCP/IP variant) could look like:
|
||||||
|
*
|
||||||
|
* ```kotlin
|
||||||
|
* // The server implementation (could be shared between server instances connected
|
||||||
|
* // to different protocol adapters):
|
||||||
|
*
|
||||||
|
* val cli = KiloInterface<Session>().apply {
|
||||||
|
* // Suppose we want to throw this exception at the caller site, so we need to register it:
|
||||||
|
* registerError { SomeException() }
|
||||||
|
*
|
||||||
|
* // Session initialization. If you need a sessino to depend initially on the client's identity.
|
||||||
|
* // you can do it here:
|
||||||
|
* onConnected {
|
||||||
|
* // check the remoteIdentity
|
||||||
|
* session.data = if( remoteIdentity == somePublicVerifyingKey )
|
||||||
|
* "known"
|
||||||
|
* else
|
||||||
|
* "unknown"
|
||||||
|
* }
|
||||||
|
* on(cmdSave) { session.data = it }
|
||||||
|
* on(cmdLoad) {
|
||||||
|
* session.data
|
||||||
|
* }
|
||||||
|
* on(cmdException) {
|
||||||
|
* throw TestException()
|
||||||
|
* }
|
||||||
|
* on(cmdDrop) {
|
||||||
|
* throw LocalInterface.BreakConnectionException()
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Create the server instance that accepts incoming TCP/IP connections on all local interfaces using the
|
||||||
|
* // specified port:
|
||||||
|
*
|
||||||
|
* val server = KiloServer(cli, acceptTcpDevice(port)) {
|
||||||
|
* // This creates a new session
|
||||||
|
* Session("unknown")
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* @param S the type of the server session object, returned by [sessionBuilder]. See above
|
||||||
|
* @param clientInterface the interface available for remote calls
|
||||||
|
* @param connections flow of incoming connections. Server stops when the flow is fully collected (normally
|
||||||
|
* it shouldn't)
|
||||||
|
* @param serverSecretKey the [SigningKey] used to identify this server during Kiloparsec handshake.
|
||||||
|
* @param sessionBuilder callback that creates session objects for successful incoming connections
|
||||||
|
*/
|
||||||
class KiloServer<S>(
|
class KiloServer<S>(
|
||||||
private val clientInterface: KiloInterface<S>,
|
private val clientInterface: KiloInterface<S>,
|
||||||
private val connections: Flow<InetTransportDevice>,
|
private val connections: Flow<InetTransportDevice>,
|
||||||
@ -29,20 +113,28 @@ class KiloServer<S>(
|
|||||||
KiloServerConnection(clientInterface, device, sessionBuilder(), serverSecretKey)
|
KiloServerConnection(clientInterface, device, sessionBuilder(), serverSecretKey)
|
||||||
.apply { debug { "server connection is ready" } }
|
.apply { debug { "server connection is ready" } }
|
||||||
.run()
|
.run()
|
||||||
}
|
} catch (_: CancellationException) {
|
||||||
catch(_: CancellationException) {
|
} catch (cce: LocalInterface.BreakConnectionException) {
|
||||||
}
|
|
||||||
catch(cce: LocalInterface.BreakConnectionException) {
|
|
||||||
info { "Closed exception caught, closing (${cce.flushSendQueue}" }
|
info { "Closed exception caught, closing (${cce.flushSendQueue}" }
|
||||||
}
|
} catch (t: Throwable) {
|
||||||
catch (t: Throwable) {
|
|
||||||
exception { "unexpected while creating kiloclient" to t }
|
exception { "unexpected while creating kiloclient" to t }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the server and cancel all pending sessions. Unlike finishing the flow passed
|
||||||
|
* for [KiloServer.connections], it will cancel all currently active sessions.
|
||||||
|
*/
|
||||||
fun close() {
|
fun close() {
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server is closed either if [close] was called or all [KiloServer.connections] were collected and flow was
|
||||||
|
* closed.
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
val isClosed: Boolean get() = job.isCompleted
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ class TcpTest {
|
|||||||
initCrypto()
|
initCrypto()
|
||||||
// Log.connectConsole(Log.Level.DEBUG)
|
// Log.connectConsole(Log.Level.DEBUG)
|
||||||
data class Session(
|
data class Session(
|
||||||
var data: String
|
var data: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
val port = 27170 + Random.nextInt(1, 200)
|
val port = 27170 + Random.nextInt(1, 200)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user