@@ -5,39 +5,113 @@ import (
55 "log/slog"
66 "time"
77
8- "github.com/robbyt/go-fsm"
8+ "github.com/robbyt/go-fsm/v2"
9+ "github.com/robbyt/go-fsm/v2/hooks"
10+ "github.com/robbyt/go-fsm/v2/hooks/broadcast"
11+ "github.com/robbyt/go-fsm/v2/transitions"
912)
1013
1114const (
12- StatusNew = fsm .StatusNew
13- StatusBooting = fsm .StatusBooting
14- StatusRunning = fsm .StatusRunning
15- StatusReloading = fsm .StatusReloading
16- StatusStopping = fsm .StatusStopping
17- StatusStopped = fsm .StatusStopped
18- StatusError = fsm .StatusError
19- StatusUnknown = fsm .StatusUnknown
15+ StatusNew = transitions .StatusNew
16+ StatusBooting = transitions .StatusBooting
17+ StatusRunning = transitions .StatusRunning
18+ StatusReloading = transitions .StatusReloading
19+ StatusStopping = transitions .StatusStopping
20+ StatusStopped = transitions .StatusStopped
21+ StatusError = transitions .StatusError
22+ StatusUnknown = transitions .StatusUnknown
2023)
2124
2225// TypicalTransitions is a set of standard transitions for a finite state machine.
23- var TypicalTransitions = fsm . TypicalTransitions
26+ var TypicalTransitions = transitions . Typical
2427
25- // Machine is a wrapper around go-fsm.Machine that provides additional functionality.
28+ // Machine is a wrapper around go-fsm v2 that provides the v1 API compatibility.
29+ // It manages both the FSM and broadcast functionality.
2630type Machine struct {
2731 * fsm.Machine
32+ broadcastManager * broadcast.Manager
2833}
2934
30- // GetStateChan returns a channel that emits the state whenever it changes.
35+ // GetStateChanWithTimeout returns a channel that emits the state whenever it changes.
3136// The channel is closed when the provided context is canceled.
37+ // For v1 API compatibility, the current state is sent immediately to the channel.
3238func (s * Machine ) GetStateChanWithTimeout (ctx context.Context ) <- chan string {
33- return s .GetStateChanWithOptions (ctx , fsm .WithSyncTimeout (5 * time .Second ))
39+ return s .getStateChanInternal (ctx , broadcast .WithTimeout (5 * time .Second ))
40+ }
41+
42+ // GetStateChan returns a channel that emits the state whenever it changes.
43+ // The channel is closed when the provided context is canceled.
44+ // For v1 API compatibility, the current state is sent immediately to the channel.
45+ func (s * Machine ) GetStateChan (ctx context.Context ) <- chan string {
46+ return s .getStateChanInternal (ctx )
47+ }
48+
49+ // GetStateChanWithOptions returns a channel that emits the state whenever it changes
50+ // with custom broadcast options.
51+ // For v1 API compatibility, the current state is sent immediately to the channel.
52+ func (s * Machine ) GetStateChanWithOptions (ctx context.Context , opts ... broadcast.Option ) <- chan string {
53+ return s .getStateChanInternal (ctx , opts ... )
54+ }
55+
56+ // getStateChanInternal is a helper that creates a channel and sends the current state to it.
57+ // This maintains v1 API compatibility where GetStateChan immediately sends the current state.
58+ func (s * Machine ) getStateChanInternal (ctx context.Context , opts ... broadcast.Option ) <- chan string {
59+ wrappedCh := make (chan string , 1 )
60+
61+ userCh , err := s .broadcastManager .GetStateChan (ctx , opts ... )
62+ if err != nil {
63+ close (wrappedCh )
64+ return wrappedCh
65+ }
66+
67+ currentState := s .GetState ()
68+ wrappedCh <- currentState
69+
70+ go func () {
71+ defer close (wrappedCh )
72+ for state := range userCh {
73+ wrappedCh <- state
74+ }
75+ }()
76+
77+ return wrappedCh
3478}
3579
3680// New creates a new finite state machine with the specified logger using "standard" state transitions.
81+ // This function provides compatibility with the v1 API while using v2 under the hood.
3782func New (handler slog.Handler ) (* Machine , error ) {
38- f , err := fsm .New (handler , StatusNew , TypicalTransitions )
83+ registry , err := hooks .NewRegistry (
84+ hooks .WithLogHandler (handler ),
85+ hooks .WithTransitions (TypicalTransitions ),
86+ )
87+ if err != nil {
88+ return nil , err
89+ }
90+
91+ broadcastManager := broadcast .NewManager (handler )
92+
93+ err = registry .RegisterPostTransitionHook (hooks.PostTransitionHookConfig {
94+ Name : "broadcast" ,
95+ From : []string {"*" },
96+ To : []string {"*" },
97+ Action : broadcastManager .BroadcastHook ,
98+ })
99+ if err != nil {
100+ return nil , err
101+ }
102+
103+ f , err := fsm .New (
104+ StatusNew ,
105+ TypicalTransitions ,
106+ fsm .WithLogHandler (handler ),
107+ fsm .WithCallbackRegistry (registry ),
108+ )
39109 if err != nil {
40110 return nil , err
41111 }
42- return & Machine {Machine : f }, nil
112+
113+ return & Machine {
114+ Machine : f ,
115+ broadcastManager : broadcastManager ,
116+ }, nil
43117}
0 commit comments