File: http.go

package info (click to toggle)
incus 6.0.4-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 23,864 kB
  • sloc: sh: 16,015; ansic: 3,121; python: 456; makefile: 321; ruby: 51; sql: 50; lisp: 6
file content (81 lines) | stat: -rw-r--r-- 1,705 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package cancel

import (
	"context"
	"fmt"
	"net/http"
	"sync"
)

// HTTPRequestCanceller tracks a cancelable operation.
type HTTPRequestCanceller struct {
	reqCancel map[*http.Request]context.CancelFunc
	lock      sync.Mutex
}

// NewHTTPRequestCanceller returns a new HTTPRequestCanceller struct.
func NewHTTPRequestCanceller() *HTTPRequestCanceller {
	c := HTTPRequestCanceller{}

	c.lock.Lock()
	c.reqCancel = make(map[*http.Request]context.CancelFunc)
	c.lock.Unlock()

	return &c
}

// Cancelable indicates whether there are operations that support cancellation.
func (c *HTTPRequestCanceller) Cancelable() bool {
	c.lock.Lock()
	length := len(c.reqCancel)
	c.lock.Unlock()

	return length > 0
}

// Cancel will attempt to cancel all ongoing operations.
func (c *HTTPRequestCanceller) Cancel() error {
	if !c.Cancelable() {
		return fmt.Errorf("This operation can't be canceled at this time")
	}

	c.lock.Lock()
	for req, cancel := range c.reqCancel {
		cancel()
		delete(c.reqCancel, req)
	}

	c.lock.Unlock()

	return nil
}

// CancelableDownload performs an http request and allows for it to be canceled at any time.
func CancelableDownload(c *HTTPRequestCanceller, do func(req *http.Request) (*http.Response, error), req *http.Request) (*http.Response, chan bool, error) {
	chDone := make(chan bool)
	ctx, cancel := context.WithCancel(req.Context())
	req = req.WithContext(ctx)
	if c != nil {
		c.lock.Lock()
		c.reqCancel[req] = cancel
		c.lock.Unlock()
	}

	go func() {
		<-chDone
		if c != nil {
			c.lock.Lock()
			cancel()
			delete(c.reqCancel, req)
			c.lock.Unlock()
		}
	}()

	resp, err := do(req)
	if err != nil {
		close(chDone)
		return nil, nil, err
	}

	return resp, chDone, nil
}