add basic peer lifecycle

This commit is contained in:
gmega 2023-08-29 17:30:08 -03:00
parent ee3cc72213
commit df3bd77384
7 changed files with 113 additions and 2 deletions

View File

@ -2,6 +2,7 @@ import std/options
import std/random
import std/hashes
import sequtils
import sugar
import ./types
import ./message
@ -15,6 +16,33 @@ export protocol
export eventdrivenengine
export Peer
type
PeerLifecycleChange* = ref object of SchedulableEvent
peer: Peer
network: Network
event: LifecycleEventType
method atScheduledTime*(self: PeerLifecycleChange,
engine: EventDrivenEngine): void =
let peer = self.peer
let oldState = peer.up
# XXX We're somewhat lax with state machine transitions and will allow
# self-transitions...
let newState = case self.event:
of started, up:
true
of down:
false
peer.up = newState
# ... but self-transitions do not get reported downstream.
if oldState != newState:
self.peer.protocols.values.toSeq.apply(p =>
p.onLifecycleEventType(self.peer, self.event, self.network))
proc getProtocol*(self: Peer, id: string): Option[Protocol] =
if self.protocols.hasKey(id):
return self.protocols[id].some
@ -34,6 +62,21 @@ proc deliver*(self: Peer, message: Message, engine: EventDrivenEngine,
self.deliverForType(message.messageType, message, engine, network)
self.deliverForType(Message.allMessages, message, engine, network)
proc scheduleLifecycleChange*(self: Peer, event: LifecycleEventType,
network: Network, time: uint64): void =
network.engine.schedule(PeerLifecycleChange(
peer: self,
network: network,
event: event,
time: time
))
proc startAt*(self: Peer, network: Network, time: uint64): void =
self.scheduleLifecycleChange(started, network, time)
proc start*(self: Peer, network: Network): void =
self.startAt(network, network.engine.currentTime)
proc initPeer*(self: Peer, protocols: seq[Protocol],
peerId: Option[int] = none(int)): Peer =

View File

@ -14,3 +14,11 @@ method deliver*(
network: Network
): void {.base.} =
raise newException(CatchableError, "Method without implementation override")
method onLifecycleEventType*(
self: Protocol,
peer: Peer,
event: LifecycleEventType,
network: Network
): void {.base.} =
discard

View File

@ -37,8 +37,14 @@ type
messageTypes*: seq[string]
type
LifecycleEventType* = enum
started
up
down
Peer* = ref object of RootObj
peerId*: int
up*: bool = false
protocols*: Table[string, Protocol]
dispatch*: MultiTable[string, Protocol]

View File

@ -9,9 +9,11 @@ import ../helpers/testpeer
suite "block exchange":
test "should respond to want-block message with a list of the blocks it has":
setup:
let engine = EventDrivenEngine()
let network = Network(engine: engine)
test "should respond to want-have message with a list of the blocks it has":
let sender = TestPeer.new(network)
let bex = BlockExchangeProtocol.new()
@ -41,3 +43,6 @@ suite "block exchange":
let response = Have(sender.inbox.messages[0])
check(response.haves == toIntSet([0, 1, 4]))

View File

@ -10,6 +10,7 @@ import ../helpers/inbox
import ../helpers/types
suite "network":
test "should dispatch message to the correct peer":
let engine = EventDrivenEngine()

View File

@ -9,6 +9,8 @@ import swarmsim/engine/message
import ../helpers/inbox
import ../helpers/types
import pretty
# We need this here as otherwise for some reason the nim compiler trips.
proc `$`*(m: Message): string = repr m
@ -79,7 +81,6 @@ suite "peer":
check(i1.messages == @[m1, m2])
test "should deliver all message types when listening to Message.allMessages":
let i1 = Inbox(protocolId: "protocol1", messageTypes: @[Message.allMessages])
@ -95,3 +96,36 @@ suite "peer":
check(i1.messages == @[m1, m2, m3])
test "should be up after start":
let i1 = Inbox(protocolId: "lifecycleListener", messageTypes: @[])
let peer = Peer.new(protocols = @[Protocol i1])
peer.startAt(network, 5)
check(not peer.up)
engine.run()
check((repr i1.events) == (repr @[
LifecycleEvent(event: started, time: 5.uint64)]))
check(peer.up)
test "should not be up after going down":
let i1 = Inbox(protocolId: "lifecycleListener", messageTypes: @[])
let peer = Peer.new(protocols = @[Protocol i1])
peer.start(network)
peer.scheduleLifecycleChange(
event = down,
network = network,
time = 10
)
engine.run()
check((repr i1.events) == (repr @[
LifecycleEvent(event: started, time: 0),
LifecycleEvent(event: down, time: 10)
]))

View File

@ -9,6 +9,11 @@ withTypeId:
Inbox* = ref object of Protocol
protocolId*: string
messages*: seq[Message]
events*: seq[LifecycleEvent]
LifecycleEvent* = ref object of RootObj
event*: LifecycleEventType
time*: uint64
method deliver*(
self: Inbox,
@ -20,7 +25,16 @@ method deliver*(
method `protocolId`*(self: Inbox): string = self.protocolId
method onLifecycleEventType*(
self: Inbox,
peer: Peer,
event: LifecycleEventType,
network: Network
) =
self.events.add(LifecycleEvent(event: event, time: network.engine.currentTime))
export Message
export LifecycleEvent
export peer
export protocol
export network