improved KVStorage support
This commit is contained in:
parent
8175bacfb8
commit
361d3f0b2b
@ -10,7 +10,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.4.2-SNAPSHOT"
|
||||
version = "0.4.3-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -16,15 +16,40 @@ import kotlin.reflect.typeOf
|
||||
interface KVStorage {
|
||||
operator fun get(key: String): 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() {
|
||||
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) {
|
||||
for (k in other.keys) {
|
||||
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) =
|
||||
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>(
|
||||
private val storage: KVStorage,
|
||||
@ -110,7 +137,7 @@ class MemoryKVStorage(copyFrom: KVStorage? = null) : KVStorage {
|
||||
return key in data
|
||||
}
|
||||
|
||||
override val keys: Collection<String>
|
||||
override val keys: Set<String>
|
||||
get() = underlying?.keys ?: data.keys
|
||||
|
||||
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
|
||||
|
||||
actual fun defaultNamedStorage(name: String): KVStorage {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
import kotlinx.browser.localStorage
|
||||
|
||||
|
||||
@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
|
||||
fun testWsServerReconnect() {
|
||||
|
||||
embeddedServer(Netty, port = 8080) {
|
||||
embeddedServer(Netty, port = 8090) {
|
||||
parsec3TransportServer(
|
||||
TestApiServer,
|
||||
) {
|
||||
@ -112,7 +112,7 @@ internal class WsServerKtTest {
|
||||
}.start(wait = false)
|
||||
|
||||
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) {
|
||||
"bar:$it"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user