This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git


The following commit(s) were added to refs/heads/main by this push:
     new fedf258  network: improve ctrl+c interupts
fedf258 is described below

commit fedf258ddf0f0bd6538fd7a1b1226af6009021b6
Author: Rohit Yadav <[email protected]>
AuthorDate: Fri Feb 9 18:56:55 2024 +0530

    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]>
---
 cmd/api.go       |  4 +++-
 cmd/network.go   | 19 ++++++-------------
 config/config.go | 20 ++++++++++++++++++++
 3 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/cmd/api.go b/cmd/api.go
index 022140a..058c6fb 100644
--- a/cmd/api.go
+++ b/cmd/api.go
@@ -79,7 +79,9 @@ func init() {
 
                        response, err := NewAPIRequest(r, api.Name, apiArgs, 
api.Async)
                        if err != nil {
-                               if response != nil {
+                               if strings.HasSuffix(err.Error(), "context 
canceled") {
+                                       return nil
+                               } else if response != nil {
                                        printResult(r.Config.Core.Output, 
response, nil)
                                }
                                return err
diff --git a/cmd/network.go b/cmd/network.go
index 6588668..af97740 100644
--- a/cmd/network.go
+++ b/cmd/network.go
@@ -30,7 +30,6 @@ import (
        "net/http/cookiejar"
        "net/url"
        "os"
-       "os/signal"
        "sort"
        "strings"
        "time"
@@ -149,19 +148,11 @@ func pollAsyncJob(r *Request, jobID string) 
(map[string]interface{}, error) {
        spinner := r.Config.StartSpinner("polling for async API result")
        defer r.Config.StopSpinner(spinner)
 
-       interrupted := false
-       c := make(chan os.Signal, 1)
-       signal.Notify(c, os.Interrupt)
-       go func() {
-               <-c
-               interrupted = true
-       }()
-
        for {
-               if interrupted {
-                       return nil, errors.New("API job query interrupted")
-               }
                select {
+               case <-r.Config.C:
+                       return nil, errors.New("async API job polling 
interrupted")
+
                case <-timeout.C:
                        return nil, errors.New("async API job query timed out")
 
@@ -294,10 +285,12 @@ func NewAPIRequest(r *Request, api string, args []string, 
isAsync bool) (map[str
 
 // we can implement further conditions to do POST or GET (or other http 
commands) here
 func executeRequest(r *Request, requestURL string, params url.Values) 
(*http.Response, error) {
+       config.SetupContext(r.Config)
        if params.Has("password") || params.Has("userdata") {
                requestURL = fmt.Sprintf("%s", r.Config.ActiveProfile.URL)
                return r.Client().PostForm(requestURL, params)
        } else {
-               return r.Client().Get(requestURL)
+               req, _ := http.NewRequestWithContext(*r.Config.Context, "GET", 
requestURL, nil)
+               return r.Client().Do(req)
        }
 }
diff --git a/config/config.go b/config/config.go
index f9befed..e390c22 100644
--- a/config/config.go
+++ b/config/config.go
@@ -18,11 +18,13 @@
 package config
 
 import (
+       "context"
        "crypto/tls"
        "fmt"
        "net/http"
        "net/http/cookiejar"
        "os"
+       "os/signal"
        "path"
        "path/filepath"
        "strconv"
@@ -76,6 +78,9 @@ type Config struct {
        HasShell      bool
        Core          *Core
        ActiveProfile *ServerProfile
+       Context       *context.Context
+       Cancel        context.CancelFunc
+       C             chan bool
 }
 
 func GetOutputFormats() []string {
@@ -182,7 +187,22 @@ func GetProfiles() []string {
        return profiles
 }
 
+func SetupContext(cfg *Config) {
+       cfg.C = make(chan bool)
+       signals := make(chan os.Signal, 1)
+       signal.Notify(signals, os.Interrupt)
+       ctx, cancel := context.WithCancel(context.Background())
+       cfg.Context = &ctx
+       cfg.Cancel = cancel
+       go func() {
+               <-signals
+               cfg.Cancel()
+               cfg.C <- true
+       }()
+}
+
 func newHTTPClient(cfg *Config) *http.Client {
+       SetupContext(cfg)
        jar, _ := cookiejar.New(nil)
        client := &http.Client{
                Jar: jar,

Reply via email to