mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
incorporate androidlib
This commit is contained in:
parent
20cf3f0825
commit
5eb5cd1421
63 changed files with 1451 additions and 108 deletions
|
|
@ -0,0 +1,29 @@
|
|||
package com.geeksville.mesh.concurrent
|
||||
|
||||
import com.geeksville.mesh.util.Exceptions
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
private val errorHandler =
|
||||
CoroutineExceptionHandler { _, exception ->
|
||||
Exceptions.report(
|
||||
exception,
|
||||
"MeshService-coroutine",
|
||||
"coroutine-exception"
|
||||
)
|
||||
}
|
||||
|
||||
/// Wrap launch with an exception handler, FIXME, move into a utility lib
|
||||
fun CoroutineScope.handledLaunch(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
) = this.launch(
|
||||
context = context + com.geeksville.mesh.concurrent.errorHandler,
|
||||
start = start,
|
||||
block = block
|
||||
)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.geeksville.mesh.concurrent
|
||||
|
||||
import com.geeksville.mesh.android.Logging
|
||||
|
||||
|
||||
/**
|
||||
* Sometimes when starting services we face situations where messages come in that require computation
|
||||
* but we can't do that computation yet because we are still waiting for some long running init to
|
||||
* complete.
|
||||
*
|
||||
* This class lets you queue up closures to run at a later date and later on you can call run() to
|
||||
* run all the previously queued work.
|
||||
*/
|
||||
class DeferredExecution : Logging {
|
||||
private val queue = mutableListOf<() -> Unit>()
|
||||
|
||||
/// Queue some new work
|
||||
fun add(fn: () -> Unit) {
|
||||
queue.add(fn)
|
||||
}
|
||||
|
||||
/// run all work in the queue and clear it to be ready to accept new work
|
||||
fun run() {
|
||||
debug("Running deferred execution numjobs=${queue.size}")
|
||||
queue.forEach {
|
||||
it()
|
||||
}
|
||||
queue.clear()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package com.geeksville.mesh.concurrent
|
||||
|
||||
import com.geeksville.mesh.android.Logging
|
||||
|
||||
|
||||
/**
|
||||
* A deferred execution object (with various possible implementations)
|
||||
*/
|
||||
interface Continuation<in T> : Logging {
|
||||
abstract fun resume(res: Result<T>)
|
||||
|
||||
// syntactic sugar
|
||||
|
||||
fun resumeSuccess(res: T) = resume(Result.success(res))
|
||||
fun resumeWithException(ex: Throwable) = try {
|
||||
resume(Result.failure(ex))
|
||||
} catch (ex: Throwable) {
|
||||
// errormsg("Ignoring $ex while resuming, because we are the ones who threw it")
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An async continuation that just calls a callback when the result is available
|
||||
*/
|
||||
class CallbackContinuation<in T>(private val cb: (Result<T>) -> Unit) : Continuation<T> {
|
||||
override fun resume(res: Result<T>) = cb(res)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a blocking/threaded version of coroutine Continuation
|
||||
*
|
||||
* A little bit ugly, but the coroutine version has a nasty internal bug that showed up
|
||||
* in my SyncBluetoothDevice so I needed a quick workaround.
|
||||
*/
|
||||
class SyncContinuation<T> : Continuation<T> {
|
||||
|
||||
private val mbox = java.lang.Object()
|
||||
private var result: Result<T>? = null
|
||||
|
||||
override fun resume(res: Result<T>) {
|
||||
synchronized(mbox) {
|
||||
result = res
|
||||
mbox.notify()
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the result (or throw an exception)
|
||||
fun await(timeoutMsecs: Long = 0): T {
|
||||
synchronized(mbox) {
|
||||
val startT = System.currentTimeMillis()
|
||||
while (result == null) {
|
||||
mbox.wait(timeoutMsecs)
|
||||
|
||||
if (timeoutMsecs > 0 && ((System.currentTimeMillis() - startT) >= timeoutMsecs))
|
||||
throw Exception("SyncContinuation timeout")
|
||||
}
|
||||
|
||||
val r = result
|
||||
if (r != null)
|
||||
return r.getOrThrow()
|
||||
else
|
||||
throw Exception("This shouldn't happen")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an init function which is responsible for saving our continuation so that some
|
||||
* other thread can call resume or resume with exception.
|
||||
*
|
||||
* Essentially this is a blocking version of the (buggy) coroutine suspendCoroutine
|
||||
*/
|
||||
fun <T> suspend(timeoutMsecs: Long = -1, initfn: (SyncContinuation<T>) -> Unit): T {
|
||||
val cont = SyncContinuation<T>()
|
||||
|
||||
// First call the init funct
|
||||
initfn(cont)
|
||||
|
||||
// Now wait for the continuation to finish
|
||||
return cont.await(timeoutMsecs)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue