removed unused code. fixed storage delegate, added adapter builder onCancel handler registration
This commit is contained in:
parent
1fdbcf7913
commit
8175bacfb8
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
Current stable version is __0.4.1-SNAPSHOT__. The full-dpulex RPC over websock is ok, the security level is still disabled until the protocol part will be sabilized.
|
Current stable version is __0.4.2-SNAPSHOT__. The full-dpulex RPC over websock is ok, the security level is still disabled until the protocol part will be sabilized.
|
||||||
|
|
||||||
This is a connection-agnostic, kotlin multiplaftorm library providing full-duplex RPC type binary protocol, effective to work with binary data, such as encrypted data, keys, multimedia, etc. Default implementation uses websockets transport (binary frames) available on all supported platofrms (currently, JS and JVM).
|
This is a connection-agnostic, kotlin multiplaftorm library providing full-duplex RPC type binary protocol, effective to work with binary data, such as encrypted data, keys, multimedia, etc. Default implementation uses websockets transport (binary frames) available on all supported platofrms (currently, JS and JVM).
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ repsitories {
|
|||||||
|
|
||||||
//...
|
//...
|
||||||
dependencies {
|
dependencies {
|
||||||
api("net.sergeych:parsec3:0.3.3")
|
api("net.sergeych:parsec3:0.4.2-SNAPSHOT")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
version = "0.4.1-SNAPSHOT"
|
version = "0.4.2-SNAPSHOT"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@ -22,6 +22,7 @@ kotlin {
|
|||||||
jvmToolchain {
|
jvmToolchain {
|
||||||
languageVersion.set(JavaLanguageVersion.of("8"))
|
languageVersion.set(JavaLanguageVersion.of("8"))
|
||||||
}
|
}
|
||||||
|
|
||||||
jvm {
|
jvm {
|
||||||
compilations.all {
|
compilations.all {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
@ -39,6 +40,10 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
all {
|
||||||
|
languageSettings.optIn("kotlinx.serialization.ExperimentalSerializationApi")
|
||||||
|
languageSettings.optIn("kotlinx.coroutines.ExperimentalCoroutinesApi")
|
||||||
|
}
|
||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3")
|
||||||
@ -83,9 +88,11 @@ kotlin {
|
|||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://maven.universablockchain.com/")
|
url = uri("https://maven.universablockchain.com/")
|
||||||
|
val mavenUser: String by project
|
||||||
|
val mavenPassword: String by project
|
||||||
credentials {
|
credentials {
|
||||||
username = System.getenv("maven_user")
|
username = mavenUser // System.getenv("maven_user")
|
||||||
password = System.getenv("maven_password")
|
password = mavenPassword // System.getenv("maven_password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ class AdapterBuilder<S : WithAdapter, H : CommandHost<S>>(
|
|||||||
f: AdapterBuilder<S, H>.() -> Unit,
|
f: AdapterBuilder<S, H>.() -> Unit,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
internal var sessionProducer: (suspend () -> S) = { WithAdapter() as S}
|
internal var sessionProducer: (suspend () -> S) = { WithAdapter() as S }
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +31,17 @@ class AdapterBuilder<S : WithAdapter, H : CommandHost<S>>(
|
|||||||
api.on(ca, block)
|
api.on(ca, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val onCancelHandlers = mutableListOf<suspend () -> Unit>()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a onCancel handler that will be called upon adapter cancelling. Several adapters
|
||||||
|
* could be registered and will be called in order of registration
|
||||||
|
*/
|
||||||
|
fun onCancel(f: suspend () -> Unit) {
|
||||||
|
onCancelHandlers += f
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
inline fun <reified T : Throwable> addError(code: String, noinline handler: (String?) -> T) {
|
inline fun <reified T : Throwable> addError(code: String, noinline handler: (String?) -> T) {
|
||||||
exceptionRegistry.register(code, handler)
|
exceptionRegistry.register(code, handler)
|
||||||
@ -41,13 +52,23 @@ class AdapterBuilder<S : WithAdapter, H : CommandHost<S>>(
|
|||||||
exceptionRegistry.putAll(otherRegistry)
|
exceptionRegistry.putAll(otherRegistry)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun createWith(input: Flow<ByteArray>, f: suspend (ByteArray)->Unit ): Adapter<S> {
|
suspend fun createWith(input: Flow<ByteArray>, f: suspend (ByteArray) -> Unit): Adapter<S> {
|
||||||
val s = sessionProducer()
|
val s = sessionProducer()
|
||||||
return Adapter<S>(
|
return Adapter<S>(
|
||||||
s, api, exceptionRegistry) { f(it) }
|
s, api, exceptionRegistry
|
||||||
.also { a->
|
) { f(it) }
|
||||||
|
.also { a ->
|
||||||
s._adapter = a
|
s._adapter = a
|
||||||
globalLaunch { input.collect { a.receiveFrame(it)} }
|
if (onCancelHandlers.isNotEmpty()) {
|
||||||
|
a.onCancel = {
|
||||||
|
for (h in onCancelHandlers) try {
|
||||||
|
h()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalLaunch { input.collect { a.receiveFrame(it) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class KVStorageDelegate<T>(
|
|||||||
private var cachedValue: T = defaultValue
|
private var cachedValue: T = defaultValue
|
||||||
private var cacheReady = false
|
private var cacheReady = false
|
||||||
|
|
||||||
operator fun getValue(thisRef: Nothing?, property: KProperty<*>): T {
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
if (cacheReady) return cachedValue
|
if (cacheReady) return cachedValue
|
||||||
val data = storage.get(name(property))
|
val data = storage.get(name(property))
|
||||||
if (data == null)
|
if (data == null)
|
||||||
@ -62,7 +62,7 @@ class KVStorageDelegate<T>(
|
|||||||
return cachedValue
|
return cachedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun setValue(thisRef: Nothing?, property: KProperty<*>, value: T) {
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
// if (!cacheReady || value != cachedValue) {
|
// if (!cacheReady || value != cachedValue) {
|
||||||
cachedValue = value
|
cachedValue = value
|
||||||
cacheReady = true
|
cacheReady = true
|
||||||
@ -83,6 +83,7 @@ class MemoryKVStorage(copyFrom: KVStorage? = null) : KVStorage {
|
|||||||
// is used while underlying is null:
|
// is used while underlying is null:
|
||||||
private val data = mutableMapOf<String, ByteArray>()
|
private val data = mutableMapOf<String, ByteArray>()
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
fun connectToStorage(other: KVStorage) {
|
fun connectToStorage(other: KVStorage) {
|
||||||
other.addAll(this)
|
other.addAll(this)
|
||||||
underlying = other
|
underlying = other
|
||||||
@ -110,10 +111,10 @@ class MemoryKVStorage(copyFrom: KVStorage? = null) : KVStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val keys: Collection<String>
|
override val keys: Collection<String>
|
||||||
get() = underlying?.let { it.keys } ?: data.keys
|
get() = underlying?.keys ?: data.keys
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
underlying?.let { it.clear() } ?: data.clear()
|
underlying?.clear() ?: data.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.sergeych.parsec3
|
package net.sergeych.parsec3
|
||||||
|
|
||||||
/**
|
///**
|
||||||
* Parsec3 secure adapter.
|
// * Parsec3 secure adapter.
|
||||||
* @param transport a parsec3 transport to establish connection with, for example [Parsec3WSClient].
|
// * @param transport a parsec3 transport to establish connection with, for example [Parsec3WSClient].
|
||||||
*/
|
// */
|
||||||
class Parsec3SecureClient<S : WithAdapter>(transport: Parsec3Transport<WithAdapter>)
|
//class Parsec3SecureClient<S : WithAdapter>(transport: Parsec3Transport<WithAdapter>)
|
@ -8,6 +8,7 @@ import kotlinx.coroutines.test.runTest
|
|||||||
import net.sergeych.parsec3.*
|
import net.sergeych.parsec3.*
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
internal class AdapterTest {
|
internal class AdapterTest {
|
||||||
|
|
||||||
@ -74,6 +75,8 @@ internal class AdapterTest {
|
|||||||
it.register("foo_x") { IllegalArgumentException(it) }
|
it.register("foo_x") { IllegalArgumentException(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var b1Cancelled = false
|
||||||
|
var b2Cancelled = false
|
||||||
val b1 = AdapterBuilder(ApiS1, er) {
|
val b1 = AdapterBuilder(ApiS1, er) {
|
||||||
newSession { TestSession("42") }
|
newSession { TestSession("42") }
|
||||||
on(api.foo) {
|
on(api.foo) {
|
||||||
@ -85,6 +88,9 @@ internal class AdapterTest {
|
|||||||
on(ApiS1.ex2) {
|
on(ApiS1.ex2) {
|
||||||
throw IllegalArgumentException()
|
throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
|
onCancel {
|
||||||
|
b1Cancelled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val b2 = AdapterBuilder(ApiS2(), er) {
|
val b2 = AdapterBuilder(ApiS2(), er) {
|
||||||
on(api.bar) {
|
on(api.bar) {
|
||||||
@ -100,6 +106,7 @@ internal class AdapterTest {
|
|||||||
throw t
|
throw t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onCancel { b2Cancelled = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
val a1 = b1.createWith(ch21.receiveAsFlow()) {
|
val a1 = b1.createWith(ch21.receiveAsFlow()) {
|
||||||
@ -122,6 +129,9 @@ internal class AdapterTest {
|
|||||||
ch21.cancel()
|
ch21.cancel()
|
||||||
a1.cancel()
|
a1.cancel()
|
||||||
a2.cancel()
|
a2.cancel()
|
||||||
|
|
||||||
|
assertTrue { b1Cancelled }
|
||||||
|
assertTrue { b2Cancelled }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,12 +1,18 @@
|
|||||||
package parsec3
|
package parsec3
|
||||||
|
|
||||||
import net.sergeych.mptools.toDump
|
import net.sergeych.mptools.toDump
|
||||||
|
import net.sergeych.parsec3.KVStorage
|
||||||
import net.sergeych.parsec3.MemoryKVStorage
|
import net.sergeych.parsec3.MemoryKVStorage
|
||||||
import net.sergeych.parsec3.stored
|
import net.sergeych.parsec3.stored
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
class TextSt(kvs: KVStorage) {
|
||||||
|
var x: String? by kvs.stored(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
internal class MemoryKVStorageTest {
|
internal class MemoryKVStorageTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -18,12 +24,20 @@ internal class MemoryKVStorageTest {
|
|||||||
s["foo"] = byteArrayOf(1,2,3)
|
s["foo"] = byteArrayOf(1,2,3)
|
||||||
|
|
||||||
var bar: String? by s.stored(null)
|
var bar: String? by s.stored(null)
|
||||||
|
val bal: String? by s.stored(null)
|
||||||
assertNull(bar)
|
assertNull(bar)
|
||||||
bar = "foo"
|
bar = "foo"
|
||||||
println(s.get("bar")?.toDump())
|
println(s.get("bar")?.toDump())
|
||||||
assertEquals("foo", bar)
|
assertEquals("foo", bar)
|
||||||
var foo: String by s.stored("", "bar")
|
val foo: String by s.stored("", "bar")
|
||||||
assertEquals("foo", foo)
|
assertEquals("foo", foo)
|
||||||
|
|
||||||
|
val t1 = TextSt(s)
|
||||||
|
assertNull(t1.x)
|
||||||
|
t1.x = "bar"
|
||||||
|
assertEquals("bar",t1.x)
|
||||||
|
val t2 = TextSt(s)
|
||||||
|
assertEquals("bar",t2.x)
|
||||||
//
|
//
|
||||||
// var i: Int? by s(defaultValue = 17)
|
// var i: Int? by s(defaultValue = 17)
|
||||||
// i = 19
|
// i = 19
|
||||||
|
@ -6,10 +6,7 @@ import io.ktor.server.websocket.*
|
|||||||
import io.ktor.websocket.*
|
import io.ktor.websocket.*
|
||||||
import net.sergeych.mp_logger.LogTag
|
import net.sergeych.mp_logger.LogTag
|
||||||
import net.sergeych.mp_logger.warning
|
import net.sergeych.mp_logger.warning
|
||||||
import net.sergeych.unikrypto.DiffieHellman
|
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a ktor server initialization module capable to perform p3 transport layer (not secure).
|
* Creates a ktor server initialization module capable to perform p3 transport layer (not secure).
|
||||||
@ -52,25 +49,23 @@ fun <S: WithAdapter, H : CommandHost<S>>Application.parsec3TransportServer(
|
|||||||
}
|
}
|
||||||
adapter.close()
|
adapter.close()
|
||||||
}
|
}
|
||||||
var totalConnections = AtomicLong(0)
|
|
||||||
var activeConnections = AtomicInteger(0)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <S: WithAdapter, H : CommandHost<S>>Application.parsec3SecureServer(
|
//fun <S: WithAdapter, H : CommandHost<S>>Application.parsec3SecureServer(
|
||||||
api: H,
|
// api: H,
|
||||||
exceptionsRegistry: ExceptionsRegistry = ExceptionsRegistry(),
|
// exceptionsRegistry: ExceptionsRegistry = ExceptionsRegistry(),
|
||||||
path: String = "/api/p3",
|
// path: String = "/api/p3",
|
||||||
f: AdapterBuilder<S, H>.() -> Unit,
|
// f: AdapterBuilder<S, H>.() -> Unit,
|
||||||
) {
|
//) {
|
||||||
val log = LogTag("P3WSS")
|
// val log = LogTag("P3WSS")
|
||||||
// parsec3TransportServer(api, ex)
|
//// parsec3TransportServer(api, ex)
|
||||||
// install(WebSockets) {
|
//// install(WebSockets) {
|
||||||
// pingPeriod = Duration.ofSeconds(45)
|
//// pingPeriod = Duration.ofSeconds(45)
|
||||||
// timeout = Duration.ofSeconds(15)
|
//// timeout = Duration.ofSeconds(15)
|
||||||
// maxFrameSize = Long.MAX_VALUE
|
//// maxFrameSize = Long.MAX_VALUE
|
||||||
// masking = false
|
//// masking = false
|
||||||
// }
|
//// }
|
||||||
val dh = DiffieHellman()
|
// val dh = DiffieHellman()
|
||||||
}
|
//}
|
||||||
|
@ -31,7 +31,7 @@ internal class WsServerKtTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testWsServer() {
|
fun testWsServer() {
|
||||||
|
|
||||||
embeddedServer(Netty, port = 8081) {
|
embeddedServer(Netty, port = 8089) {
|
||||||
parsec3TransportServer(
|
parsec3TransportServer(
|
||||||
TestApiServer,
|
TestApiServer,
|
||||||
) {
|
) {
|
||||||
@ -42,7 +42,7 @@ internal class WsServerKtTest {
|
|||||||
}
|
}
|
||||||
}.start(wait = false)
|
}.start(wait = false)
|
||||||
|
|
||||||
val client = Parsec3WSClient("ws://localhost:8081/api/p3", TestApiClient) {
|
val client = Parsec3WSClient("ws://localhost:8089/api/p3", TestApiClient) {
|
||||||
on(api.bar) {
|
on(api.bar) {
|
||||||
"bar:$it"
|
"bar:$it"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user