diff --git a/dagger/market.nim b/dagger/market.nim index 715a008b..7feb11eb 100644 --- a/dagger/market.nim +++ b/dagger/market.nim @@ -46,5 +46,5 @@ method subscribeSelection*(market: Market, Future[Subscription] {.base, async.} = raiseAssert("not implemented") -method unsubscribe*(subscription: Subscription) {.base, async.} = +method unsubscribe*(subscription: Subscription) {.base, async, upraises:[].} = raiseAssert("not implemented") diff --git a/dagger/sales.nim b/dagger/sales.nim index 864da0be..dc3002f0 100644 --- a/dagger/sales.nim +++ b/dagger/sales.nim @@ -13,14 +13,16 @@ const DefaultOfferExpiryInterval = (10 * 60).u256 type Sales* = ref object market: Market - available*: seq[Availability] subscription: ?Subscription + available*: seq[Availability] offerExpiryInterval*: UInt256 + onSale*: OnSale Availability* = object id*: array[32, byte] size*: uint64 duration*: uint64 minPrice*: UInt256 + OnSale = proc(offer: StorageOffer) {.gcsafe, upraises: [].} func new*(_: type Sales, market: Market): Sales = Sales(market: market, offerExpiryInterval: DefaultOfferExpiryInterval) @@ -56,10 +58,20 @@ proc createOffer(sales: Sales, ) proc handleRequest(sales: Sales, request: StorageRequest) {.async.} = - if availability =? sales.findAvailability(request): - sales.remove(availability) - let offer = sales.createOffer(request, availability) - await sales.market.offerStorage(offer) + without availability =? sales.findAvailability(request): + return + + sales.remove(availability) + + let offer = sales.createOffer(request, availability) + await sales.market.offerStorage(offer) + + var subscription: ?Subscription + proc onSelect(offerId: array[32, byte]) {.gcsafe, upraises:[].} = + if subscription =? subscription: + asyncSpawn subscription.unsubscribe() + sales.onSale(offer) + subscription = some await sales.market.subscribeSelection(request.id, onSelect) proc start*(sales: Sales) = doAssert sales.subscription.isNone, "Sales already started" diff --git a/tests/dagger/helpers/mockmarket.nim b/tests/dagger/helpers/mockmarket.nim index a4d1c474..2ad925c9 100644 --- a/tests/dagger/helpers/mockmarket.nim +++ b/tests/dagger/helpers/mockmarket.nim @@ -1,5 +1,6 @@ import std/sequtils import std/heapqueue +import pkg/questionable import pkg/dagger/market export market @@ -15,6 +16,7 @@ type Subscriptions = object onRequest: seq[RequestSubscription] onOffer: seq[OfferSubscription] + onSelect: seq[SelectSubscription] RequestSubscription* = ref object of Subscription market: MockMarket callback: OnRequest @@ -22,23 +24,39 @@ type market: MockMarket requestId: array[32, byte] callback: OnOffer + SelectSubscription* = ref object of Subscription + market: MockMarket + requestId: array[32, byte] + callback: OnSelect Expiry = object future: Future[void] expiry: UInt256 method requestStorage*(market: MockMarket, request: StorageRequest) {.async.} = market.requested.add(request) - for subscription in market.subscriptions.onRequest: + let subscriptions = market.subscriptions.onRequest + for subscription in subscriptions: subscription.callback(request) method offerStorage*(market: MockMarket, offer: StorageOffer) {.async.} = market.offered.add(offer) - for subscription in market.subscriptions.onOffer: + let subscriptions = market.subscriptions.onOffer + for subscription in subscriptions: if subscription.requestId == offer.requestId: subscription.callback(offer) +proc findOffer(market: MockMarket, id: array[32, byte]): ?StorageOffer = + for offer in market.offered: + if offer.id == id: + return some offer + method selectOffer*(market: MockMarket, id: array[32, byte]) {.async.} = market.selected.add(id) + let subscriptions = market.subscriptions.onSelect + for subscription in subscriptions: + if offer =? market.findOffer(id): + if subscription.requestId == offer.requestId: + subscription.callback(id) method subscribeRequests*(market: MockMarket, callback: OnRequest): @@ -62,12 +80,27 @@ method subscribeOffers*(market: MockMarket, market.subscriptions.onOffer.add(subscription) return subscription +method subscribeSelection*(market: MockMarket, + requestId: array[32, byte], + callback: OnSelect): + Future[Subscription] {.async.} = + let subscription = SelectSubscription( + market: market, + requestId: requestId, + callback: callback + ) + market.subscriptions.onSelect.add(subscription) + return subscription + method unsubscribe*(subscription: RequestSubscription) {.async.} = subscription.market.subscriptions.onRequest.keepItIf(it != subscription) method unsubscribe*(subscription: OfferSubscription) {.async.} = subscription.market.subscriptions.onOffer.keepItIf(it != subscription) +method unsubscribe*(subscription: SelectSubscription) {.async.} = + subscription.market.subscriptions.onSelect.keepItIf(it != subscription) + func `<`(a, b: Expiry): bool = a.expiry < b.expiry diff --git a/tests/dagger/testsales.nim b/tests/dagger/testsales.nim index 1b3e1e09..16967e5d 100644 --- a/tests/dagger/testsales.nim +++ b/tests/dagger/testsales.nim @@ -74,3 +74,17 @@ suite "Sales": await market.requestStorage(request) check market.offered[0].expiry == now + sales.offerExpiryInterval sales.stop() + + test "call onSale when offer is selected": + let availability = Availability.init(size=100, duration=60, minPrice=42.u256) + sales.add(availability) + var selectedOffer: StorageOffer + sales.onSale = proc(offer: StorageOffer) = + selectedOffer = offer + sales.start() + let request = StorageRequest(duration:60.u256, size:100.u256, maxPrice:42.u256) + await market.requestStorage(request) + let offer = market.offered[0] + await market.selectOffer(offer.id) + check selectedOffer == offer + sales.stop()