feat: measure each direction of the speed test for 7 s (0.0.7)

This commit is contained in:
redtea committed 2026-10-13 23:12:30 +03:00
1 parent ab8751d436
commit 5155bc36cd
5 files changed
+32 -21

No files matched your search

+17 -11
View File
@@ -13,24 +13,30 @@ import (
)
const (
// speedWindow is how long each direction is measured for.
speedWindow = 3 * time.Second
// speedWindow is how long each direction is measured for, unless the
// server asks for another window; speedWindowMax bounds what it may ask.
speedWindow = 3 * time.Second
speedWindowMax = 30 * time.Second
// speedWait is how long the download may take to start: in a relayed test
// its bytes come from the browser.
speedWait = 10 * time.Second
// speedUpCap bounds the upload, whatever the link does in speedWindow.
// speedUpCap bounds the upload, whatever the link does in the window.
speedUpCap = 48 << 20
)
// doSpeed measures the agent's HTTP link to the server: round-trip time of an
// empty request, then how much flows each way in speedWindow. In a relayed
// empty request, then how much flows each way in the window. In a relayed
// test the server pipes both streams to the browser, so they run end to end.
func (a *Agent) doSpeed(ctx context.Context, env proto.TaskEnvelope) proto.TaskResult {
var args proto.SysSpeedArgs
if len(env.Args) > 0 {
_ = json.Unmarshal(env.Args, &args)
}
res, err := a.measureSpeed(ctx, args.Relay)
window := speedWindow
if args.WindowMs > 0 {
window = min(time.Duration(args.WindowMs)*time.Millisecond, speedWindowMax)
}
res, err := a.measureSpeed(ctx, args.Relay, window)
if err != nil {
return proto.TaskResult{Error: err.Error()}
}
@@ -38,7 +44,7 @@ func (a *Agent) doSpeed(ctx context.Context, env proto.TaskEnvelope) proto.TaskR
return proto.TaskResult{OK: true, Data: data}
}
func (a *Agent) measureSpeed(ctx context.Context, relay bool) (proto.SysSpeedResult, error) {
func (a *Agent) measureSpeed(ctx context.Context, relay bool, window time.Duration) (proto.SysSpeedResult, error) {
res := proto.SysSpeedResult{Relay: relay}
streams := "/api/agent/speed"
if relay {
@@ -59,14 +65,14 @@ func (a *Agent) measureSpeed(ctx context.Context, relay bool) (proto.SysSpeedRes
}
}
down, err := a.speedDown(ctx, streams+"/down")
down, err := a.speedDown(ctx, streams+"/down", window)
if err != nil {
return res, err
}
res.DownBps = down
// Up: send until the window closes or the cap is hit.
body := &speedSource{deadline: time.Now().Add(speedWindow), left: speedUpCap}
body := &speedSource{deadline: time.Now().Add(window), left: speedUpCap}
start := time.Now()
resp, err := a.speedRequest(ctx, http.MethodPost, streams+"/up", body)
if err != nil {
@@ -78,9 +84,9 @@ func (a *Agent) measureSpeed(ctx context.Context, relay bool) (proto.SysSpeedRes
return res, nil
}
// speedDown reads what the server streams for speedWindow, counted from the
// speedDown reads what the server streams for the window, counted from the
// first byte, and returns the rate.
func (a *Agent) speedDown(ctx context.Context, path string) (float64, error) {
func (a *Agent) speedDown(ctx context.Context, path string, window time.Duration) (float64, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
t := time.AfterFunc(speedWait, cancel)
@@ -99,7 +105,7 @@ func (a *Agent) speedDown(ctx context.Context, path string) (float64, error) {
k, err := resp.Body.Read(buf)
if k > 0 && start.IsZero() {
start = time.Now()
t.Reset(speedWindow)
t.Reset(window)
}
n += int64(k)
if err != nil {