|
@@ -43,8 +43,8 @@ class DemoInMem {
|
|
|
emitter.emit(10, CoinValue.mega)
|
|
|
|
|
|
bank.exchange(bank.getSelfAccount(), emitter, 1_300_000)
|
|
|
- (0 until 100).forEach { personMap.computeIfAbsent(UUID.randomUUID()) { id -> DemoHuman(id, Nomen.randomName()) } }
|
|
|
- personMap.keys.map { bank.addAccount(it) }.forEach {
|
|
|
+ (0 until 10).forEach { personMap.computeIfAbsent(UUID.randomUUID()) { id -> DemoHuman(id, Nomen.randomName()) } }
|
|
|
+ personMap.keys.map { bank.addAccount(it) }.subList(0, 1).forEach {
|
|
|
bank.exchange(it, bank.getSelfAccount(), 1_200 + (500 * Math.random()).roundToLong())
|
|
|
.thenRun({ log.info("exchange ok") })
|
|
|
.exceptionally({ log.error("exchange error"); null })
|
|
@@ -136,22 +136,21 @@ class GlobalBank : Bank {
|
|
|
val coinsMoreOrExact = e.from.extractMoreOrExact(e.amount)
|
|
|
val coinsExact = coinsMoreOrExact.filter { it.id != null }
|
|
|
val coinsCashback = coinsMoreOrExact.filter { it.id == null }
|
|
|
- val retry = if (coinsCashback.isNotEmpty()) {
|
|
|
+ val ok = if (coinsCashback.isNotEmpty()) {
|
|
|
if (e.to.id == selfAccount.id && e.from.id == emitter.id) {
|
|
|
- false
|
|
|
- } else if (e.from.id == selfAccount.id) {
|
|
|
true
|
|
|
+ } else if (e.from.id == selfAccount.id) {
|
|
|
+ false
|
|
|
} else {
|
|
|
TODO()
|
|
|
}
|
|
|
} else {
|
|
|
- false
|
|
|
+ true
|
|
|
}
|
|
|
- if (!retry) {
|
|
|
+ if (ok) {
|
|
|
e.to.accept(coinsExact)
|
|
|
emitter.free(coinsExact)
|
|
|
globalQueue.offerLast(ExchangeSuccessEvent(UUID.randomUUID(), e))
|
|
|
- true
|
|
|
} else {
|
|
|
e.from.accept(coinsExact)
|
|
|
coinsCashback.map { it as DemoCashbackCoin }.map { it.invert() }.forEach {
|
|
@@ -159,8 +158,8 @@ class GlobalBank : Bank {
|
|
|
val coin = emitter.extractOne(coinId)
|
|
|
e.from.accept(listOf(coin))
|
|
|
}
|
|
|
- false
|
|
|
}
|
|
|
+ ok
|
|
|
}
|
|
|
}
|
|
|
is ExchangeSuccessEvent -> {
|
|
@@ -181,12 +180,14 @@ class GlobalBank : Bank {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fun poll(e: BankEvent): Boolean = runBlocking {
|
|
|
- try {
|
|
|
- pollLater(e)
|
|
|
- } catch (t: Throwable) {
|
|
|
- log.error("error in event", t)
|
|
|
- true
|
|
|
+ fun poll(e: BankEvent): Boolean {
|
|
|
+ return runBlocking {
|
|
|
+ try {
|
|
|
+ pollLater(e)
|
|
|
+ } catch (t: Throwable) {
|
|
|
+ log.error("error in event", t)
|
|
|
+ true
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -213,13 +214,31 @@ class GlobalBank : Bank {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-abstract class ExchangeBankEvent(val eventId: UUID) : BankEvent {
|
|
|
+abstract class AbstractBankEvent(val eventId: UUID) : BankEvent {
|
|
|
|
|
|
override fun getId(): UUID {
|
|
|
return eventId
|
|
|
}
|
|
|
+
|
|
|
+ override fun equals(other: Any?): Boolean {
|
|
|
+ if (this === other) return true
|
|
|
+ if (javaClass != other?.javaClass) return false
|
|
|
+
|
|
|
+ other as AbstractBankEvent
|
|
|
+
|
|
|
+ if (eventId != other.eventId) return false
|
|
|
+
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun hashCode(): Int {
|
|
|
+ return eventId.hashCode()
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
+abstract class ExchangeBankEvent(eventId: UUID) : AbstractBankEvent(eventId)
|
|
|
+
|
|
|
class ExchangeSuccessEvent(eventId: UUID, val parentEvent: ExchangeStartEvent) : ExchangeBankEvent(eventId)
|
|
|
|
|
|
class ExchangeFailedEvent(eventId: UUID, val parentEvent: ExchangeStartEvent, val reason: String) : ExchangeBankEvent(eventId)
|
|
@@ -310,7 +329,7 @@ class DemoInMemEmitter : GlobalEmitter {
|
|
|
|
|
|
val maxEraValue: Int = CoinValue.MAX_ERA.toInt()
|
|
|
|
|
|
-class DemoCoin(val coinId: UUID, val initialValue: CoinValue, var _era: Int = 1) : Coin {
|
|
|
+class DemoCoin(val coinId: UUID, val initialValue: CoinValue, var _era: Int = 0) : Coin {
|
|
|
|
|
|
override fun getId(): UUID = coinId
|
|
|
|
|
@@ -358,8 +377,12 @@ class DemoCashbackCoin(val _value: CoinValue, val cashback: Long, val _era: Int)
|
|
|
}
|
|
|
|
|
|
fun invert(): DemoFutureCoin {
|
|
|
- val ret = DemoFutureCoin(_value, Math.max(1, maxEraValue - _era + 1))
|
|
|
- if (ret.current != value.amount + cashback)
|
|
|
+ var newEra = maxEraValue - _era
|
|
|
+ if (newEra == maxEraValue) newEra = 0
|
|
|
+ var newCurrent = value.amount + cashback
|
|
|
+ if (newCurrent == 0L) newCurrent = value.amount
|
|
|
+ val ret = DemoFutureCoin(_value, newEra)
|
|
|
+ if (ret.current != newCurrent)
|
|
|
throw IllegalArgumentException("wrong inverted coin")
|
|
|
return ret
|
|
|
}
|
|
@@ -384,7 +407,7 @@ class DemoFutureCoin(val _value: CoinValue, val _era: Int) : Coin {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-class DemoHuman(val selfId: UUID, name: String) : NaturalPerson {
|
|
|
+class DemoHuman(val selfId: UUID, val name: String) : NaturalPerson {
|
|
|
|
|
|
override fun getId(): UUID = selfId
|
|
|
|
|
@@ -467,9 +490,13 @@ class CoinUtils {
|
|
|
var totalCashback = cashback
|
|
|
do {
|
|
|
val value = CoinValue.values().filter { it.amount >= Math.abs(totalCashback) }.sortedBy { it.amount }.first()
|
|
|
- val valueByEra = (1..maxEraValue).map { era -> era to (value.amount - ((era - 1) * value.delta)) }.filter { it.second <= Math.abs(totalCashback) }.first()
|
|
|
- ret.add(DemoCashbackCoin(value, -valueByEra.second, valueByEra.first))
|
|
|
- totalCashback += valueByEra.second
|
|
|
+ val valueByEra = (0..(maxEraValue - 1)).map { era -> era to (value.amount - (era * value.delta)) }.filter { it.second <= Math.abs(totalCashback) }.firstOrNull()
|
|
|
+ if (valueByEra != null) {
|
|
|
+ ret.add(DemoCashbackCoin(value, -valueByEra.second, valueByEra.first))
|
|
|
+ totalCashback += valueByEra.second
|
|
|
+ } else {
|
|
|
+ throw RuntimeException("no value")
|
|
|
+ }
|
|
|
} while (totalCashback < 0)
|
|
|
return ret
|
|
|
}
|