Skip to content

Instantly share code, notes, and snippets.

@uzzu
Last active January 16, 2019 17:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uzzu/2efae3f1b52c4395062c7f348527d985 to your computer and use it in GitHub Desktop.
Save uzzu/2efae3f1b52c4395062c7f348527d985 to your computer and use it in GitHub Desktop.
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.broadcast
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.CoroutineContext
class View(ui: CoroutineContext) {
private val presenter = Presenter(
ui = ui,
io = Dispatchers.IO,
view = this,
interactor = Interactor()
)
fun process(id: Int, value: Int) {
presenter.given(id, value)
}
fun render(id: Int, result: Int) {
println("call[$id]view result: $result")
}
fun render(id: Int, e: Throwable) {
println("call[$id]view error: $e")
throw e
}
}
class Interactor {
private var count: Int = 0
suspend fun doSomething(value : Int): Int{
println("interactor: ${++count}")
delay(50)
return value * value
}
}
data class HotInvocationContext(
val mutex: Mutex = Mutex(),
val map: MutableMap<String, BroadcastChannel<*>> = mutableMapOf()
)
suspend fun <T> CoroutineScope.invokeHot(
set: HotInvocationContext,
key: String,
block: suspend () -> T
): T {
val (mutex, map) = set
return mutex.withLock {
if (map.contains(key)) {
if (!map[key]!!.isClosedForSend) {
println("channel reused")
val broadcastChannel = map[key] as BroadcastChannel<T>
return@withLock broadcastChannel.openSubscription()
} else {
println("channel has been closed")
map.remove(key)
}
}
println("channel created")
val broadcastChannel = map.getOrPut(key) {
broadcast {
val result = block()
mutex.withLock {
send(result)
map.remove(key)
}
println("channel sent")
}
} as BroadcastChannel<T>
broadcastChannel.openSubscription()
}.receive()
}
class Presenter(
ui: CoroutineContext,
private val io: CoroutineDispatcher,
private val view: View,
private val interactor: Interactor
): CoroutineScope {
private val set: HotInvocationContext = HotInvocationContext()
private val job: Job = Job()
override val coroutineContext: CoroutineContext = job + ui
fun given(id: Int, value: Int) {
launch {
runCatching {
withContext(io) {
invokeHot(set, "doSomething$value") {
interactor.doSomething(value)
}
}
}
.onSuccess { view.render(id, it) }
.onFailure { view.render(id, it) }
}
}
}
fun main() = runBlocking {
val view = View(coroutineContext)
repeat(100) {
delay(10)
println("call[$it]")
view.process(it, 5)
}
}
call[0]
channel created
call[1]
channel reused
interactor: 1
call[2]
channel reused
call[3]
channel reused
call[4]
channel reused
call[5]
channel reused
call[6]
channel sent
call[5]view result: 25
call[0]view result: 25
call[1]view result: 25
call[2]view result: 25
call[3]view result: 25
call[4]view result: 25
channel created
interactor: 2
call[7]
channel reused
call[8]
channel reused
call[9]
channel reused
channel sent
call[6]view result: 25
call[9]view result: 25
call[7]view result: 25
call[8]view result: 25
call[10]
channel created
interactor: 3
call[11]
channel reused
call[12]
channel reused
call[13]
channel reused
call[14]
channel reused
channel sent
call[12]view result: 25
call[10]view result: 25
call[11]view result: 25
call[14]view result: 25
call[13]view result: 25
call[15]
channel created
interactor: 4
call[16]
channel reused
call[17]
channel reused
call[18]
channel reused
call[19]
channel reused
call[20]
channel sent
call[18]view result: 25
call[16]view result: 25
call[17]view result: 25
call[19]view result: 25
channel created
interactor: 5
call[15]view result: 25
call[21]
channel reused
call[22]
channel reused
call[23]
channel reused
call[24]
channel reused
channel sent
call[21]view result: 25
call[22]view result: 25
call[20]view result: 25
call[24]view result: 25
call[23]view result: 25
call[25]
channel created
interactor: 6
call[26]
channel reused
call[27]
channel reused
call[28]
channel reused
call[29]
channel reused
channel sent
call[26]view result: 25
call[27]view result: 25
call[25]view result: 25
call[28]view result: 25
call[29]view result: 25
call[30]
channel created
interactor: 7
call[31]
channel reused
call[32]
channel reused
call[33]
channel reused
call[34]
channel reused
channel sent
call[31]view result: 25
call[32]view result: 25
call[33]view result: 25
call[34]view result: 25
call[30]view result: 25
call[35]
channel created
interactor: 8
call[36]
channel reused
call[37]
channel reused
call[38]
channel reused
call[39]
channel reused
channel sent
call[36]view result: 25
call[37]view result: 25
call[38]view result: 25
call[35]view result: 25
call[39]view result: 25
call[40]
channel created
interactor: 9
call[41]
channel reused
call[42]
channel reused
call[43]
channel reused
call[44]
channel reused
channel sent
call[41]view result: 25
call[44]view result: 25
call[42]view result: 25
call[43]view result: 25
call[40]view result: 25
call[45]
channel created
interactor: 10
call[46]
channel reused
call[47]
channel reused
call[48]
channel reused
call[49]
channel reused
channel sent
call[46]view result: 25
call[47]view result: 25
call[48]view result: 25
call[49]view result: 25
call[45]view result: 25
call[50]
channel created
interactor: 11
call[51]
channel reused
call[52]
channel reused
call[53]
channel reused
call[54]
channel reused
channel sent
call[52]view result: 25
call[51]view result: 25
call[53]view result: 25
call[54]view result: 25
call[50]view result: 25
call[55]
channel created
interactor: 12
call[56]
channel reused
call[57]
channel reused
call[58]
channel reused
call[59]
channel reused
channel sent
call[57]view result: 25
call[56]view result: 25
call[58]view result: 25
call[55]view result: 25
call[59]view result: 25
call[60]
channel created
interactor: 13
call[61]
channel reused
call[62]
channel reused
call[63]
channel reused
call[64]
channel reused
call[65]
channel sent
channel created
interactor: 14
call[61]view result: 25
call[62]view result: 25
call[63]view result: 25
call[64]view result: 25
call[60]view result: 25
call[66]
channel reused
call[67]
channel reused
call[68]
channel reused
call[69]
channel reused
call[70]
channel sent
channel created
interactor: 15
call[66]view result: 25
call[67]view result: 25
call[68]view result: 25
call[69]view result: 25
call[65]view result: 25
call[71]
channel reused
call[72]
channel reused
call[73]
channel reused
call[74]
channel reused
channel sent
call[72]view result: 25
call[71]view result: 25
call[73]view result: 25
call[70]view result: 25
call[74]view result: 25
call[75]
channel created
interactor: 16
call[76]
channel reused
call[77]
channel reused
call[78]
channel reused
call[79]
channel reused
channel sent
call[77]view result: 25
call[76]view result: 25
call[78]view result: 25
call[75]view result: 25
call[79]view result: 25
call[80]
channel created
interactor: 17
call[81]
channel reused
call[82]
channel reused
call[83]
channel reused
call[84]
channel reused
channel sent
call[80]view result: 25
call[83]view result: 25
call[84]view result: 25
call[81]view result: 25
call[82]view result: 25
call[85]
channel created
interactor: 18
call[86]
channel reused
call[87]
channel reused
call[88]
channel reused
call[89]
channel reused
channel sent
call[86]view result: 25
call[87]view result: 25
call[88]view result: 25
call[89]view result: 25
call[85]view result: 25
call[90]
channel created
interactor: 19
call[91]
channel reused
call[92]
channel reused
call[93]
channel reused
call[94]
channel reused
channel sent
call[91]view result: 25
call[93]view result: 25
call[92]view result: 25
call[90]view result: 25
call[94]view result: 25
call[95]
channel created
interactor: 20
call[96]
channel reused
call[97]
channel reused
call[98]
channel reused
call[99]
channel reused
channel sent
call[96]view result: 25
call[99]view result: 25
call[97]view result: 25
call[95]view result: 25
call[98]view result: 25
Process finished with exit code 0
import com.github.uzzu.kortex.hotInvocation
import com.github.uzzu.kortex.withHot
import kotlinx.coroutines.runBlocking
import okhttp3.Authenticator
import okhttp3.Request
import okhttp3.Response
import okhttp3.Route
class CustomAuthenticator : Authenticator {
private val hotInvocation = hotInvocation()
override fun authenticate(route: Route, response: Response): Request? =
runBlocking(hotInvocation) {
val authenticateResult = withHot("authenticate") {
// some authorization logic here
// :
//
}
response.request()
.newBuilder()
//
// :
//
.build()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment