Coder Social home page Coder Social logo

xxfast / kstore Goto Github PK

View Code? Open in Web Editor NEW
476.0 3.0 15.0 481 KB

A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisation and kotlinx.io

Home Page: https://xxfast.github.io/KStore/

License: Apache License 2.0

Kotlin 100.00%
kotlin kotlin-multiplatform kotlinx-coroutines kotlinx-serialization okio

kstore's Introduction

KStore

Build

Kotlin Alpha Kotlin Maven Central

badge-android badge-ios badge-mac badge-watchos badge-tvos badge-jvm badge-linux badge-windows badge-nodejs badge-jsBrowser badge-wasmJsBrowser

A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialization and kotlinx.io. Inspired by RxStore

Features

  • πŸ”’ Read-write locks; with a mutex FIFO lock
  • πŸ’Ύ In-memory caching; read once from disk and reuse
  • πŸ“¬ Default values; no file? no problem!
  • 🚚 Migration support; moving shop? take your data with you
  • πŸš‰ Multiplatform!

Installation

KStore is published on Maven Central. Latest version Maven Central

repositories { 
  mavenCentral()
  // or for snapshot builds
  maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
# for common
kstore = { module = "io.github.xxfast:kstore", version.ref = "kstore" }

# for android, iOS, desktop and nodeJs
kstore-file = { module = "io.github.xxfast:kstore-file", version.ref = "kstore" }

# for jsBrowser and wasmJsBrowser
kstore-storage = { module = "io.github.xxfast:kstore-storage", version.ref = "kstore" }

Depending on your target platforms, you will need to add platform configurations here

At a glance

import kotlin.io.path.Path
import kotlinx.serialization.Serializable

// Take any serializable model 
@Serializable data class Pet(val name: String, val age: Int) 

// Create a store
val store: KStore<Pet> = storeOf(file = Path("path/to/my_cats.json"))

// Get, set, update or delete values 
val mylo: Pet? = store.get()
store.set(mylo)
store.update { pet: Pet? ->
  pet?.copy(age = pet.age + 1)
}
store.delete()

// Observe for updates
val pets: Flow<Pet?> = store.updates

Installation and Usage

Documentation here

API Reference here

Licence

Copyright 2023 Isuru Rajapakse

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

kstore's People

Contributors

asemy avatar dependabot[bot] avatar jantie avatar ranger163 avatar xxfast avatar zacharee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

kstore's Issues

Sample app

Add a dead simple sample app to demonstrate KStore use-cases

Stores on desktop targets requires the folder to be created ahead of file writes/reads

Creating a store for android/ios is fairly straightforward

//android
val filesDir: String = androidContext().filesDir.path
storeOf(file = "$filesDir/countries.json".toPath(), default = emptyList())
        
// ios
val filesDir: String? = NSFileManager.defaultManager.DocumentDirectory?.relativePath
requireNotNull(filesDir) { "Document directory not found" }
storeOf(file = "$filesDir/countries.json".toPath(), default = emptyList())

However, for desktop we need this extra step

// desktop
val filesDir: String = AppDirsFactory.getInstance()
            .getUserDataDir(PACKAGE_NAME, VERSION, AUTHOR)

FILE_SYSTEM.createDirectories(filesDir.toPath())

storeOf(file = "$filesDir/countries.json".toPath(), default = emptyList())

Need to think of an API to bridge this gap

An API to the get cached value synchronously

Sometimes we want to be able to read the cached value from the store synchronously.

For example, on Ktor's default request as requested in this feature

interface Database {  
  suspend fun readUsername(): String? 
  val cachedUsername: String?
}

defaultRequest {
  database.readUsername()?.let { header("X-User-ID", it) } // wont compile
  database.cachedUsername?.let { header("X-User-ID", it) }
}

iOS targets crashes when store is setting a value while there is no previous file

Uncaught Kotlin exception: okio.IOException: Operation not permitted
    at 0   PSCore                              0x10548be63        kfun:okio#errnoToIOException(kotlin.Int){}okio.IOException + 419 
    at 1   PSCore                              0x105490993        kfun:okio.PosixFileSystem#sink(okio.Path;kotlin.Boolean){}okio.Sink + 751 
    at 2   PSCore                              0x105565b1f        kfun:au.com.gridstone.pscore.app.data.$<get-appDataModule>$lambda$11$lambda$2$lambda$0$FUNCTION_REFERENCE$18.$<bridge-UNNN>invoke(au.com.gridstone.pscore.login.data.models.DeviceCredentials?){}#internal + 871 
    at 3   PSCore                              0x105562caf        kfun:au.com.gridstone.pscore.app.data.$<get-appDataModule>$lambda$11$lambda$2$suspendConversion0COROUTINE$2.invokeSuspend#internal + 347 
    at 4   PSCore                              0x105562e3f        kfun:au.com.gridstone.pscore.app.data.$<get-appDataModule>$lambda$11$lambda$2$suspendConversion0COROUTINE$2.invoke#internal + 195 
    at 5   PSCore                              0x1054a59e3        kfun:io.github.xxfast.kstore.KStore.$writeCOROUTINE$73.invokeSuspend#internal + 427 
    at 6   PSCore                              0x1054a5bf3        kfun:io.github.xxfast.kstore.KStore.write#internal + 183 
    at 7   PSCore                              0x1054a6493        kfun:io.github.xxfast.kstore.KStore.$setCOROUTINE$75#invokeSuspend(kotlin.Result<kotlin.Any?>){}kotlin.Any? + 547 
    at 8   PSCore                              0x1054a6757        kfun:io.github.xxfast.kstore.KStore#set(1:0?){} + 183 
    at 9   PSCore                              0x1055180b7        kfun:au.com.gridstone.pscore.login.screens.$LoginDomain$lambda$14$lambda$13$lambda$12COROUTINE$39.invokeSuspend#internal + 8635 
    at 10  PSCore                              0x1051d4397        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 203 
    at 11  PSCore                              0x1052d926f        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 1439 
    at 12  PSCore                              0x1052ec4ab        kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda$0$FUNCTION_REFERENCE$487.$<bridge-UNN>invoke(){}#internal + 227 
    at 13  PSCore                              0x1056b5f63        ___6f72672e6a6574627261696e732e6b6f746c696e783a6b6f746c696e782d636f726f7574696e65732d636f72652f6f70742f6275696c644167656e742f776f726b2f343465633665383530643563363366302f6b6f746c696e782d636f726f7574696e65732d636f72652f6e617469766544617277696e2f7372632f44697370617463686572732e6b74_knbridge459_block_invoke + 439 
    at 14  libdispatch.dylib                   0x1047c05a7        _dispatch_call_block_and_release + 31 
    at 15  libdispatch.dylib                   0x1047c205b        _dispatch_client_callout + 19 
    at 16  libdispatch.dylib                   0x1047d280f        _dispatch_main_queue_drain + 1195 
    at 17  libdispatch.dylib                   0x1047d2353        _dispatch_main_queue_callback_4CF + 43 
    at 18  CoreFoundation                      0x1c0c166f7        <redacted> + 15 
    at 19  CoreFoundation                      0x1c0bf8057        <redacted> + 2035 
    at 20  CoreFoundation                      0x1c0bfced3        CFRunLoopRunSpecific + 611 
    at 21  GraphicsServices                    0x1f9efe367        GSEventRunModal + 163 
    at 22  UIKitCore                           0x1c30db3cf        <redacted> + 887 
    at 23  UIKitCore                           0x1c30db033        UIApplicationMain + 339 
    at 24  SwiftUI                             0x1c46e8013        <redacted> + 2419 
    at 25  SwiftUI                             0x1c464916b        <redacted> + 387 
    at 26  SwiftUI                             0x1c46324bb        <redacted> + 2867 
    at 27  ios                                 0x1042a5b87        main + 35 
    at 28  dyld                                0x1df26495f        <redacted> + 2527 

Versioned fileStore crashes on Android

Currently (version 0.7.2 but i guess its more like since 0.7.0) the versioned KStore cannot be instantiated on Android devices.
Creating such a KStore results in:
java.io.FileNotFoundException: $my_store.json.version: open failed: EROFS (Read-only file system)
However, using the same path "${context.filesDir.toPath().pathString}/my_store.json".toPath() in the regular storeOf function works perfectly fine.

Not sure if the leading Dollar is intended or not, but i just scrolled a bit into the changes and it seems like the 0.7.0 fix for #69 might have caused such versioned KStores to always be created on the root level of the File-System. Which in case of an Android file System will always be Read-Only.
Imo the version jsons should be created in the same directory as the store itself. Tinkering with it i could even reproduce this within the KVersionedStoreTests when i use a relative path and comment out the deletion test. The store file is created at the correct location, but the version file will always be created at the root directory of the current launching scope.

How to handle migrations?

If I have stored an object and need to alter the structure of the class, how can I migrate the existing data to the new structure? Do you support this?

Some users might take a long time to download the latest update of an app, I must thus be able to migrate between from e.g. v1 to v5 of a data structure. Do you support this?

java.io.IOException: failed to create directory: tmp

Thanks for this awesome library!

I've set it up as per your instructions but when I go to use it I'm getting the following exceptions (essentially it can't create the directory or it can't store the file due to a read-only FS. Did I miss a permission request or something?

How I initialized it

private val store: KStore<JWTTokens> = storeOf(filePath = "tmp/jwt.session")

with 'tmp'

java.io.IOException: failed to create directory: tmp
                                                                                                    	at okio.JvmSystemFileSystem.createDirectory(JvmSystemFileSystem.kt:116)
                                                                                                    	at okio.FileSystem.createDirectory(FileSystem.kt:95)

without the 'tmp' prefix

java.io.FileNotFoundException: jwt.session: open failed: EROFS (Read-only file system)

Add StateFlow and MutableStateFlow support

Flows require the direct statement of a CoroutineScope , stateIn, or collect() to properly access the data in a composable's LaunchedEffect. This is a lot of effort, and Flows are considered a cold state once completed.

Based on JetBrains' shift towards StateFlow and SharedFlow, I recommend adding a way to use both of these datatypes to the API, as well as their mutable versions a feature of the next update.

Add browser target

To be able to browser targets, I'll need to rework how encoder/decorders work because FILE_SYSTEM doesn't exist for a js browser targets

IOS and Android Crash

Hi I am using v0.6.0 In Both android and ios the app crash when launching.

IOS Crash log

Uncaught Kotlin exception: okio.IOException: Read-only file system
    at 0   My application                      0x100ff8fbb        kfun:kotlin.Exception#<init>(kotlin.String?;kotlin.Throwable?){} + 147 
    at 1   My application                      0x10184aadb        kfun:okio.IOException#<init>(kotlin.String?;kotlin.Throwable?){} + 147 
    at 2   My application                      0x10184ab6b        kfun:okio.IOException#<init>(kotlin.String?){} + 123 
    at 3   My application                      0x1018456c3        kfun:okio#errnoToIOException(kotlin.Int){}okio.IOException + 523 
    at 4   My application                      0x10186e3b7        kfun:okio#variantSink__at__okio.PosixFileSystem(okio.Path;kotlin.Boolean){}okio.Sink + 715 
    at 5   My application                      0x101849fd7        kfun:okio.PosixFileSystem#sink(okio.Path;kotlin.Boolean){}okio.Sink + 199 
    at 6   My application                      0x1018480cb        kfun:okio.FileSystem#sink$default(okio.Path;kotlin.Boolean;kotlin.Int){}okio.Sink + 275 
    at 7   My application                      0x101873e7b        kfun:io.github.xxfast.kstore.file.FileCodec#encode#suspend(1:0?;kotlin.coroutines.Continuation<kotlin.Unit>){}kotlin.Any + 723 
    at 8   My application                      0x101825cab        kfun:io.github.xxfast.kstore.KStore.$write$lambda$1COROUTINE$6.invokeSuspend#internal + 551 
    at 9   My application                      0x1018260af        kfun:io.github.xxfast.kstore.KStore.write$lambda$1#internal + 363 
    at 10  My application                      0x101826e73        kfun:io.github.xxfast.kstore.KStore.$write$lambda$1$FUNCTION_REFERENCE$1.invoke#internal + 163 
    at 11  My application                      0x101008d2b        kfun:kotlin.coroutines.intrinsics.object-3.invokeSuspend#internal + 799 
    at 12  My application                      0x1010059db        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 651 
    at 13  My application                      0x1011d0b8b        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 2715 
    at 14  My application                      0x1011d426b        kfun:kotlinx.coroutines.internal.LimitedDispatcher.Worker.run#internal + 307 
    at 15  My application                      0x101201deb        kfun:kotlinx.coroutines.MultiWorkerDispatcher.$workerRunLoop$lambda$2COROUTINE$0.invokeSuspend#internal + 2591 
    at 16  My application                      0x1010059db        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 651 
    at 17  My application                      0x1011d0b8b        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 2715 
    at 18  My application                      0x10115ff13        kfun:kotlinx.coroutines.EventLoopImplBase#processNextEvent(){}kotlin.Long + 1431 
    at 19  My application                      0x1011f8de7        kfun:kotlinx.coroutines.BlockingCoroutine.joinBlocking#internal + 483 
    at 20  My application                      0x1011f85a3        kfun:kotlinx.coroutines#runBlocking(kotlin.coroutines.CoroutineContext;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>){0Β§<kotlin.Any?>}0:0 + 1615 
    at 21  My application                      0x1011f87df        kfun:kotlinx.coroutines#runBlocking$default(kotlin.coroutines.CoroutineContext?;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>;kotlin.Int){0Β§<kotlin.Any?>}0:0 + 271 
    at 22  My application                      0x1011ff7cf        kfun:kotlinx.coroutines.MultiWorkerDispatcher.workerRunLoop#internal + 203 
    at 23  My application                      0x10120102b        kfun:kotlinx.coroutines.MultiWorkerDispatcher.<init>$lambda$1$lambda$0#internal + 91 
    at 24  My application                      0x10120272b        kfun:kotlinx.coroutines.MultiWorkerDispatcher.$<init>$lambda$1$lambda$0$FUNCTION_REFERENCE$4.invoke#internal + 95 
    at 25  My application                      0x10120283f        kfun:kotlinx.coroutines.MultiWorkerDispatcher.$<init>$lambda$1$lambda$0$FUNCTION_REFERENCE$4.$<bridge-UNN>invoke(){}#internal + 95 
    at 26  My application                      0x10101383b        WorkerLaunchpad + 195 
    at 27  My application                      0x101b03b27        _ZN6Worker19processQueueElementEb + 2603 
    at 28  My application                      0x101b02f9f        _ZN12_GLOBAL__N_113workerRoutineEPv + 219 
    at 29  libsystem_pthread.dylib             0x1b1838427        _pthread_start + 115 
    at 30  libsystem_pthread.dylib             0x1b1833647        thread_start + 7 
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.runtime.BroadcastFrameClock@7a830e70, StandaloneCoroutine{Cancelling}@7a92be00, FlushCoroutineDispatcher@7a840490]
        at 0   My application                      0x10100034b        kfun:kotlin.Throwable#<init>(kotlin.String?){} + 123 
        at 1   My application                      0x100ff8f13        kfun:kotlin.Exception#<init>(kotlin.String?){} + 119 
        at 2   My application                      0x100ff923f        kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 119 
        at 3   My application                      0x101203dff        kfun:kotlinx.coroutines.internal.DiagnosticCoroutineContextException#<init>(kotlin.coroutines.CoroutineContext){} + 203 
        at 4   My application                      0x1011cbb23        kfun:kotlinx.coroutines.internal#handleUncaughtCoroutineException(kotlin.coroutines.CoroutineContext;kotlin.Throwable){} + 1135 
        at 5   My application                      0x10115af37        kfun:kotlinx.coroutines#handleCoroutineException(kotlin.coroutines.CoroutineContext;kotlin.Throwable){} + 819 
        at 6   My application                      0x10114b353        kfun:kotlinx.coroutines.StandaloneCoroutine.handleJobException#internal + 187 
        at 7   My application                      0x101168057        kfun:kotlinx.coroutines.JobSupport.finalizeFinishingState#internal + 1235 
        at 8   My application                      0x10117228b        kfun:kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath#internal + 2239 
        at 9   My application                      0x101171993        kfun:kotlinx.coroutines.JobSupport.tryMakeCompleting#internal + 719 
        at 10  My application                      0x1011714d7        kfun:kotlinx.coroutines.JobSupport#makeCompletingOnce(kotlin.Any?){}kotlin.Any? + 411 
        at 11  My application                      0x10114a027        kfun:kotlinx.coroutines.AbstractCoroutine#resumeWith(kotlin.Result<1:0>){} + 243 
        at 12  My application                      0x101005c43        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 1267 
        at 13  My application                      0x1011d0a3b        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 2379 
        at 14  My application                      0x1016552b7        kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.dispatch$lambda$1$lambda$0#internal + 571 
        at 15  My application                      0x101656c57        kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.$dispatch$lambda$1$lambda$0$FUNCTION_REFERENCE$3.invoke#internal + 99 
        at 16  My application                      0x101656dab        kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.$dispatch$lambda$1$lambda$0$FUNCTION_REFERENCE$3.$<bridge-UNN>invoke(){}#internal + 95 
        at 17  My application                      0x101654b53        kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.performRun#internal + 399 
        at 18  My application                      0x1016554db        kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.dispatch$lambda$1#internal + 259 
        at 19  My application                      0x10165677b        kfun:androidx.compose.ui.platform.FlushCoroutineDispatcher.$dispatch$lambda$1$FUNCTION_REFERENCE$0.invoke#internal + 163 
        at 20  My application                      0x101008d2b        kfun:kotlin.coroutines.intrinsics.object-3.invokeSuspend#internal + 799 
        at 21  My application                      0x1010059db        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 651 
        at 22  My application                      0x1011d0b8b        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 2715 
        at 23  My application                      0x1013cbc9f        kfun:org.jetbrains.skiko.NsQueueDispatcher.dispatch$lambda$0#internal + 155 
        at 24  My application                      0x1013cc01f        kfun:org.jetbrains.skiko.NsQueueDispatcher.$dispatch$lambda$0$FUNCTION_REFERENCE$0.invoke#internal + 95 
        at 25  My application                      0x1013cc133        kfun:org.jetbrains.skiko.NsQueueDispatcher.$dispatch$lambda$0$FUNCTION_REFERENCE$0.$<bridge-UNN>invoke(){}#internal + 95 
        at 26  My application                      0x1013cd2c7        _6f72672e6a6574627261696e732e736b696b6f3a736b696b6f2f6f70742f6275696c644167656e742f776f726b2f613634643361613437376431326636622f736b696b6f2f7372632f64617277696e4d61696e2f6b6f746c696e2f6f72672f6a6574627261696e732f736b696b6f2f44697370617463686572732e6b74_knbridge6 + 279 
        at 27  libdispatch.dylib                   0x180132ee3        _dispatch_call_block_and_release + 23 
        at 28  libdispatch.dylib                   0x180134707        _dispatch_client_callout + 15 
        at 29  libdispatch.dylib                   0x180143fd7        _dispatch_main_queue_drain + 1219 
        at 30  libdispatch.dylib                   0x180143b03        _dispatch_main_queue_callback_4CF + 39 
        at 31  CoreFoundation                      0x18039a783        __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 11 
        at 32  CoreFoundation                      0x180394de3        __CFRunLoopRun + 1911 
        at 33  CoreFoundation                      0x180394253        CFRunLoopRunSpecific + 583 
        at 34  GraphicsServices                    0x188eb7c9b        GSEventRunModal + 159 
        at 35  UIKitCore                           0x10553afef        -[UIApplication _run] + 867 
        at 36  UIKitCore                           0x10553ef3b        UIApplicationMain + 123 
        at 37  SwiftUI                             0x1095e734b        OUTLINED_FUNCTION_54 + 499 
        at 38  SwiftUI                             0x1095e71eb        OUTLINED_FUNCTION_54 + 147 
        at 39  SwiftUI                             0x108ddf473        OUTLINED_FUNCTION_16 + 87 
        at 40  My application                      0x100fe11d3        $s14My_application6iOSAppV5$mainyyFZ + 39 (/Users/a503959/mydrive/projects/personal/Photo Manager/PhotoManagerMulti/iosApp/iosApp/iOSApp.swift:<unknown>)
        at 41  My application                      0x100fe127f        main + 11 
        at 42  dyld                                0x104621513        0x0 + 4368504083 
        at 43  ???                                 0x10452df27        0x0 + 4367507239 
        at 44  ???                                 0x9479ffffffffffff 0x0 + -7747880208937517057 

Android Crash Log

4617-4617  AndroidRuntime          com.myapplication.MyApplication      E  FATAL EXCEPTION: main
                                                                           Process: com.myapplication.MyApplication, PID: 4617
                                                                           java.io.FileNotFoundException: testPreference.json: open failed: EROFS (Read-only file system)
                                                                           	at libcore.io.IoBridge.open(IoBridge.java:574)
                                                                           	at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
                                                                           	at okio.Okio__JvmOkioKt.sink(JvmOkio.kt:174)
                                                                           	at okio.Okio.sink(Unknown Source:1)
                                                                           	at okio.Okio__JvmOkioKt.sink$default(JvmOkio.kt:174)
                                                                           	at okio.Okio.sink$default(Unknown Source:1)
                                                                           	at okio.JvmSystemFileSystem.sink(JvmSystemFileSystem.kt:101)
                                                                           	at okio.FileSystem.sink(FileSystem.kt:75)
                                                                           	at io.github.xxfast.kstore.file.FileCodec.encode(FileCodec.kt:45)
                                                                           	at io.github.xxfast.kstore.KStore$write$2.invokeSuspend(KStore.kt:34)
                                                                           	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                           	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                           	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
                                                                           	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
                                                                           	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
                                                                           	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
                                                                           	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
                                                                           	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
                                                                           	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@5515b02, androidx.compose.runtime.BroadcastFrameClock@2ea8c13, StandaloneCoroutine{Cancelling}@e3d9e50, AndroidUiDispatcher@858f849]
                                                                           Caused by: android.system.ErrnoException: open failed: EROFS (Read-only file system)
                                                                           	at libcore.io.Linux.open(Native Method)
                                                                           	at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
                                                                           	at libcore.io.BlockGuardOs.open(BlockGuardOs.java:274)
                                                                           	at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
                                                                           	at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7779)
                                                                           	at libcore.io.IoBridge.open(IoBridge.java:560)
                                                                           	... 17 more

Unresolved reference: storeOf

I have the dependency in the commonMain:
api("io.github.xxfast:kstore:0.7.1")

Then I try to create an instance of KStore:
val store: KStore<UserEntity> = storeOf(filePath = "path/to/my_cats.json")

But the reference tos storeOf canΒ΄t be found.

Closeable and clear on close

Hi, I think it would be useful if the store implements AutoCloseable and one can configure the store to delete all data when it's closed. What do you think?

JsonDecodingException in VersionedCodec

We've got the non-fatal error in Crashlytics with the following stacktrace:

Non-fatal Exception: kotlinx.serialization.json.internal.JsonDecodingException Unexpected JSON token at offset 0: Expected numeric literal at path: $ JSON input: kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException (JsonExceptions.kt:24) kotlinx.serialization.json.okio.OkioStreamsKt.decodeFromBufferedSource (OkioStreams.kt:65) io.github.xxfast.kstore.file.extensions.VersionedCodec.decode (KVersionedStore.kt:68) io.github.xxfast.kstore.KStore$read$2.invokeSuspend (KStore.kt:40) ...

We use KStore 0.6.0 in the similar way:

val kstore = storeOf(
    filePath = "$storePath/application_$applicationId.json",
    version = 0,
    enableCache = true,
    json = json
)

kstore.update {
   ...
}

where storePath is application.applicationContext.filesDir.path + "/cross_sell"

It looks like a problem in version file reading: https://github.com/xxfast/KStore/blob/0.6.0/kstore-file/src/commonMain/kotlin/io/github/xxfast/kstore/file/extensions/KVersionedStore.kt#L67C33-L68C1. Have you any ideas?

Also I see that you are going to save version to file metadata instead. Do you have any plans?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.