This commit adds and passes context around to (almost) every function. This allows cancelling (almost) every function call globally.
57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
package cancel
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
type SetDeadline interface {
|
|
SetDeadline(t time.Time)
|
|
}
|
|
|
|
type SetReadDeadline interface {
|
|
SetReadDeadline(t time.Time) error
|
|
}
|
|
|
|
type SetWriteDeadline interface {
|
|
SetWriteDeadline(t time.Time) error
|
|
}
|
|
|
|
// Copy reads from src, and copies to dst.
|
|
//
|
|
// If the context is closed before src is closed, attempts to close the underlying reader and writer.
|
|
func Copy(ctx context.Context, dst io.Writer, src io.Reader) (written int64, err error) {
|
|
|
|
// if the context has a deadline, the propanate that deadline to the underyling file.
|
|
// this might cause the read call to not block.
|
|
if deadline, ok := ctx.Deadline(); ok {
|
|
var zero time.Time
|
|
|
|
if file, ok := src.(SetReadDeadline); ok {
|
|
file.SetReadDeadline(deadline)
|
|
defer file.SetReadDeadline(zero)
|
|
} else if file, ok := src.(SetDeadline); ok {
|
|
file.SetDeadline(deadline)
|
|
defer file.SetDeadline(zero)
|
|
}
|
|
|
|
if file, ok := dst.(SetWriteDeadline); ok {
|
|
file.SetWriteDeadline(deadline)
|
|
defer file.SetWriteDeadline(zero)
|
|
} else if file, ok := dst.(SetDeadline); ok {
|
|
file.SetDeadline(deadline)
|
|
defer file.SetDeadline(zero)
|
|
}
|
|
}
|
|
|
|
written, err, _ = WithContext2(ctx, func(start func()) (int64, error) {
|
|
start()
|
|
return io.Copy(dst, src)
|
|
}, func() {
|
|
if closer, ok := src.(io.Closer); ok {
|
|
closer.Close()
|
|
}
|
|
})
|
|
return written, err
|
|
}
|