@@ -64,7 +64,8 @@ type State[Event any, Env Environment] interface {
6464 // emitted.
6565 ProcessEvent (event Event , env Env ) (* StateTransition [Event , Env ], error )
6666
67- // IsTerminal returns true if this state is terminal, and false otherwise.
67+ // IsTerminal returns true if this state is terminal, and false
68+ // otherwise.
6869 IsTerminal () bool
6970
7071 // TODO(roasbeef): also add state serialization?
@@ -159,13 +160,17 @@ type StateMachineCfg[Event any, Env Environment] struct {
159160 // can be used to set up tracking state such as a txid confirmation
160161 // event.
161162 InitEvent fn.Option [DaemonEvent ]
163+
164+ // MsgMapper is an optional message mapper that can be used to map
165+ // normal wire messages into FSM events.
166+ MsgMapper fn.Option [MsgMapper [Event ]]
162167}
163168
164169// NewStateMachine creates a new state machine given a set of daemon adapters,
165170// an initial state, an environment, and an event to process as if emitted at
166171// the onset of the state machine. Such an event can be used to set up tracking
167172// state such as a txid confirmation event.
168- func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ],
173+ func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ], //nolint:lll
169174) StateMachine [Event , Env ] {
170175
171176 return StateMachine [Event , Env ]{
@@ -206,6 +211,43 @@ func (s *StateMachine[Event, Env]) SendEvent(event Event) {
206211 }
207212}
208213
214+ // CanHandle returns true if the target message can be routed to the state
215+ // machine.
216+ func (s * StateMachine [Event , Env ]) CanHandle (msg lnwire.Message ) bool {
217+ cfgMapper := s .cfg .MsgMapper
218+ return fn .MapOptionZ (cfgMapper , func (mapper MsgMapper [Event ]) bool {
219+ return mapper .MapMsg (msg ).IsSome ()
220+ })
221+ }
222+
223+ // SendMessage attempts to send a wire message to the state machine. If the
224+ // message can be mapped using the default message mapper, then true is
225+ // returned indicating that the message was processed. Otherwise, false is
226+ // returned.
227+ func (s * StateMachine [Event , Env ]) SendMessage (msg lnwire.Message ) bool {
228+ // If we have no message mapper, then return false as we can't process
229+ // this message.
230+ if ! s .cfg .MsgMapper .IsSome () {
231+ return false
232+ }
233+
234+ // Otherwise, try to map the message using the default message mapper.
235+ // If we can't extract an event, then we'll return false to indicate
236+ // that the message wasn't processed.
237+ var processed bool
238+ s .cfg .MsgMapper .WhenSome (func (mapper MsgMapper [Event ]) {
239+ event := mapper .MapMsg (msg )
240+
241+ event .WhenSome (func (event Event ) {
242+ s .SendEvent (event )
243+
244+ processed = true
245+ })
246+ })
247+
248+ return processed
249+ }
250+
209251// CurrentState returns the current state of the state machine.
210252func (s * StateMachine [Event , Env ]) CurrentState () (State [Event , Env ], error ) {
211253 query := stateQuery [Event , Env ]{
@@ -225,7 +267,9 @@ type StateSubscriber[E any, F Environment] *fn.EventReceiver[State[E, F]]
225267
226268// RegisterStateEvents registers a new event listener that will be notified of
227269// new state transitions.
228- func (s * StateMachine [Event , Env ]) RegisterStateEvents () StateSubscriber [Event , Env ] {
270+ func (s * StateMachine [Event , Env ]) RegisterStateEvents () StateSubscriber [
271+ Event , Env ] {
272+
229273 subscriber := fn.NewEventReceiver [State [Event , Env ]](10 )
230274
231275 // TODO(roasbeef): instead give the state and the input event?
@@ -237,16 +281,17 @@ func (s *StateMachine[Event, Env]) RegisterStateEvents() StateSubscriber[Event,
237281
238282// RemoveStateSub removes the target state subscriber from the set of active
239283// subscribers.
240- func (s * StateMachine [Event , Env ]) RemoveStateSub (sub StateSubscriber [Event , Env ]) {
241- s .newStateEvents .RemoveSubscriber (sub )
284+ func (s * StateMachine [Event , Env ]) RemoveStateSub (sub StateSubscriber [
285+ Event , Env ]) {
286+
287+ _ = s .newStateEvents .RemoveSubscriber (sub )
242288}
243289
244290// executeDaemonEvent executes a daemon event, which is a special type of event
245291// that can be emitted as part of the state transition function of the state
246292// machine. An error is returned if the type of event is unknown.
247293func (s * StateMachine [Event , Env ]) executeDaemonEvent (event DaemonEvent ) error {
248294 switch daemonEvent := event .(type ) {
249-
250295 // This is a send message event, so we'll send the event, and also mind
251296 // any preconditions as well as post-send events.
252297 case * SendMsgEvent [Event ]:
@@ -255,7 +300,8 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
255300 daemonEvent .TargetPeer , daemonEvent .Msgs ,
256301 )
257302 if err != nil {
258- return fmt .Errorf ("unable to send msgs: %w" , err )
303+ return fmt .Errorf ("unable to send msgs: %w" ,
304+ err )
259305 }
260306
261307 // If a post-send event was specified, then we'll
@@ -300,7 +346,12 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
300346 )
301347
302348 if canSend {
303- sendAndCleanUp ()
349+ err := sendAndCleanUp ()
350+ if err != nil {
351+ //nolint:lll
352+ log .Errorf ("FSM(%v): unable to send message: %v" , err )
353+ }
354+
304355 return
305356 }
306357
@@ -319,8 +370,6 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
319370 daemonEvent .Tx , daemonEvent .Label ,
320371 )
321372 if err != nil {
322- // TODO(roasbeef): hook has channel read event event is
323- // hit?
324373 return fmt .Errorf ("unable to broadcast txn: %w" , err )
325374 }
326375
@@ -414,6 +463,8 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
414463 // any new emitted internal events to our event queue. This continues
415464 // until we reach a terminal state, or we run out of internal events to
416465 // process.
466+ //
467+ //nolint:lll
417468 for nextEvent := eventQueue .Dequeue (); nextEvent .IsSome (); nextEvent = eventQueue .Dequeue () {
418469 err := fn .MapOptionZ (nextEvent , func (event Event ) error {
419470 // Apply the state transition function of the current
@@ -426,13 +477,17 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
426477 }
427478
428479 newEvents := transition .NewEvents
429- err = fn .MapOptionZ (newEvents , func (events EmittedEvent [Event ]) error {
480+ err = fn .MapOptionZ (newEvents , func (events EmittedEvent [Event ]) error { //nolint:lll
430481 // With the event processed, we'll process any
431482 // new daemon events that were emitted as part
432483 // of this new state transition.
484+ //
485+ //nolint:lll
433486 err := fn .MapOptionZ (events .ExternalEvents , func (dEvents DaemonEventSet ) error {
434487 for _ , dEvent := range dEvents {
435- err := s .executeDaemonEvent (dEvent )
488+ err := s .executeDaemonEvent (
489+ dEvent ,
490+ )
436491 if err != nil {
437492 return err
438493 }
@@ -446,6 +501,8 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
446501
447502 // Next, we'll add any new emitted events to
448503 // our event queue.
504+ //
505+ //nolint:lll
449506 events .InternalEvent .WhenSome (func (inEvent Event ) {
450507 eventQueue .Enqueue (inEvent )
451508 })
@@ -516,7 +573,10 @@ func (s *StateMachine[Event, Env]) driveMachine() {
516573 // An outside caller is querying our state, so we'll return the
517574 // latest state.
518575 case stateQuery := <- s .stateQuery :
519- if ! fn .SendOrQuit (stateQuery .CurrentState , currentState , s .quit ) {
576+ if ! fn .SendOrQuit (
577+ stateQuery .CurrentState , currentState , s .quit ,
578+ ) {
579+
520580 return
521581 }
522582
0 commit comments