Compare commits
2 Commits
8175bacfb8
...
40fe234070
Author | SHA1 | Date | |
---|---|---|---|
40fe234070 | |||
361d3f0b2b |
@ -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.2-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.3-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.4.2-SNAPSHOT")
|
api("net.sergeych:parsec3:0.4.3-SNAPSHOT")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
version = "0.4.2-SNAPSHOT"
|
version = "0.4.3-SNAPSHOT"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -16,15 +16,40 @@ import kotlin.reflect.typeOf
|
|||||||
interface KVStorage {
|
interface KVStorage {
|
||||||
operator fun get(key: String): ByteArray?
|
operator fun get(key: String): ByteArray?
|
||||||
operator fun set(key: String, value: ByteArray?)
|
operator fun set(key: String, value: ByteArray?)
|
||||||
operator fun contains(key: String): Boolean
|
|
||||||
|
/**
|
||||||
|
* Check whether key is in storage.
|
||||||
|
* Default implementation uses [keys]. You may override it for performance
|
||||||
|
*/
|
||||||
|
operator fun contains(key: String): Boolean = key in keys
|
||||||
|
|
||||||
|
val keys: Set<String>
|
||||||
|
|
||||||
|
|
||||||
val keys: Collection<String>
|
/**
|
||||||
|
* Get number of object in the storage
|
||||||
|
* Default implementation uses [keys]. You may override it for performance
|
||||||
|
*/
|
||||||
|
val size: Int get() = keys.size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all objects in the storage
|
||||||
|
* Default implementation uses [keys]. You may override it for performance
|
||||||
|
*/
|
||||||
fun clear() {
|
fun clear() {
|
||||||
for (k in keys) this[k] = null
|
for (k in keys) this[k] = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation uses [keys]. You may override it for performance
|
||||||
|
*/
|
||||||
|
fun isEmpty() = size == 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation uses [keys]. You may override it for performance
|
||||||
|
*/
|
||||||
|
fun isNotEmpty() = size != 0
|
||||||
|
|
||||||
fun addAll(other: KVStorage) {
|
fun addAll(other: KVStorage) {
|
||||||
for (k in other.keys) {
|
for (k in other.keys) {
|
||||||
this[k] = other[k]
|
this[k] = other[k]
|
||||||
@ -38,6 +63,8 @@ inline operator fun <reified T> KVStorage.invoke(defaultValue: T,overrideName: S
|
|||||||
|
|
||||||
inline fun <reified T> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
|
inline fun <reified T> KVStorage.stored(defaultValue: T, overrideName: String? = null) =
|
||||||
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
|
KVStorageDelegate<T>(this, typeOf<T>(), defaultValue, overrideName)
|
||||||
|
inline fun <reified T> KVStorage.optStored(defaultValue: T?=null, overrideName: String? = null) =
|
||||||
|
KVStorageDelegate<T?>(this, typeOf<T?>(), defaultValue, overrideName)
|
||||||
|
|
||||||
class KVStorageDelegate<T>(
|
class KVStorageDelegate<T>(
|
||||||
private val storage: KVStorage,
|
private val storage: KVStorage,
|
||||||
@ -110,7 +137,7 @@ class MemoryKVStorage(copyFrom: KVStorage? = null) : KVStorage {
|
|||||||
return key in data
|
return key in data
|
||||||
}
|
}
|
||||||
|
|
||||||
override val keys: Collection<String>
|
override val keys: Set<String>
|
||||||
get() = underlying?.keys ?: data.keys
|
get() = underlying?.keys ?: data.keys
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
|
39
src/jsMain/kotlin/net/sergeych/parsec3/BrowserKVStorage.kt
Normal file
39
src/jsMain/kotlin/net/sergeych/parsec3/BrowserKVStorage.kt
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package net.sergeych.parsec3
|
||||||
|
|
||||||
|
import net.sergeych.mp_tools.decodeBase64Compact
|
||||||
|
import net.sergeych.mp_tools.encodeToBase64Compact
|
||||||
|
import org.w3c.dom.Storage
|
||||||
|
import org.w3c.dom.set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default KV storage in browser. Use if with `localStorage` or `sessionStorage`. Uses
|
||||||
|
* prefix for storage values to not to collide with other data
|
||||||
|
*/
|
||||||
|
class BrowserKVStorage(keyPrefix: String, private val bst: Storage) : KVStorage {
|
||||||
|
|
||||||
|
private val prefix = "$keyPrefix:"
|
||||||
|
fun k(key: String) = "$prefix$key"
|
||||||
|
override fun get(key: String): ByteArray? {
|
||||||
|
return bst.getItem(k(key))?.decodeBase64Compact()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(key: String, value: ByteArray?) {
|
||||||
|
val corrected = k(key)
|
||||||
|
if (value == null)
|
||||||
|
bst.removeItem(corrected)
|
||||||
|
else
|
||||||
|
bst.set(corrected, value.encodeToBase64Compact())
|
||||||
|
}
|
||||||
|
|
||||||
|
override val keys: Set<String>
|
||||||
|
get() {
|
||||||
|
val kk = mutableListOf<String>()
|
||||||
|
for (i in 0 until bst.length) {
|
||||||
|
val k = bst.key(i) ?: break
|
||||||
|
if( k.startsWith(prefix)) {
|
||||||
|
kk += k.substring(prefix.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kk.toSet()
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package net.sergeych.parsec3
|
package net.sergeych.parsec3
|
||||||
|
|
||||||
actual fun defaultNamedStorage(name: String): KVStorage {
|
import kotlinx.browser.localStorage
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
@Suppress("unused")
|
||||||
|
actual fun defaultNamedStorage(name: String): KVStorage = BrowserKVStorage(name, localStorage)
|
36
src/jsTest/kotlin/testBrowserKVStorage.kt
Normal file
36
src/jsTest/kotlin/testBrowserKVStorage.kt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import kotlinx.browser.sessionStorage
|
||||||
|
import net.sergeych.parsec3.BrowserKVStorage
|
||||||
|
import net.sergeych.parsec3.optStored
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class testBrowserKVStorage {
|
||||||
|
@Test
|
||||||
|
fun testStorage() {
|
||||||
|
val st = BrowserKVStorage("tpr", sessionStorage)
|
||||||
|
var foo: String? by st.optStored()
|
||||||
|
assertNull(foo)
|
||||||
|
foo = "bar"
|
||||||
|
assertEquals("bar", foo)
|
||||||
|
println(st.keys)
|
||||||
|
assertTrue { "foo" in st.keys }
|
||||||
|
assertFalse { "bar" in st.keys }
|
||||||
|
var bar: Int? by st.optStored()
|
||||||
|
assertNull(bar)
|
||||||
|
bar = 42
|
||||||
|
assertEquals(42, bar)
|
||||||
|
assertTrue { "foo" in st.keys }
|
||||||
|
assertTrue { "bar" in st.keys }
|
||||||
|
assertEquals("bar", foo)
|
||||||
|
|
||||||
|
val st2 = BrowserKVStorage("tpr", sessionStorage)
|
||||||
|
val foo2: String? by st.optStored(overrideName = "foo")
|
||||||
|
assertEquals("bar", foo2)
|
||||||
|
|
||||||
|
assertTrue(st2.isNotEmpty())
|
||||||
|
assertTrue(st.isNotEmpty())
|
||||||
|
|
||||||
|
st.clear()
|
||||||
|
assertTrue(st.isEmpty())
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -97,7 +97,7 @@ internal class WsServerKtTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testWsServerReconnect() {
|
fun testWsServerReconnect() {
|
||||||
|
|
||||||
embeddedServer(Netty, port = 8080) {
|
embeddedServer(Netty, port = 8090) {
|
||||||
parsec3TransportServer(
|
parsec3TransportServer(
|
||||||
TestApiServer,
|
TestApiServer,
|
||||||
) {
|
) {
|
||||||
@ -112,7 +112,7 @@ internal class WsServerKtTest {
|
|||||||
}.start(wait = false)
|
}.start(wait = false)
|
||||||
|
|
||||||
Log.connectConsole(Log.Level.DEBUG)
|
Log.connectConsole(Log.Level.DEBUG)
|
||||||
val client = Parsec3WSClient("ws://localhost:8080/api/p3", TestApiClient) {
|
val client = Parsec3WSClient("ws://localhost:8090/api/p3", TestApiClient) {
|
||||||
on(api.bar) {
|
on(api.bar) {
|
||||||
"bar:$it"
|
"bar:$it"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user