@@ -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?
@@ -162,13 +163,17 @@ type StateMachineCfg[Event any, Env Environment] struct {
162163 // can be used to set up tracking state such as a txid confirmation
163164 // event.
164165 InitEvent fn.Option [DaemonEvent ]
166+
167+ // MsgMapper is an optional message mapper that can be used to map
168+ // normal wire messages into FSM events.
169+ MsgMapper fn.Option [MsgMapper [Event ]]
165170}
166171
167172// NewStateMachine creates a new state machine given a set of daemon adapters,
168173// an initial state, an environment, and an event to process as if emitted at
169174// the onset of the state machine. Such an event can be used to set up tracking
170175// state such as a txid confirmation event.
171- func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ],
176+ func NewStateMachine [Event any , Env Environment ](cfg StateMachineCfg [Event , Env ], //nolint:lll
172177) StateMachine [Event , Env ] {
173178
174179 return StateMachine [Event , Env ]{
@@ -209,6 +214,43 @@ func (s *StateMachine[Event, Env]) SendEvent(event Event) {
209214 }
210215}
211216
217+ // CanHandle returns true if the target message can be routed to the state
218+ // machine.
219+ func (s * StateMachine [Event , Env ]) CanHandle (msg lnwire.Message ) bool {
220+ cfgMapper := s .cfg .MsgMapper
221+ return fn .MapOptionZ (cfgMapper , func (mapper MsgMapper [Event ]) bool {
222+ return mapper .MapMsg (msg ).IsSome ()
223+ })
224+ }
225+
226+ // SendMessage attempts to send a wire message to the state machine. If the
227+ // message can be mapped using the default message mapper, then true is
228+ // returned indicating that the message was processed. Otherwise, false is
229+ // returned.
230+ func (s * StateMachine [Event , Env ]) SendMessage (msg lnwire.Message ) bool {
231+ // If we have no message mapper, then return false as we can't process
232+ // this message.
233+ if ! s .cfg .MsgMapper .IsSome () {
234+ return false
235+ }
236+
237+ // Otherwise, try to map the message using the default message mapper.
238+ // If we can't extract an event, then we'll return false to indicate
239+ // that the message wasn't processed.
240+ var processed bool
241+ s .cfg .MsgMapper .WhenSome (func (mapper MsgMapper [Event ]) {
242+ event := mapper .MapMsg (msg )
243+
244+ event .WhenSome (func (event Event ) {
245+ s .SendEvent (event )
246+
247+ processed = true
248+ })
249+ })
250+
251+ return processed
252+ }
253+
212254// CurrentState returns the current state of the state machine.
213255func (s * StateMachine [Event , Env ]) CurrentState () (State [Event , Env ], error ) {
214256 query := stateQuery [Event , Env ]{
@@ -228,7 +270,9 @@ type StateSubscriber[E any, F Environment] *fn.EventReceiver[State[E, F]]
228270
229271// RegisterStateEvents registers a new event listener that will be notified of
230272// new state transitions.
231- func (s * StateMachine [Event , Env ]) RegisterStateEvents () StateSubscriber [Event , Env ] {
273+ func (s * StateMachine [Event , Env ]) RegisterStateEvents () StateSubscriber [
274+ Event , Env ] {
275+
232276 subscriber := fn.NewEventReceiver [State [Event , Env ]](10 )
233277
234278 // TODO(roasbeef): instead give the state and the input event?
@@ -240,16 +284,17 @@ func (s *StateMachine[Event, Env]) RegisterStateEvents() StateSubscriber[Event,
240284
241285// RemoveStateSub removes the target state subscriber from the set of active
242286// subscribers.
243- func (s * StateMachine [Event , Env ]) RemoveStateSub (sub StateSubscriber [Event , Env ]) {
244- s .newStateEvents .RemoveSubscriber (sub )
287+ func (s * StateMachine [Event , Env ]) RemoveStateSub (sub StateSubscriber [
288+ Event , Env ]) {
289+
290+ _ = s .newStateEvents .RemoveSubscriber (sub )
245291}
246292
247293// executeDaemonEvent executes a daemon event, which is a special type of event
248294// that can be emitted as part of the state transition function of the state
249295// machine. An error is returned if the type of event is unknown.
250296func (s * StateMachine [Event , Env ]) executeDaemonEvent (event DaemonEvent ) error {
251297 switch daemonEvent := event .(type ) {
252-
253298 // This is a send message event, so we'll send the event, and also mind
254299 // any preconditions as well as post-send events.
255300 case * SendMsgEvent [Event ]:
@@ -258,7 +303,8 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
258303 daemonEvent .TargetPeer , daemonEvent .Msgs ,
259304 )
260305 if err != nil {
261- return fmt .Errorf ("unable to send msgs: %w" , err )
306+ return fmt .Errorf ("unable to send msgs: %w" ,
307+ err )
262308 }
263309
264310 // If a post-send event was specified, then we'll
@@ -303,7 +349,12 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
303349 )
304350
305351 if canSend {
306- sendAndCleanUp ()
352+ err := sendAndCleanUp ()
353+ if err != nil {
354+ //nolint:lll
355+ log .Errorf ("FSM(%v): unable to send message: %v" , err )
356+ }
357+
307358 return
308359 }
309360
@@ -322,8 +373,6 @@ func (s *StateMachine[Event, Env]) executeDaemonEvent(event DaemonEvent) error {
322373 daemonEvent .Tx , daemonEvent .Label ,
323374 )
324375 if err != nil {
325- // TODO(roasbeef): hook has channel read event event is
326- // hit?
327376 return fmt .Errorf ("unable to broadcast txn: %w" , err )
328377 }
329378
@@ -417,6 +466,8 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
417466 // any new emitted internal events to our event queue. This continues
418467 // until we reach a terminal state, or we run out of internal events to
419468 // process.
469+ //
470+ //nolint:lll
420471 for nextEvent := eventQueue .Dequeue (); nextEvent .IsSome (); nextEvent = eventQueue .Dequeue () {
421472 err := fn .MapOptionZ (nextEvent , func (event Event ) error {
422473 // Apply the state transition function of the current
@@ -429,13 +480,17 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
429480 }
430481
431482 newEvents := transition .NewEvents
432- err = fn .MapOptionZ (newEvents , func (events EmittedEvent [Event ]) error {
483+ err = fn .MapOptionZ (newEvents , func (events EmittedEvent [Event ]) error { //nolint:lll
433484 // With the event processed, we'll process any
434485 // new daemon events that were emitted as part
435486 // of this new state transition.
487+ //
488+ //nolint:lll
436489 err := fn .MapOptionZ (events .ExternalEvents , func (dEvents DaemonEventSet ) error {
437490 for _ , dEvent := range dEvents {
438- err := s .executeDaemonEvent (dEvent )
491+ err := s .executeDaemonEvent (
492+ dEvent ,
493+ )
439494 if err != nil {
440495 return err
441496 }
@@ -449,6 +504,8 @@ func (s *StateMachine[Event, Env]) applyEvents(currentState State[Event, Env],
449504
450505 // Next, we'll add any new emitted events to
451506 // our event queue.
507+ //
508+ //nolint:lll
452509 events .InternalEvent .WhenSome (func (inEvent Event ) {
453510 eventQueue .Enqueue (inEvent )
454511 })
@@ -530,7 +587,10 @@ func (s *StateMachine[Event, Env]) driveMachine() {
530587 // An outside caller is querying our state, so we'll return the
531588 // latest state.
532589 case stateQuery := <- s .stateQuery :
533- if ! fn .SendOrQuit (stateQuery .CurrentState , currentState , s .quit ) {
590+ if ! fn .SendOrQuit (
591+ stateQuery .CurrentState , currentState , s .quit ,
592+ ) {
593+
534594 return
535595 }
536596
0 commit comments