Daniel Pitts
07/29/2024, 8:23 PMsuspend fun CoroutineScope.startThing(action: Deferred<String>): String
🧵Daniel Pitts
07/29/2024, 8:24 PMpackage com.stochastictinkr
import kotlinx.coroutines.*
fun CoroutineScope.launchAction(action: String): String {
launch {
delay(1000)
println("$action completed")
}
return "$action started"
}
suspend fun startJobSuspend(action: Deferred<String>): String {
val string = action.await()
return coroutineScope { launchAction(string) }
}
suspend fun CoroutineScope.startJobSuspendScoped(action: Deferred<String>): String {
val string = action.await()
return launchAction(string)
}
fun CoroutineScope.startJobDeferred(action: Deferred<String>): Deferred<String> {
return async {
launchAction(action.await())
}
}
fun main() = runBlocking {
println("About to start main")
val main = launchAction("main")
println(main)
println("About to start suspend-action")
val suspend = startJobSuspend(async { "suspend-action" })
println(suspend)
println("About to start suspend-scoped-action")
val suspendScoped = startJobSuspendScoped(async { "suspend-scoped-action" })
println(suspendScoped)
println("About to start deferred-action")
val deferred = startJobDeferred(async { "deferred-action" })
println(deferred.await())
}
streetsofboston
07/29/2024, 8:26 PMCoroutineScope
receiver for the suspend version of startThing
?Daniel Pitts
07/29/2024, 8:26 PMstreetsofboston
07/29/2024, 8:27 PMsuspend
function, you can call the function coroutineScope { /* this is a CoroutineScope*/... }
, in which the CoroutineScope of the calling function will be provided.Daniel Pitts
07/29/2024, 8:28 PMstreetsofboston
07/29/2024, 8:29 PMsuspend
fun to resume before the Deferred 'await' call has finished?Daniel Pitts
07/29/2024, 8:30 PMstreetsofboston
07/29/2024, 8:30 PMstartThing
🙂Daniel Pitts
07/29/2024, 8:31 PMstreetsofboston
07/29/2024, 8:33 PMfun CoroutineScope.startThing(action: String): String
will return immediately.
A call coroutineScope { }
calling that function will only resume until that launch
has finished.Daniel Pitts
07/29/2024, 8:36 PMstreetsofboston
07/29/2024, 8:36 PMstartJobSuspendScoped
to possibly resume before the launchAction
has finished?Daniel Pitts
07/29/2024, 8:36 PMlaunch
within launchAction
has finished..Daniel Pitts
07/29/2024, 8:37 PMstreetsofboston
07/29/2024, 8:40 PMstartJobSuspendScoped
marked as suspend
only so that you can call the await
on the action
?Daniel Pitts
07/29/2024, 8:40 PMDaniel Pitts
07/29/2024, 8:51 PMstartJobDeferred
doesn't do what I want. Only startJobSuspendScoped
does what I expect.streetsofboston
07/29/2024, 8:56 PMsuspend-scoped-action started
suspend-scoped-action completed
Daniel Pitts
07/29/2024, 8:56 PMstreetsofboston
07/29/2024, 9:14 PMstartJobSuspendScoped
needs to suspend to await the action string, but should launch the action separately. This means they have separate lifecycles.
suspend fun CoroutineScope.startJobSuspendScoped(action: Deferred<String>): String {
val string = action.await()
return launchAction(string)
}
will accomplish this, but you get the warning about it being both suspend and having a CoroutineScope.Daniel Pitts
07/29/2024, 9:14 PMDaniel Pitts
07/29/2024, 9:14 PMstreetsofboston
07/29/2024, 9:15 PMstreetsofboston
07/29/2024, 9:17 PMval result = launchAction(async { "suspend-scoped-action" }.await())
println(result)
streetsofboston
07/29/2024, 9:17 PMawait
is called in the calling function and then the launchAction is done asynchronously.Daniel Pitts
07/29/2024, 9:18 PMstreetsofboston
07/29/2024, 9:18 PMstreetsofboston
07/29/2024, 9:19 PMDaniel Pitts
07/29/2024, 9:19 PMstreetsofboston
07/29/2024, 9:20 PMlauncAction
inside an object that has its own CoroutineScopeDaniel Pitts
07/29/2024, 9:20 PMCoroutineScope.connect(existingConnection: Connection)
and CoroutineScope.connect(hostName: String)
Daniel Pitts
07/29/2024, 9:23 PMfun CoroutineScope.telnet(
readWriteCloser: ReadWriteCloser,
virtualTerminal: NetworkVirtualTerminal,
options: suspend OptionsConfiguration.() -> Unit
): Telnet {
val (reader, writer, closer) = readWriteCloser
val output = TelnetOutput(writer)
val optionNegotiator = OptionNegotiator(output)
launch {
optionNegotiator.options.options()
TelnetInputProcessor(reader, optionNegotiator, virtualTerminal).processInput()
}
return Telnet(optionNegotiator, output, closer)
}
streetsofboston
07/29/2024, 9:26 PMclass Action(private val scope: CoroutineScope = CoroutineScope(Job())) {
fun launch(action: String): String {
scope.launch {
delay(1000)
println("$action completed")
}
return "$action started"
}
}
suspend fun startJobSuspendUsingAction(action: Deferred<String>): String {
val string = action.await()
return Action().launch(string)
}
Daniel Pitts
07/29/2024, 9:34 PMsuspend fun telnet(
coroutineScope: CoroutineScope = CoroutineScope(Job()),
remoteHost: String,
remotePort: Int = 23,
socketConfiguration: suspend SocketChannel.() -> Unit = {},
virtualTerminal: NetworkVirtualTerminal,
options: suspend OptionsConfiguration.() -> Unit = {},
): Telnet {
SelectorProvider.provider()
val socket = SocketChannel.open().apply {
configureBlocking(false)
socketConfiguration()
awaitConnect(inetSocketAddress(remoteHost, remotePort))
}
return coroutineScope.telnet(virtualTerminal, socket, options)
}