mirror of
https://github.com/logos-storage/nim-ethers.git
synced 2026-01-02 13:43:06 +00:00
128 lines
4.0 KiB
Nim
128 lines
4.0 KiB
Nim
import std/tables
|
|
import std/sequtils
|
|
import ./basics
|
|
import ./provider
|
|
import ./subscriptions/blocksubscriber
|
|
import ./subscriptions/logsbloom
|
|
|
|
type
|
|
Subscriptions* = ref object
|
|
provider: Provider
|
|
blockSubscriber: BlockSubscriber
|
|
blockSubscriptions: Table[SubscriptionId, BlockHandler]
|
|
logSubscriptions: Table[SubscriptionId, (EventFilter, LogHandler)]
|
|
nextSubscriptionId: int
|
|
LocalSubscription* = ref object of Subscription
|
|
subscriptions: Subscriptions
|
|
id: SubscriptionId
|
|
SubscriptionId = int
|
|
|
|
func len*(subscriptions: Subscriptions): int =
|
|
subscriptions.blockSubscriptions.len + subscriptions.logSubscriptions.len
|
|
|
|
proc subscribe*(
|
|
subscriptions: Subscriptions,
|
|
onBlock: BlockHandler
|
|
): Future[Subscription] {.async:(raises:[ProviderError, CancelledError]).} =
|
|
let id = subscriptions.nextSubscriptionId
|
|
inc subscriptions.nextSubscriptionId
|
|
subscriptions.blockSubscriptions[id] = onBlock
|
|
await subscriptions.blockSubscriber.start()
|
|
LocalSubscription(subscriptions: subscriptions, id: id)
|
|
|
|
proc subscribe*(
|
|
subscriptions: Subscriptions,
|
|
filter: EventFilter,
|
|
onLog: LogHandler
|
|
): Future[Subscription] {.async:(raises:[ProviderError, CancelledError]).} =
|
|
let id = subscriptions.nextSubscriptionId
|
|
inc subscriptions.nextSubscriptionId
|
|
subscriptions.logSubscriptions[id] = (filter, onLog)
|
|
await subscriptions.blockSubscriber.start()
|
|
LocalSubscription(subscriptions: subscriptions, id: id)
|
|
|
|
method unsubscribe*(
|
|
subscription: LocalSubscription
|
|
) {.async:(raises:[ProviderError, CancelledError]).} =
|
|
let subscriptions = subscription.subscriptions
|
|
let id = subscription.id
|
|
subscriptions.logSubscriptions.del(id)
|
|
subscriptions.blockSubscriptions.del(id)
|
|
if subscriptions.len == 0:
|
|
await subscriptions.blockSubscriber.stop()
|
|
|
|
proc getLogs(
|
|
subscriptions: Subscriptions,
|
|
filter: EventFilter,
|
|
blockTag: BlockTag
|
|
): Future[seq[Log]] {.async:(raises:[ProviderError, CancelledError]).} =
|
|
let logFilter = Filter()
|
|
logFilter.address = filter.address
|
|
logFilter.topics = filter.topics
|
|
logFilter.fromBlock = blockTag
|
|
logFilter.toBlock = blockTag
|
|
await subscriptions.provider.getLogs(logFilter)
|
|
|
|
proc getLogs(
|
|
subscriptions: Subscriptions,
|
|
blck: Block
|
|
): Future[Table[SubscriptionId, seq[Log]]] {.
|
|
async:(raises:[ProviderError, CancelledError])
|
|
.} =
|
|
without blockNumber =? blck.number:
|
|
return
|
|
let blockTag = BlockTag.init(blockNumber)
|
|
let ids = toSeq(subscriptions.logSubscriptions.keys)
|
|
for id in ids:
|
|
without (filter, _) =? subscriptions.logSubscriptions.?[id]:
|
|
continue
|
|
if filter notin blck:
|
|
continue
|
|
result[id] = await subscriptions.getLogs(filter, blockTag)
|
|
|
|
proc processBlock(
|
|
subscriptions: Subscriptions,
|
|
blockNumber: BlockNumber
|
|
): Future[bool] {.async:(raises:[CancelledError]).} =
|
|
try:
|
|
let blockTag = BlockTag.init(blockNumber)
|
|
without blck =? await subscriptions.provider.getBlock(blockTag):
|
|
return false
|
|
if blck.logsBloom.isNone:
|
|
return false
|
|
let logs = await subscriptions.getLogs(blck)
|
|
for handler in subscriptions.blockSubscriptions.values:
|
|
handler(success blck)
|
|
for (id, logs) in logs.pairs:
|
|
if (_, handler) =? subscriptions.logSubscriptions.?[id]:
|
|
for log in logs:
|
|
handler(success log)
|
|
return true
|
|
except ProviderError:
|
|
return false
|
|
|
|
func new*(
|
|
_: type Subscriptions,
|
|
provider: Provider,
|
|
pollingInterval: Duration
|
|
): Subscriptions =
|
|
let subscriptions = Subscriptions()
|
|
proc processBlock(
|
|
blockNumber: BlockNumber
|
|
): Future[bool] {.async:(raises:[CancelledError]).} =
|
|
await subscriptions.processBlock(blockNumber)
|
|
let blockSubscriber = BlockSubscriber.new(
|
|
provider,
|
|
processBlock,
|
|
pollingInterval
|
|
)
|
|
subscriptions.provider = provider
|
|
subscriptions.blockSubscriber = blockSubscriber
|
|
subscriptions
|
|
|
|
proc close*(subscriptions: Subscriptions) {.async:(raises:[]).} =
|
|
await subscriptions.blockSubscriber.stop()
|
|
|
|
proc update*(subscriptions: Subscriptions) =
|
|
subscriptions.blockSubscriber.update()
|