@@ -14,6 +14,60 @@ import (
1414 "golang.org/x/term"
1515)
1616
17+ type spinner interface {
18+ Fail (message ... any )
19+ Success (message ... any )
20+ Stop () error
21+ }
22+
23+ // spinnerFunc creates a new spinner. Overridable for testing.
24+ //
25+ //nolint:gochecknoglobals
26+ var spinnerFunc = func (message string ) (spinner , error ) {
27+ sp , err := pterm .DefaultSpinner .Start (message )
28+ if err != nil {
29+ return nil , fmt .Errorf ("failed to start spinner: %w" , err )
30+ }
31+
32+ return & spinnerWrapper {spinnerPrinter : sp }, nil
33+ }
34+
35+ // spinnerWrapper wraps pterm.SpinnerPrinter to implement the spinner interface.
36+ type spinnerWrapper struct {
37+ spinnerPrinter * pterm.SpinnerPrinter
38+ }
39+
40+ func (w * spinnerWrapper ) Fail (message ... any ) {
41+ w .spinnerPrinter .Fail (message ... )
42+ }
43+
44+ func (w * spinnerWrapper ) Success (message ... any ) {
45+ if message == nil {
46+ _ = w .spinnerPrinter .WithRemoveWhenDone ().Stop ()
47+
48+ return
49+ }
50+
51+ w .spinnerPrinter .Success (message ... )
52+ }
53+
54+ func (w * spinnerWrapper ) Stop () error {
55+ if err := w .spinnerPrinter .Stop (); err != nil {
56+ return fmt .Errorf ("failed to stop spinner: %w" , err )
57+ }
58+
59+ return nil
60+ }
61+
62+ // confirmDialog prompts the user for confirmation. Overridable for testing.
63+ //
64+ //nolint:gochecknoglobals
65+ var confirmDialog = func (msg string , defaultVal bool ) (bool , error ) {
66+ return pterm .DefaultInteractiveConfirm .
67+ WithDefaultValue (defaultVal ).
68+ Show (msg )
69+ }
70+
1771// Gateway model constants.
1872const (
1973 ARCADYAN string = "ARCADYAN"
@@ -24,22 +78,34 @@ const (
2478//nolint:gochecknoglobals
2579var initGatewayFunc = initGateway
2680
27- // withSpinner runs an operation with a spinner, handling success/failure.
28- // It starts a spinner with the given message, executes the function,
29- // and properly stops the spinner on success or failure .
81+ // fetchWithFeedback runs an operation with a spinner, handling success/failure.
82+ // It starts a spinner with the given message, executes the fetch function,
83+ // displays the result using the display function, and properly stops the spinner .
3084//
3185//nolint:ireturn
32- func withSpinner [T any ](message string , fn func () (T , error )) (T , error ) {
33- spinner , _ := pterm .DefaultSpinner .Start (message )
34-
35- result , err := fn ()
86+ func fetchWithFeedback [T any ](
87+ message string ,
88+ fetch func () (T , error ),
89+ display func (T ),
90+ successMessage ... any ,
91+ ) (T , error ) {
92+ spinnerInstance , err := spinnerFunc (message )
3693 if err != nil {
37- spinner .Fail (fmt .Sprintf ("%s: %v" , message , err ))
94+ return * new (T ), err
95+ }
96+
97+ result , opErr := fetch ()
98+ if opErr != nil {
99+ spinnerInstance .Fail (fmt .Sprintf ("%s: %v" , message , opErr ))
38100
39- return result , fmt .Errorf ("%s: %w" , message , err )
101+ return result , fmt .Errorf ("%s: %w" , message , opErr )
40102 }
41103
42- _ = spinner .WithRemoveWhenDone ().Stop ()
104+ spinnerInstance .Success (successMessage ... )
105+
106+ if display != nil {
107+ display (result )
108+ }
43109
44110 return result , nil
45111}
@@ -62,16 +128,9 @@ func login(_ context.Context, _ *cli.Command) error {
62128 return err
63129 }
64130
65- result , err := withSpinner ("Checking logging in..." , func () (* tmhi.LoginResult , error ) {
66- return gateway .Login ()
67- })
68- if err != nil {
69- return err
70- }
71-
72- displayLoginResult (result )
131+ _ , err = fetchWithFeedback ("Checking logging in..." , gateway .Login , displayLoginResult )
73132
74- return nil
133+ return err
75134}
76135
77136func req (_ context.Context , cmd * cli.Command ) error {
@@ -111,14 +170,9 @@ func info(_ context.Context, _ *cli.Command) error {
111170 return err
112171 }
113172
114- result , err := gateway .Info ()
115- if err != nil {
116- return fmt .Errorf ("info command failed: %w" , err )
117- }
118-
119- displayInfoResult (result )
173+ _ , err = fetchWithFeedback ("Fetching gateway info..." , gateway .Info , displayInfoResult )
120174
121- return nil
175+ return err
122176}
123177
124178func status (_ context.Context , _ * cli.Command ) error {
@@ -127,16 +181,9 @@ func status(_ context.Context, _ *cli.Command) error {
127181 return err
128182 }
129183
130- result , err := withSpinner ("Checking gateway status..." , func () (* tmhi.StatusResult , error ) {
131- return gateway .Status ()
132- })
133- if err != nil {
134- return err
135- }
136-
137- displayStatusResult (result )
184+ _ , err = fetchWithFeedback ("Checking gateway status..." , gateway .Status , displayStatusResult )
138185
139- return nil
186+ return err
140187}
141188
142189func signalCmd (_ context.Context , _ * cli.Command ) error {
@@ -145,19 +192,13 @@ func signalCmd(_ context.Context, _ *cli.Command) error {
145192 return err
146193 }
147194
148- result , err := withSpinner (
195+ _ , err = fetchWithFeedback (
149196 "Fetching signal information..." ,
150- func () (* tmhi.SignalResult , error ) {
151- return gateway .Signal ()
152- },
197+ gateway .Signal ,
198+ displaySignalResult ,
153199 )
154- if err != nil {
155- return err
156- }
157200
158- displaySignalResult (result )
159-
160- return nil
201+ return err
161202}
162203
163204func reboot (_ context.Context , cmd * cli.Command ) error {
@@ -167,10 +208,15 @@ func reboot(_ context.Context, cmd *cli.Command) error {
167208 }
168209
169210 if ! cmd .Bool (ConfigAutoConfirm ) {
170- confirm , _ := pterm .DefaultInteractiveConfirm .
171- WithDefaultValue (false ).
172- Show ("Are you sure you want to reboot the gateway?" )
173- if ! confirm {
211+ confirmed , confirmErr := confirmDialog (
212+ "Are you sure you want to reboot the gateway?" ,
213+ false ,
214+ )
215+ if confirmErr != nil {
216+ return fmt .Errorf ("confirmation failed: %w" , confirmErr )
217+ }
218+
219+ if ! confirmed {
174220 pterm .Warning .Println ("Reboot cancelled" )
175221
176222 return nil
@@ -183,18 +229,21 @@ func reboot(_ context.Context, cmd *cli.Command) error {
183229 return nil
184230 }
185231
186- spinner , _ := pterm .DefaultSpinner .Start ("Rebooting gateway..." )
187-
188- err = gateway .Reboot ()
189- if err != nil {
190- spinner .Fail ("Reboot failed" )
191-
192- return fmt .Errorf ("could not reboot gateway: %w" , err )
193- }
232+ _ , ret := fetchWithFeedback (
233+ "Rebooting gateway..." ,
234+ func () (* tmhi.SignalResult , error ) {
235+ rebootErr := gateway .Reboot ()
236+ if rebootErr != nil {
237+ return nil , fmt .Errorf ("Reboot failed: %w" , rebootErr )
238+ }
194239
195- spinner .Success ("Reboot command sent successfully" )
240+ return nil , nil //nolint:nilnil // no error to report
241+ },
242+ nil ,
243+ "Reboot command sent successfully" ,
244+ )
196245
197- return nil
246+ return ret
198247}
199248
200249func defaultConfigPath () string {
0 commit comments