@@ -32,7 +32,6 @@ import com.harrytmthy.safebox.extensions.safeBoxScope
32
32
import com.harrytmthy.safebox.extensions.toBytes
33
33
import com.harrytmthy.safebox.extensions.toEncodedByteArray
34
34
import com.harrytmthy.safebox.keystore.SecureRandomKeyProvider
35
- import com.harrytmthy.safebox.registry.SafeBoxBlobFileRegistry
36
35
import com.harrytmthy.safebox.state.SafeBoxStateListener
37
36
import com.harrytmthy.safebox.state.SafeBoxStateManager
38
37
import com.harrytmthy.safebox.storage.Bytes
@@ -199,27 +198,25 @@ public class SafeBox private constructor(
199
198
}
200
199
201
200
/* *
201
+ * **Deprecated:** SafeBox no longer supports instance closing.
202
+ *
202
203
* Immediately closes the underlying file channel and releases resources.
203
- * Also unregisters the file from [SafeBoxBlobFileRegistry], allowing a new SafeBox
204
- * instance to be created with the same filename.
205
204
*
206
205
* ⚠️ Once closed, this instance becomes *permanently unusable*. Any further access will fail.
207
206
*
208
207
* ⚠️ Only use this method when you're certain that no writes are in progress.
209
208
*
210
209
* Closing during an active write can result in data corruption or incomplete persistence.
211
210
*/
211
+ @Deprecated(message = " This method is now a no-op, as SafeBox is always active and reusable." )
212
212
public fun close () {
213
- SafeBoxBlobFileRegistry .unregister(blobStore.getFileName())
214
- blobStore.close()
215
- keyCipherProvider.destroyKey()
216
- valueCipherProvider.destroyKey()
213
+ // no-op
217
214
}
218
215
219
216
/* *
217
+ * **Deprecated:** SafeBox no longer supports instance closing.
218
+ *
220
219
* Closes the underlying file channel only after all pending writes have completed.
221
- * Also unregisters the file from [SafeBoxBlobFileRegistry], allowing a new SafeBox
222
- * instance to be created with the same filename.
223
220
*
224
221
* ⚠️ Once closed, this instance becomes *permanently unusable*. Any further access will fail.
225
222
*
@@ -228,8 +225,9 @@ public class SafeBox private constructor(
228
225
* Internally, this launches a coroutine on [safeBoxScope] to wait until the SafeBox
229
226
* becomes idle before releasing resources.
230
227
*/
228
+ @Deprecated(message = " This method is now a no-op, as SafeBox is always active and reusable." )
231
229
public fun closeWhenIdle () {
232
- stateManager.closeWhenIdle(::close)
230
+ // no-op
233
231
}
234
232
235
233
override fun getAll (): Map <String , Any ?> {
@@ -376,6 +374,9 @@ public class SafeBox private constructor(
376
374
@VisibleForTesting
377
375
internal const val DEFAULT_VALUE_KEYSTORE_ALIAS = " SafeBoxValue"
378
376
377
+ @VisibleForTesting
378
+ internal val instances = ConcurrentHashMap <String , SafeBox >()
379
+
379
380
/* *
380
381
* Creates a [SafeBox] instance with secure defaults:
381
382
* - Keys are deterministically encrypted using [ChaCha20CipherProvider].
@@ -411,7 +412,10 @@ public class SafeBox private constructor(
411
412
ioDispatcher : CoroutineDispatcher = Dispatchers .IO ,
412
413
stateListener : SafeBoxStateListener ? = null,
413
414
): SafeBox {
414
- SafeBoxBlobFileRegistry .register(fileName)
415
+ instances[fileName]?.let { safeBox ->
416
+ stateListener?.let (safeBox.stateManager::setStateListener)
417
+ return safeBox
418
+ }
415
419
val aesGcmCipherProvider = AesGcmCipherProvider .create(
416
420
alias = valueKeyStoreAlias,
417
421
aad = additionalAuthenticatedData,
@@ -428,6 +432,7 @@ public class SafeBox private constructor(
428
432
val stateManager = SafeBoxStateManager (fileName, stateListener, ioDispatcher)
429
433
val blobStore = SafeBoxBlobStore .create(context, fileName)
430
434
return SafeBox (blobStore, keyCipherProvider, valueCipherProvider, stateManager)
435
+ .also { instances[fileName] = it }
431
436
}
432
437
433
438
/* *
@@ -461,10 +466,14 @@ public class SafeBox private constructor(
461
466
ioDispatcher : CoroutineDispatcher = Dispatchers .IO ,
462
467
stateListener : SafeBoxStateListener ? = null,
463
468
): SafeBox {
464
- SafeBoxBlobFileRegistry .register(fileName)
469
+ instances[fileName]?.let { safeBox ->
470
+ stateListener?.let (safeBox.stateManager::setStateListener)
471
+ return safeBox
472
+ }
465
473
val stateManager = SafeBoxStateManager (fileName, stateListener, ioDispatcher)
466
474
val blobStore = SafeBoxBlobStore .create(context, fileName)
467
475
return SafeBox (blobStore, keyCipherProvider, valueCipherProvider, stateManager)
476
+ .also { instances[fileName] = it }
468
477
}
469
478
}
470
479
}
0 commit comments