|
|
@ -17,10 +17,12 @@ import (
|
|
|
|
"net/http"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
"unicode/utf8"
|
|
|
|
"unicode/utf8"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/peterbourgon/ff/v2/ffcli"
|
|
|
|
"github.com/peterbourgon/ff/v2/ffcli"
|
|
|
|
|
|
|
|
"golang.org/x/time/rate"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn/ipnstate"
|
|
|
|
"tailscale.com/ipn/ipnstate"
|
|
|
|
)
|
|
|
|
)
|
|
|
@ -62,6 +64,7 @@ func runPush(ctx context.Context, args []string) error {
|
|
|
|
|
|
|
|
|
|
|
|
var fileContents io.Reader
|
|
|
|
var fileContents io.Reader
|
|
|
|
var name = pushArgs.name
|
|
|
|
var name = pushArgs.name
|
|
|
|
|
|
|
|
var contentLength int64 = -1
|
|
|
|
if fileArg == "-" {
|
|
|
|
if fileArg == "-" {
|
|
|
|
fileContents = os.Stdin
|
|
|
|
fileContents = os.Stdin
|
|
|
|
if name == "" {
|
|
|
|
if name == "" {
|
|
|
@ -76,10 +79,22 @@ func runPush(ctx context.Context, args []string) error {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
defer f.Close()
|
|
|
|
fileContents = f
|
|
|
|
fi, err := f.Stat()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if fi.IsDir() {
|
|
|
|
|
|
|
|
return errors.New("directories not supported")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
contentLength = fi.Size()
|
|
|
|
|
|
|
|
fileContents = io.LimitReader(f, contentLength)
|
|
|
|
if name == "" {
|
|
|
|
if name == "" {
|
|
|
|
name = fileArg
|
|
|
|
name = fileArg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if slow, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_SLOW_PUSH")); slow {
|
|
|
|
|
|
|
|
fileContents = &slowReader{r: fileContents}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dstURL := "http://" + net.JoinHostPort(ip, fmt.Sprint(peerAPIPort)) + "/v0/put/" + url.PathEscape(name)
|
|
|
|
dstURL := "http://" + net.JoinHostPort(ip, fmt.Sprint(peerAPIPort)) + "/v0/put/" + url.PathEscape(name)
|
|
|
@ -87,6 +102,7 @@ func runPush(ctx context.Context, args []string) error {
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req.ContentLength = contentLength
|
|
|
|
if pushArgs.verbose {
|
|
|
|
if pushArgs.verbose {
|
|
|
|
log.Printf("sending to %v ...", dstURL)
|
|
|
|
log.Printf("sending to %v ...", dstURL)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -171,3 +187,22 @@ func pickStdinFilename() (name string, r io.Reader, err error) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "stdin" + ext(sniff), io.MultiReader(bytes.NewReader(sniff), os.Stdin), nil
|
|
|
|
return "stdin" + ext(sniff), io.MultiReader(bytes.NewReader(sniff), os.Stdin), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type slowReader struct {
|
|
|
|
|
|
|
|
r io.Reader
|
|
|
|
|
|
|
|
rl *rate.Limiter
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (r *slowReader) Read(p []byte) (n int, err error) {
|
|
|
|
|
|
|
|
const burst = 4 << 10
|
|
|
|
|
|
|
|
plen := len(p)
|
|
|
|
|
|
|
|
if plen > burst {
|
|
|
|
|
|
|
|
plen = burst
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.rl == nil {
|
|
|
|
|
|
|
|
r.rl = rate.NewLimiter(rate.Limit(1<<10), burst)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err = r.r.Read(p[:plen])
|
|
|
|
|
|
|
|
r.rl.WaitN(context.Background(), n)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|