Skip to content

Commit fedf258

Browse files
network: improve ctrl+c interupts
This cancels the HTTP request when Ctrl+C is made, without crashing cmk and immediately getting the shell back to interacting users. Fixes #126 Signed-off-by: Rohit Yadav <[email protected]>
1 parent d1599ea commit fedf258

File tree

3 files changed

+29
-14
lines changed

3 files changed

+29
-14
lines changed

cmd/api.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ func init() {
7979

8080
response, err := NewAPIRequest(r, api.Name, apiArgs, api.Async)
8181
if err != nil {
82-
if response != nil {
82+
if strings.HasSuffix(err.Error(), "context canceled") {
83+
return nil
84+
} else if response != nil {
8385
printResult(r.Config.Core.Output, response, nil)
8486
}
8587
return err

cmd/network.go

+6-13
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import (
3030
"net/http/cookiejar"
3131
"net/url"
3232
"os"
33-
"os/signal"
3433
"sort"
3534
"strings"
3635
"time"
@@ -149,19 +148,11 @@ func pollAsyncJob(r *Request, jobID string) (map[string]interface{}, error) {
149148
spinner := r.Config.StartSpinner("polling for async API result")
150149
defer r.Config.StopSpinner(spinner)
151150

152-
interrupted := false
153-
c := make(chan os.Signal, 1)
154-
signal.Notify(c, os.Interrupt)
155-
go func() {
156-
<-c
157-
interrupted = true
158-
}()
159-
160151
for {
161-
if interrupted {
162-
return nil, errors.New("API job query interrupted")
163-
}
164152
select {
153+
case <-r.Config.C:
154+
return nil, errors.New("async API job polling interrupted")
155+
165156
case <-timeout.C:
166157
return nil, errors.New("async API job query timed out")
167158

@@ -294,10 +285,12 @@ func NewAPIRequest(r *Request, api string, args []string, isAsync bool) (map[str
294285

295286
// we can implement further conditions to do POST or GET (or other http commands) here
296287
func executeRequest(r *Request, requestURL string, params url.Values) (*http.Response, error) {
288+
config.SetupContext(r.Config)
297289
if params.Has("password") || params.Has("userdata") {
298290
requestURL = fmt.Sprintf("%s", r.Config.ActiveProfile.URL)
299291
return r.Client().PostForm(requestURL, params)
300292
} else {
301-
return r.Client().Get(requestURL)
293+
req, _ := http.NewRequestWithContext(*r.Config.Context, "GET", requestURL, nil)
294+
return r.Client().Do(req)
302295
}
303296
}

config/config.go

+20
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
package config
1919

2020
import (
21+
"context"
2122
"crypto/tls"
2223
"fmt"
2324
"net/http"
2425
"net/http/cookiejar"
2526
"os"
27+
"os/signal"
2628
"path"
2729
"path/filepath"
2830
"strconv"
@@ -76,6 +78,9 @@ type Config struct {
7678
HasShell bool
7779
Core *Core
7880
ActiveProfile *ServerProfile
81+
Context *context.Context
82+
Cancel context.CancelFunc
83+
C chan bool
7984
}
8085

8186
func GetOutputFormats() []string {
@@ -182,7 +187,22 @@ func GetProfiles() []string {
182187
return profiles
183188
}
184189

190+
func SetupContext(cfg *Config) {
191+
cfg.C = make(chan bool)
192+
signals := make(chan os.Signal, 1)
193+
signal.Notify(signals, os.Interrupt)
194+
ctx, cancel := context.WithCancel(context.Background())
195+
cfg.Context = &ctx
196+
cfg.Cancel = cancel
197+
go func() {
198+
<-signals
199+
cfg.Cancel()
200+
cfg.C <- true
201+
}()
202+
}
203+
185204
func newHTTPClient(cfg *Config) *http.Client {
205+
SetupContext(cfg)
186206
jar, _ := cookiejar.New(nil)
187207
client := &http.Client{
188208
Jar: jar,

0 commit comments

Comments
 (0)