Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* All credit goes to https://github.com/gregopet for inspiration!
*/
package ratpack.kotlin.coroutines
import kotlinx.coroutines.AbstractCoroutine
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers.Unconfined
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import ratpack.exec.Blocking
import ratpack.exec.Downstream
import ratpack.exec.ExecSpec
import ratpack.exec.Promise
import ratpack.handling.Context
import ratpack.kotlin.handling.KContext
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
/**
*
* Runs the given block on the request thread.
*
* Frees the request thread as soon as the first await (or any other suspendable function) is encountered and
* continues work on another appropriate thread after the operation finishes.
*
* @param block The block to execute
*/
fun Context.async(block: suspend CoroutineScope.() -> Any?) {
GlobalScope.launch(Unconfined, CoroutineStart.UNDISPATCHED) {
try {
block(this)
} catch (t: Throwable) {
[email protected](t)
}
}
}
fun KContext.async(cb: suspend CoroutineScope.() -> Any?) = this.context.async(cb)
/**
* Returns the result of the [block] as soon as the blocking computation completes. The request thread is released
* during the blocking operation.
*/
suspend fun await(block: () -> T): T = Blocking.get(block).await()
/**
* Resolves the promise and returns its value as soon as the blocking computation completes. The request thread is released
* during the blocking operation.
*/
suspend fun Promise.await(fork: Boolean = false, onStart: (ExecSpec) -> Unit = {}): T = suspendCancellableCoroutine { cont: CancellableContinuation ->
if (fork) { this.fork(onStart) } else { this }.onError { cont.resumeWithException(it) }.then { cont.resume(it) }
}
/**
* Convert this [Promise] into a [Deferred] by launching an async coroutine, inside of which
* the promised value will be resolved.
*/
fun Promise.defer(fork: Boolean = false, onStart: (ExecSpec) -> Unit = {}): Deferred {
return GlobalScope.async(Unconfined, CoroutineStart.UNDISPATCHED) {
[email protected](fork, onStart)
}
}
/**
* Run a block of code asynchronously in a new coroutine, but do not start it until it is referenced.
*/
fun lazyAsync(mode: LazyThreadSafetyMode = LazyThreadSafetyMode.NONE, block: suspend CoroutineScope.() -> T): Lazy> = lazy(mode) { async(block = block) }
/**
* Convert this block into a [Deferred] by launching an async coroutine, inside of which
* the block will be resolved.
*/
fun async(start: CoroutineStart = CoroutineStart.UNDISPATCHED, block: suspend CoroutineScope.() -> T): Deferred {
return GlobalScope.async(Unconfined, start, block = block)
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, onStart: (ExecSpec) -> Unit = {}, zipper: (T1, T2) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
return zipper(d1.await(), d2.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
onStart: (ExecSpec) -> Unit = {}, zipper: (T1, T2, T3) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
p4: Promise, onStart: (ExecSpec) -> Unit = {}, zipper: (T1, T2, T3, T4) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
val d4 = p4.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await(), d4.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
p4: Promise, p5: Promise, onStart: (ExecSpec) -> Unit = {},
zipper: (T1, T2, T3, T4, T5) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
val d4 = p4.defer(true, onStart)
val d5 = p5.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await(), d4.await(), d5.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
p4: Promise, p5: Promise, p6: Promise,
onStart: (ExecSpec) -> Unit = {}, zipper: (T1, T2, T3, T4, T5, T6) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
val d4 = p4.defer(true, onStart)
val d5 = p5.defer(true, onStart)
val d6 = p6.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await(), d4.await(), d5.await(), d6.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
p4: Promise, p5: Promise, p6: Promise,
p7: Promise, onStart: (ExecSpec) -> Unit = {},
zipper: (T1, T2, T3, T4, T5, T6, T7) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
val d4 = p4.defer(true, onStart)
val d5 = p5.defer(true, onStart)
val d6 = p6.defer(true, onStart)
val d7 = p7.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await(), d4.await(), d5.await(), d6.await(), d7.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
p4: Promise, p5: Promise, p6: Promise,
p7: Promise, p8: Promise, onStart: (ExecSpec) -> Unit = {},
zipper: (T1, T2, T3, T4, T5, T6, T7, T8) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
val d4 = p4.defer(true, onStart)
val d5 = p5.defer(true, onStart)
val d6 = p6.defer(true, onStart)
val d7 = p7.defer(true, onStart)
val d8 = p8.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await(), d4.await(), d5.await(), d6.await(), d7.await(), d8.await())
}
/**
* Consume the promises in parallel and execute the zipper function on the results.
*/
suspend fun zip(p1: Promise, p2: Promise, p3: Promise,
p4: Promise, p5: Promise, p6: Promise,
p7: Promise, p8: Promise, p9: Promise,
onStart: (ExecSpec) -> Unit = {}, zipper: (T1, T2, T3, T4, T5, T6, T7, T8, T9) -> R): R {
val d1 = p1.defer(true, onStart)
val d2 = p2.defer(true, onStart)
val d3 = p3.defer(true, onStart)
val d4 = p4.defer(true, onStart)
val d5 = p5.defer(true, onStart)
val d6 = p6.defer(true, onStart)
val d7 = p7.defer(true, onStart)
val d8 = p8.defer(true, onStart)
val d9 = p9.defer(true, onStart)
return zipper(d1.await(), d2.await(), d3.await(), d4.await(), d5.await(), d6.await(), d7.await(), d8.await(), d9.await())
}
/**
* Creates a [promise][Promise] that will run a given [block] in a coroutine.
*/
fun CoroutineScope.promise(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): Promise = Promise.async { downstream ->
launch(context, CoroutineStart.UNDISPATCHED) {
try {
downstream.success(block(this))
} catch (e: Exception) {
downstream.error(e)
}
}
}
/**
* Creates a [promise][Promise] that will run a given [block] in a coroutine.
*/
fun promise(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): Promise = Promise.async { downstream ->
val coroutine = PromiseCoroutine(context, downstream)
coroutine.start(CoroutineStart.UNDISPATCHED, coroutine, block)
}
private class PromiseCoroutine(
parentContext: CoroutineContext,
private val downstream: Downstream
) : AbstractCoroutine(parentContext, true) {
override val cancelsParent: Boolean get() = true
override fun onCompleted(value: T) {
downstream.success(value)
}
override fun onCancelled(cause: Throwable, handled: Boolean) {
downstream.error(cause)
}
}