@@ -67,7 +67,8 @@ type State[Event any, Env Environment] interface {
6767 // emitted.
6868 ProcessEvent (event Event , env Env ) (* StateTransition [Event , Env ], error )
6969
70- // IsTerminal returns true if this state is terminal, and false otherwise.
70+ // IsTerminal returns true if this state is terminal, and false
71+ // otherwise.
7172 IsTerminal () bool
7273
7374 // TODO(roasbeef): also add state serialization?
@@ -165,13 +166,17 @@ type StateMachineCfg[Event any, Env Environment] struct {
165166 // can be used to set up tracking state such as a txid confirmation
166167 // event.
167168 InitEvent fn.Option [DaemonEvent ]
169+
170+ // MsgMapper is an optional message mapper that can be used to map
171+ // normal wire messages into FSM events.
172+ MsgMapper fn.Option [MsgMapper [Event ]]
168173}
169174
170175// NewStateMachine creates a new state machine given a set of daemon adapters,
171176// an initial state, an environment, and an event to process as if emitted at
172177// the onset of the state machine. Such an event can be used to set up tracking
173178// state such as a txid confirmation event.
174- func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ],
179+ func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ], //nolint:lll
175180) StateMachine [Event , Env ] {
176181
177182 return StateMachine [Event , Env ]{
@@ -212,6 +217,43 @@ func (s *StateMachine[Event, Env]) SendEvent(event Event) {
212217 }
213218}
214219
220+ // CanHandle returns true if the target message can be routed to the state
221+ // machine.
222+ func (s * StateMachine [Event , Env ]) CanHandle (msg lnwire.Message ) bool {
223+ cfgMapper := s .cfg .MsgMapper
224+ return fn .MapOptionZ (cfgMapper , func (mapper MsgMapper [Event ]) bool {
225+ return mapper .MapMsg (msg ).IsSome ()
226+ })
227+ }
228+
229+ // SendMessage attempts to send a wire message to the state machine. If the
230+ // message can be mapped using the default message mapper, then true is
231+ // returned indicating that the message was processed. Otherwise, false is
232+ // returned.
233+ func (s * StateMachine [Event , Env ]) SendMessage (msg lnwire.Message ) bool {
234+ // If we have no message mapper, then return false as we can't process
235+ // this message.
236+ if ! s .cfg .MsgMapper .IsSome () {
237+ return false
238+ }
239+
240+ // Otherwise, try to map the message using the default message mapper.
241+ // If we can't extract an event, then we'll return false to indicate
242+ // that the message wasn't processed.
243+ var processed bool
244+ s .cfg .MsgMapper .WhenSome (func (mapper MsgMapper [Event ]) {
245+ event := mapper .MapMsg (msg )
246+
247+ event .WhenSome (func (event Event ) {
248+ s .SendEvent (event )
249+
250+ processed = true
251+ })
252+ })
253+
254+ return processed
255+ }
256+
215257// CurrentState returns the current state of the state machine.
216258func (s * StateMachine [Event , Env ]) CurrentState () (State [Event , Env ], error ) {
217259 query := stateQuery [Event , Env ]{
@@ -231,7 +273,9 @@ type StateSubscriber[E any, F Environment] *fn.EventReceiver[State[E, F]]
231273
232274// RegisterStateEvents registers a new event listener that will be notified of
233275// new state transitions.
234- func (s * StateMachine [Event , Env ]) RegisterStateEvents () StateSubscriber [Event , Env ] {
276+ func (s * StateMachine [Event , Env ]) RegisterStateEvents () StateSubscriber [
277+ Event , Env ] {
278+
235279 subscriber := fn.NewEventReceiver [State [Event , Env ]](10 )
236280
237281 // TODO(roasbeef): instead give the state and the input event?
@@ -243,16 +287,17 @@ func (s *StateMachine[Event, Env]) RegisterStateEvents() StateSubscriber[Event,
243287
244288// RemoveStateSub removes the target state subscriber from the set of active
245289// subscribers.
246- func (s * StateMachine [Event , Env ]) RemoveStateSub (sub StateSubscriber [Event , Env ]) {
247- s .newStateEvents .RemoveSubscriber (sub )
290+ func (s * StateMachine [Event , Env ]) RemoveStateSub (sub StateSubscriber [
291+ Event , Env ]) {
292+
293+ _ = s .newStateEvents .RemoveSubscriber (sub )
248294}
249295
250296// executeDaemonEvent executes a daemon event, which is a special type of event
251297// that can be emitted as part of the state transition function of the state
252298// machine. An error is returned if the type of event is unknown.
253299func (s * StateMachine [Event , Env ]) executeDaemonEvent (event DaemonEvent ) error {
254300 switch daemonEvent := event .(type ) {
255-
256301 // This is a send message event, so we'll send the event, and also mind
257302 // any preconditions as well as post-send events.
258303 case * SendMsgEvent [Event ]:
@@ -261,7 +306,8 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
261306 daemonEvent .TargetPeer , daemonEvent .Msgs ,
262307 )
263308 if err != nil {
264- return fmt .Errorf ("unable to send msgs: %w" , err )
309+ return fmt .Errorf ("unable to send msgs: %w" ,
310+ err )
265311 }
266312
267313 // If a post-send event was specified, then we'll
@@ -306,7 +352,12 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
306352 )
307353
308354 if canSend {
309- sendAndCleanUp ()
355+ err := sendAndCleanUp ()
356+ if err != nil {
357+ //nolint:lll
358+ log .Errorf ("FSM(%v): unable to send message: %v" , err )
359+ }
360+
310361 return
311362 }
312363
@@ -335,8 +386,6 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
335386 daemonEvent .Tx , daemonEvent .Label ,
336387 )
337388 if err != nil {
338- // TODO(roasbeef): hook has channel read event event is
339- // hit?
340389 return fmt .Errorf ("unable to broadcast txn: %w" , err )
341390 }
342391
@@ -430,6 +479,8 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
430479 // any new emitted internal events to our event queue. This continues
431480 // until we reach a terminal state, or we run out of internal events to
432481 // process.
482+ //
483+ //nolint:lll
433484 for nextEvent := eventQueue .Dequeue (); nextEvent .IsSome (); nextEvent = eventQueue .Dequeue () {
434485 err := fn .MapOptionZ (nextEvent , func (event Event ) error {
435486 // Apply the state transition function of the current
@@ -442,13 +493,17 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
442493 }
443494
444495 newEvents := transition .NewEvents
445- err = fn .MapOptionZ (newEvents , func (events EmittedEvent [Event ]) error {
496+ err = fn .MapOptionZ (newEvents , func (events EmittedEvent [Event ]) error { //nolint:lll
446497 // With the event processed, we'll process any
447498 // new daemon events that were emitted as part
448499 // of this new state transition.
500+ //
501+ //nolint:lll
449502 err := fn .MapOptionZ (events .ExternalEvents , func (dEvents DaemonEventSet ) error {
450503 for _ , dEvent := range dEvents {
451- err := s .executeDaemonEvent (dEvent )
504+ err := s .executeDaemonEvent (
505+ dEvent ,
506+ )
452507 if err != nil {
453508 return err
454509 }
@@ -462,6 +517,8 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
462517
463518 // Next, we'll add any new emitted events to
464519 // our event queue.
520+ //
521+ //nolint:lll
465522 events .InternalEvent .WhenSome (func (inEvent Event ) {
466523 eventQueue .Enqueue (inEvent )
467524 })
@@ -543,7 +600,10 @@ func (s *StateMachine[Event, Env]) driveMachine() {
543600 // An outside caller is querying our state, so we'll return the
544601 // latest state.
545602 case stateQuery := <- s .stateQuery :
546- if ! fn .SendOrQuit (stateQuery .CurrentState , currentState , s .quit ) {
603+ if ! fn .SendOrQuit (
604+ stateQuery .CurrentState , currentState , s .quit ,
605+ ) {
606+
547607 return
548608 }
549609
0 commit comments