mirror of
https://github.com/logos-storage/logos-storage-network-crawler.git
synced 2026-01-07 07:53:11 +00:00
Sets up asyncdataevent
This commit is contained in:
parent
f46e9837ca
commit
b5b2957209
64
codexcrawler/utils/asyncdataevent.nim
Normal file
64
codexcrawler/utils/asyncdataevent.nim
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import pkg/questionable
|
||||||
|
import pkg/questionable/results
|
||||||
|
import pkg/chronos
|
||||||
|
|
||||||
|
type
|
||||||
|
AsyncDataEventSubscription* = ref object
|
||||||
|
key: EventQueueKey
|
||||||
|
isRunning: bool
|
||||||
|
fireEvent: AsyncEvent
|
||||||
|
stopEvent: AsyncEvent
|
||||||
|
lastResult: ?!void
|
||||||
|
|
||||||
|
AsyncDataEvent*[T] = ref object
|
||||||
|
queue: AsyncEventQueue[?T]
|
||||||
|
subscriptions: seq[AsyncDataEventSubscription]
|
||||||
|
|
||||||
|
AsyncDataEventHandler*[T] = proc(data: T): Future[?!void]
|
||||||
|
|
||||||
|
proc newAsyncDataEvent*[T](): AsyncDataEvent[T] =
|
||||||
|
AsyncDataEvent[T](
|
||||||
|
queue: newAsyncEventQueue[?T](),
|
||||||
|
subscriptions: newSeq[AsyncDataEventSubscription]()
|
||||||
|
)
|
||||||
|
|
||||||
|
proc subscribe*[T](event: AsyncDataEvent[T], handler: AsyncDataEventHandler[T]): AsyncDataEventSubscription =
|
||||||
|
let subscription = AsyncDataEventSubscription(
|
||||||
|
key: event.queue.register(),
|
||||||
|
isRunning: true,
|
||||||
|
fireEvent: newAsyncEvent(),
|
||||||
|
stopEvent: newAsyncEvent()
|
||||||
|
)
|
||||||
|
|
||||||
|
proc listener() {.async.} =
|
||||||
|
while subscription.isRunning:
|
||||||
|
let items = await event.queue.waitEvents(subscription.key)
|
||||||
|
for item in items:
|
||||||
|
if data =? item:
|
||||||
|
subscription.lastResult = (await handler(data))
|
||||||
|
subscription.fireEvent.fire()
|
||||||
|
subscription.stopEvent.fire()
|
||||||
|
|
||||||
|
asyncSpawn listener()
|
||||||
|
|
||||||
|
event.subscriptions.add(subscription)
|
||||||
|
subscription
|
||||||
|
|
||||||
|
proc fire*[T](event: AsyncDataEvent[T], data: T): Future[?!void] {.async.} =
|
||||||
|
event.queue.emit(data.some)
|
||||||
|
for subscription in event.subscriptions:
|
||||||
|
await subscription.fireEvent.wait()
|
||||||
|
if err =? subscription.lastResult.errorOption:
|
||||||
|
return failure(err)
|
||||||
|
success()
|
||||||
|
|
||||||
|
proc unsubscribe*[T](event: AsyncDataEvent[T], subscription: AsyncDataEventSubscription) {.async.} =
|
||||||
|
subscription.isRunning = false
|
||||||
|
event.queue.emit(T.none)
|
||||||
|
await subscription.stopEvent.wait()
|
||||||
|
event.subscriptions.delete(event.subscriptions.find(subscription))
|
||||||
|
|
||||||
|
proc unsubscribeAll*[T](event: AsyncDataEvent[T]) {.async.} =
|
||||||
|
let all = event.subscriptions
|
||||||
|
for subscription in all:
|
||||||
|
await event.unsubscribe(subscription)
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import pkg/asynctest/chronos/unittest
|
|
||||||
|
|
||||||
suite "Example tests":
|
|
||||||
test "Example":
|
|
||||||
echo "Woo!"
|
|
||||||
check:
|
|
||||||
1 == 1
|
|
||||||
3
tests/codexcrawler/testutils.nim
Normal file
3
tests/codexcrawler/testutils.nim
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import ./utils/testasyncdataevent
|
||||||
|
|
||||||
|
{.warning[UnusedImport]: off.}
|
||||||
86
tests/codexcrawler/utils/testasyncdataevent.nim
Normal file
86
tests/codexcrawler/utils/testasyncdataevent.nim
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import pkg/chronos
|
||||||
|
import pkg/questionable
|
||||||
|
import pkg/questionable/results
|
||||||
|
import pkg/asynctest/chronos/unittest
|
||||||
|
|
||||||
|
import ../../../codexcrawler/utils/asyncdataevent
|
||||||
|
|
||||||
|
type
|
||||||
|
ExampleData = object
|
||||||
|
s: string
|
||||||
|
|
||||||
|
suite "AsyncDataEvent":
|
||||||
|
var event: AsyncDataEvent[ExampleData]
|
||||||
|
let msg = "Yeah!"
|
||||||
|
|
||||||
|
setup:
|
||||||
|
event = newAsyncDataEvent[ExampleData]()
|
||||||
|
|
||||||
|
teardown:
|
||||||
|
await event.unsubscribeAll()
|
||||||
|
|
||||||
|
test "Successful event":
|
||||||
|
var data = ""
|
||||||
|
proc eventHandler(e: ExampleData): Future[?!void] {.async.} =
|
||||||
|
data = e.s
|
||||||
|
success()
|
||||||
|
|
||||||
|
let s = event.subscribe(eventHandler)
|
||||||
|
|
||||||
|
check:
|
||||||
|
isOK(await event.fire(ExampleData(
|
||||||
|
s: msg
|
||||||
|
)))
|
||||||
|
data == msg
|
||||||
|
|
||||||
|
await event.unsubscribe(s)
|
||||||
|
|
||||||
|
test "Failed event preserves error message":
|
||||||
|
proc eventHandler(e: ExampleData): Future[?!void] {.async.} =
|
||||||
|
failure(msg)
|
||||||
|
|
||||||
|
let s = event.subscribe(eventHandler)
|
||||||
|
let fireResult = await event.fire(ExampleData(
|
||||||
|
s: "a"
|
||||||
|
))
|
||||||
|
|
||||||
|
check:
|
||||||
|
fireResult.isErr
|
||||||
|
fireResult.error.msg == msg
|
||||||
|
|
||||||
|
await event.unsubscribe(s)
|
||||||
|
|
||||||
|
test "Emits data to multiple subscribers":
|
||||||
|
var
|
||||||
|
data1 = ""
|
||||||
|
data2 = ""
|
||||||
|
data3 = ""
|
||||||
|
|
||||||
|
proc handler1(e: ExampleData): Future[?!void] {.async.} =
|
||||||
|
data1 = e.s
|
||||||
|
success()
|
||||||
|
proc handler2(e: ExampleData): Future[?!void] {.async.} =
|
||||||
|
data2 = e.s
|
||||||
|
success()
|
||||||
|
proc handler3(e: ExampleData): Future[?!void] {.async.} =
|
||||||
|
data3 = e.s
|
||||||
|
success()
|
||||||
|
|
||||||
|
let
|
||||||
|
s1 = event.subscribe(handler1)
|
||||||
|
s2 = event.subscribe(handler2)
|
||||||
|
s3 = event.subscribe(handler3)
|
||||||
|
|
||||||
|
let fireResult = await event.fire(ExampleData(
|
||||||
|
s: msg
|
||||||
|
))
|
||||||
|
|
||||||
|
check:
|
||||||
|
fireResult.isOK
|
||||||
|
data1 == msg
|
||||||
|
data2 == msg
|
||||||
|
data3 == msg
|
||||||
|
|
||||||
|
await event.unsubscribe(s1)
|
||||||
|
await event.unsubscribe(s2)
|
||||||
|
await event.unsubscribe(s3)
|
||||||
@ -1,3 +1,3 @@
|
|||||||
import ./codexcrawler/exampletest
|
import ./codexcrawler/testutils
|
||||||
|
|
||||||
{.warning[UnusedImport]: off.}
|
{.warning[UnusedImport]: off.}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user