mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 10:25:35 +03:00
Clean code after review
This commit is contained in:
parent
fe884dba2d
commit
d3ce4c491c
7 changed files with 67 additions and 109 deletions
|
@ -17,74 +17,23 @@ package im.vector.matrix.android.internal.database
|
|||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.internal.OsSharedRealm
|
||||
import kotlinx.coroutines.CancellableContinuation
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.Future
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
private object AsyncTransactionThreadHolder {
|
||||
|
||||
val EXECUTOR: ExecutorService by lazy {
|
||||
Executors.newSingleThreadExecutor()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AsyncTransactionRunnable(private val continuation: CancellableContinuation<Unit>,
|
||||
private val realmConfiguration: RealmConfiguration,
|
||||
private val transaction: (realm: Realm) -> Unit) : Runnable {
|
||||
|
||||
override fun run() {
|
||||
if (Thread.currentThread().isInterrupted) {
|
||||
return
|
||||
}
|
||||
var versionID: OsSharedRealm.VersionID? = null
|
||||
var exception: Throwable? = null
|
||||
|
||||
val bgRealm = Realm.getInstance(realmConfiguration)
|
||||
suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> Unit) = withContext(Dispatchers.IO) {
|
||||
Realm.getInstance(config).use { bgRealm ->
|
||||
bgRealm.beginTransaction()
|
||||
try {
|
||||
transaction(bgRealm)
|
||||
if (Thread.currentThread().isInterrupted) {
|
||||
return
|
||||
}
|
||||
if (isActive) {
|
||||
bgRealm.commitTransaction()
|
||||
versionID = bgRealm.sharedRealm.versionID
|
||||
} catch (e: Throwable) {
|
||||
exception = e
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (bgRealm.isInTransaction) {
|
||||
bgRealm.cancelTransaction()
|
||||
}
|
||||
} finally {
|
||||
bgRealm.close()
|
||||
}
|
||||
}
|
||||
val backgroundException = exception
|
||||
val backgroundVersionID = versionID
|
||||
when {
|
||||
backgroundVersionID != null -> continuation.resume(Unit)
|
||||
backgroundException != null -> continuation.resumeWithException(backgroundException)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun awaitTransaction(realmConfiguration: RealmConfiguration, transaction: (realm: Realm) -> Unit) {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
var futureTask: Future<*>? = null
|
||||
continuation.invokeOnCancellation {
|
||||
Timber.v("Cancel database transaction")
|
||||
futureTask?.cancel(true)
|
||||
}
|
||||
val runnable = AsyncTransactionRunnable(continuation, realmConfiguration, transaction)
|
||||
futureTask = AsyncTransactionThreadHolder.EXECUTOR.submit(runnable)
|
||||
}
|
||||
|
||||
}
|
|
@ -36,20 +36,20 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context)
|
|||
.build(context)
|
||||
|
||||
private val merlinsBeard = MerlinsBeard.Builder().build(context)
|
||||
private val listeners = ArrayList<Listener>()
|
||||
private val listeners = Collections.synchronizedList(ArrayList<Listener>())
|
||||
|
||||
init {
|
||||
merlin.bind()
|
||||
merlin.registerDisconnectable {
|
||||
Timber.v("On Disconnect")
|
||||
val localListeners = Collections.synchronizedList(listeners)
|
||||
val localListeners = listeners.toList()
|
||||
localListeners.forEach {
|
||||
it.onDisconnect()
|
||||
}
|
||||
}
|
||||
merlin.registerConnectable {
|
||||
Timber.v("On Connect")
|
||||
val localListeners = Collections.synchronizedList(listeners)
|
||||
val localListeners = listeners.toList()
|
||||
localListeners.forEach {
|
||||
it.onConnect()
|
||||
}
|
||||
|
|
|
@ -20,17 +20,16 @@ import android.content.Context
|
|||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.send.SendState
|
||||
import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult
|
||||
import im.vector.matrix.android.internal.util.awaitCallback
|
||||
import im.vector.matrix.android.internal.worker.SessionWorkerParams
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import im.vector.matrix.android.internal.worker.getSessionComponent
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
||||
|
@ -71,44 +70,30 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
|||
}
|
||||
localEchoUpdater.updateSendState(localEvent.eventId, SendState.ENCRYPTING)
|
||||
|
||||
// TODO Better async handling
|
||||
val latch = CountDownLatch(1)
|
||||
|
||||
var result: MXEncryptEventContentResult? = null
|
||||
var error: Throwable? = null
|
||||
|
||||
val localMutableContent = HashMap(localEvent.content)
|
||||
params.keepKeys?.forEach {
|
||||
localMutableContent.remove(it)
|
||||
}
|
||||
|
||||
var error: Throwable? = null
|
||||
var result: MXEncryptEventContentResult? = null
|
||||
try {
|
||||
crypto.encryptEventContent(localMutableContent, localEvent.type, params.roomId, object : MatrixCallback<MXEncryptEventContentResult> {
|
||||
override fun onSuccess(data: MXEncryptEventContentResult) {
|
||||
result = data
|
||||
latch.countDown()
|
||||
result = awaitCallback {
|
||||
crypto.encryptEventContent(localMutableContent, localEvent.type, params.roomId, it)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
error = failure
|
||||
latch.countDown()
|
||||
} catch (throwable: Throwable) {
|
||||
error = throwable
|
||||
}
|
||||
})
|
||||
} catch (e: Throwable) {
|
||||
error = e
|
||||
latch.countDown()
|
||||
}
|
||||
latch.await()
|
||||
|
||||
if (result != null) {
|
||||
val modifiedContent = HashMap(result?.eventContent)
|
||||
val modifiedContent = HashMap(result.eventContent)
|
||||
params.keepKeys?.forEach { toKeep ->
|
||||
localEvent.content?.get(toKeep)?.let {
|
||||
//put it back in the encrypted thing
|
||||
modifiedContent[toKeep] = it
|
||||
}
|
||||
}
|
||||
val safeResult = result!!.copy(eventContent = modifiedContent)
|
||||
val safeResult = result.copy(eventContent = modifiedContent)
|
||||
val encryptedEvent = localEvent.copy(
|
||||
type = safeResult.eventType,
|
||||
content = safeResult.eventContent
|
||||
|
@ -122,7 +107,8 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters)
|
|||
}
|
||||
localEchoUpdater.updateSendState(localEvent.eventId, sendState)
|
||||
//always return success, or the chain will be stuck for ever!
|
||||
val nextWorkerParams = SendEventWorker.Params(params.userId, params.roomId, localEvent, error?.localizedMessage ?: "Error")
|
||||
val nextWorkerParams = SendEventWorker.Params(params.userId, params.roomId, localEvent, error?.localizedMessage
|
||||
?: "Error")
|
||||
return Result.success(WorkerParamsFactory.toData(nextWorkerParams))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ internal data class ConfigurableTask<PARAMS, RESULT>(
|
|||
val retryCount: Int,
|
||||
val callback: MatrixCallback<RESULT>
|
||||
|
||||
) : Task<PARAMS, RESULT> {
|
||||
) : Task<PARAMS, RESULT> by task {
|
||||
|
||||
|
||||
class Builder<PARAMS, RESULT>(
|
||||
|
@ -66,11 +66,6 @@ internal data class ConfigurableTask<PARAMS, RESULT>(
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
override suspend fun execute(params: PARAMS): RESULT {
|
||||
return task.execute(params)
|
||||
}
|
||||
|
||||
fun executeBy(taskExecutor: TaskExecutor): Cancelable {
|
||||
return taskExecutor.execute(this)
|
||||
}
|
||||
|
|
|
@ -18,16 +18,12 @@ package im.vector.matrix.android.internal.task
|
|||
|
||||
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.api.util.CancelableBag
|
||||
import im.vector.matrix.android.internal.di.MatrixScope
|
||||
import im.vector.matrix.android.internal.extensions.foldToCallback
|
||||
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
@ -36,11 +32,11 @@ import kotlin.coroutines.EmptyCoroutineContext
|
|||
internal class TaskExecutor @Inject constructor(private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val networkConnectivityChecker: NetworkConnectivityChecker) {
|
||||
|
||||
private val cancelableBag = CancelableBag()
|
||||
private val executorScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
fun <PARAMS, RESULT> execute(task: ConfigurableTask<PARAMS, RESULT>): Cancelable {
|
||||
|
||||
val job = GlobalScope.launch(task.callbackThread.toDispatcher()) {
|
||||
val job = executorScope.launch(task.callbackThread.toDispatcher()) {
|
||||
val resultOrFailure = runCatching {
|
||||
withContext(task.executionThread.toDispatcher()) {
|
||||
Timber.v("Enqueue task $task")
|
||||
|
@ -60,14 +56,11 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers
|
|||
}
|
||||
.foldToCallback(task.callback)
|
||||
}
|
||||
return CancelableCoroutine(job).also {
|
||||
cancelableBag += it
|
||||
}
|
||||
return CancelableCoroutine(job)
|
||||
}
|
||||
|
||||
fun cancelAll() = synchronized(this) {
|
||||
cancelableBag.cancel()
|
||||
}
|
||||
fun cancelAll() = executorScope.coroutineContext.cancelChildren()
|
||||
|
||||
|
||||
private suspend fun <T> retry(
|
||||
times: Int = Int.MAX_VALUE,
|
||||
|
|
|
@ -22,7 +22,7 @@ import io.realm.Realm
|
|||
import io.realm.RealmModel
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
internal suspend fun Monarchy.awaitTransaction(transaction: (realm: Realm) -> Unit) {
|
||||
internal suspend fun Monarchy.awaitTransaction(transaction: suspend (realm: Realm) -> Unit) {
|
||||
awaitTransaction(realmConfiguration, transaction)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* 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.
|
||||
|
||||
*/
|
||||
package im.vector.matrix.android.internal.util
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
suspend inline fun <T> awaitCallback(crossinline callback: (MatrixCallback<T>) -> Unit) = suspendCoroutine<T> { cont ->
|
||||
callback(object : MatrixCallback<T> {
|
||||
override fun onFailure(failure: Throwable) {
|
||||
cont.resumeWithException(failure)
|
||||
}
|
||||
|
||||
override fun onSuccess(data: T) {
|
||||
cont.resume(data)
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue