mirror of
https://github.com/mollyim/monero-wallet-sdk.git
synced 2024-10-01 03:45:36 -04:00
lib: initial support for InProcess provider
This commit is contained in:
parent
f0c425dca9
commit
6811bdf47a
@ -8,9 +8,9 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class MoneroSdkClient(private val context: Context) {
|
||||
|
||||
@ -86,7 +86,7 @@ class MoneroSdkClient(private val context: Context) {
|
||||
throw IOException("Cannot create wallet data directory: ${walletDataDir.path}")
|
||||
}
|
||||
|
||||
override suspend fun write(writer: (FileOutputStream) -> Unit) {
|
||||
override suspend fun write(writer: (OutputStream) -> Unit) {
|
||||
val output = file.startWrite()
|
||||
try {
|
||||
writer(output)
|
||||
@ -97,7 +97,7 @@ class MoneroSdkClient(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun read(): FileInputStream {
|
||||
override suspend fun read(): InputStream {
|
||||
return file.openRead()
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,5 @@ package im.molly.monero;
|
||||
|
||||
interface IStorageAdapter {
|
||||
boolean writeAsync(in ParcelFileDescriptor pfd);
|
||||
void readAsync(in ParcelFileDescriptor pfd);
|
||||
oneway void readAsync(in ParcelFileDescriptor pfd);
|
||||
}
|
||||
|
10
lib/android/src/main/kotlin/im/molly/monero/Binder.kt
Normal file
10
lib/android/src/main/kotlin/im/molly/monero/Binder.kt
Normal file
@ -0,0 +1,10 @@
|
||||
package im.molly.monero
|
||||
|
||||
import android.os.IInterface
|
||||
|
||||
/**
|
||||
* Returns whether this interface is in a remote process.
|
||||
*/
|
||||
fun IInterface.isRemote(): Boolean {
|
||||
return asBinder() !== this
|
||||
}
|
@ -17,30 +17,28 @@ internal class StorageAdapter(var dataStore: WalletDataStore?) : IStorageAdapter
|
||||
override fun writeAsync(pfd: ParcelFileDescriptor?): Boolean {
|
||||
requireNotNull(pfd)
|
||||
val localDataStore = dataStore
|
||||
if (localDataStore == null) {
|
||||
pfd.close()
|
||||
return false
|
||||
}
|
||||
val inputStream = ParcelFileDescriptor.AutoCloseInputStream(pfd)
|
||||
ioStorageScope.launch {
|
||||
mutex.withLock {
|
||||
localDataStore.write { output ->
|
||||
inputStream.copyTo(output)
|
||||
return if (localDataStore != null) {
|
||||
val inputStream = ParcelFileDescriptor.AutoCloseInputStream(pfd)
|
||||
ioStorageScope.launch {
|
||||
mutex.withLock {
|
||||
localDataStore.write { output ->
|
||||
inputStream.copyTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.invokeOnCompletion { inputStream.close() }
|
||||
return true
|
||||
}.invokeOnCompletion { inputStream.close() }
|
||||
true
|
||||
} else {
|
||||
pfd.close()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun readAsync(pfd: ParcelFileDescriptor?) {
|
||||
requireNotNull(pfd)
|
||||
val localDataStore = dataStore
|
||||
if (localDataStore == null) {
|
||||
pfd.close()
|
||||
throw IllegalArgumentException("WalletDataStore cannot be null")
|
||||
}
|
||||
val outputStream = ParcelFileDescriptor.AutoCloseOutputStream(pfd)
|
||||
ioStorageScope.launch {
|
||||
val localDataStore =
|
||||
dataStore ?: throw IllegalArgumentException("WalletDataStore cannot be null")
|
||||
mutex.withLock {
|
||||
localDataStore.read().use { input ->
|
||||
input.copyTo(outputStream)
|
||||
|
@ -1,9 +1,9 @@
|
||||
package im.molly.monero
|
||||
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
interface WalletDataStore {
|
||||
suspend fun write(writer: (FileOutputStream) -> Unit)
|
||||
suspend fun read(): FileInputStream
|
||||
suspend fun write(writer: (OutputStream) -> Unit)
|
||||
suspend fun read(): InputStream
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class WalletNative private constructor(
|
||||
networkId: Int,
|
||||
private val storageAdapter: IStorageAdapter?,
|
||||
private val storageAdapter: IStorageAdapter,
|
||||
private val remoteNodeClient: IRemoteNodeClient?,
|
||||
private val scope: CoroutineScope,
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
@ -21,7 +21,7 @@ class WalletNative private constructor(
|
||||
// TODO: Find better name because this is a local synchronization wallet, not a full node wallet
|
||||
suspend fun fullNode(
|
||||
networkId: Int,
|
||||
storageAdapter: IStorageAdapter? = null,
|
||||
storageAdapter: IStorageAdapter,
|
||||
remoteNodeClient: IRemoteNodeClient? = null,
|
||||
secretSpendKey: SecretKey? = null,
|
||||
restorePoint: Long? = null,
|
||||
@ -59,13 +59,17 @@ class WalletNative private constructor(
|
||||
private val handle: Long = nativeCreate(networkId)
|
||||
|
||||
private suspend fun tryWriteState(): Boolean {
|
||||
requireNotNull(storageAdapter)
|
||||
return withContext(ioDispatcher) {
|
||||
val pipe = ParcelFileDescriptor.createReliablePipe()
|
||||
pipe[1].use { writeSide ->
|
||||
val storageIsReady = storageAdapter.writeAsync(pipe[0])
|
||||
val pipe = ParcelFileDescriptor.createPipe()
|
||||
val readFd = pipe[0]
|
||||
val writeFd = pipe[1]
|
||||
val storageIsReady = storageAdapter.writeAsync(readFd)
|
||||
if (storageAdapter.isRemote()) {
|
||||
readFd.close()
|
||||
}
|
||||
writeFd.use {
|
||||
if (storageIsReady) {
|
||||
val result = nativeSave(handle, writeSide.fd)
|
||||
val result = nativeSave(handle, it.fd)
|
||||
if (!result) {
|
||||
logger.e("Wallet data serialization failed")
|
||||
}
|
||||
@ -79,15 +83,18 @@ class WalletNative private constructor(
|
||||
}
|
||||
|
||||
private suspend fun readState() {
|
||||
requireNotNull(storageAdapter)
|
||||
return withContext(ioDispatcher) {
|
||||
val pipe = ParcelFileDescriptor.createReliablePipe()
|
||||
pipe[0].use { readSide ->
|
||||
pipe[1].use { writeSide ->
|
||||
storageAdapter.readAsync(writeSide)
|
||||
withContext(ioDispatcher) {
|
||||
val pipe = ParcelFileDescriptor.createPipe()
|
||||
val readFd = pipe[0]
|
||||
val writeFd = pipe[1]
|
||||
storageAdapter.readAsync(writeFd)
|
||||
if (storageAdapter.isRemote()) {
|
||||
writeFd.close()
|
||||
}
|
||||
readFd.use {
|
||||
if (!nativeLoad(handle, it.fd)) {
|
||||
throw IllegalStateException("Wallet data deserialization failed")
|
||||
}
|
||||
val result = nativeLoad(handle, readSide.fd)
|
||||
check(result) { "Wallet data deserialization failed" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ internal class WalletServiceImpl(
|
||||
callback: IWalletServiceCallbacks?,
|
||||
) {
|
||||
requireNotNull(config)
|
||||
requireNotNull(storage)
|
||||
serviceScope.launch {
|
||||
val wallet = WalletNative.fullNode(
|
||||
networkId = config.networkId,
|
||||
@ -97,6 +98,7 @@ internal class WalletServiceImpl(
|
||||
restorePoint: Long? = null,
|
||||
): IWallet {
|
||||
requireNotNull(config)
|
||||
requireNotNull(storage)
|
||||
requireNotNull(secretSpendKey)
|
||||
return WalletNative.fullNode(
|
||||
networkId = config.networkId,
|
||||
|
Loading…
Reference in New Issue
Block a user