feat: measure each direction of the speed test for 7 s (0.0.7)
This commit is contained in:
1 parent
ab8751d436
commit
5155bc36cd
5 files changed
+32
-21
No files matched your search
+17
-11
@@ -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 {
|
||||
|
||||
@@ -184,6 +184,9 @@ type SysSpeedArgs struct {
|
||||
// Relay makes the agent use the relayed streams, which the server pipes
|
||||
// to and from the browser.
|
||||
Relay bool `json:"relay,omitempty"`
|
||||
// WindowMs is how long to measure each direction for; 0 leaves it to the
|
||||
// agent (3 s, all an agent older than 0.0.7 does).
|
||||
WindowMs int `json:"window_ms,omitempty"`
|
||||
}
|
||||
|
||||
// SysSpeedResult is returned for TaskSysSpeed: the agent's HTTP link to the
|
||||
|
||||
@@ -20,17 +20,20 @@ const (
|
||||
// statCacheFor is how long one sample answers every open status page, so
|
||||
// several tabs cost the agent a single reading.
|
||||
statCacheFor = 2 * time.Second
|
||||
// speedWindow is how long the agent is asked to measure each direction
|
||||
// for. An agent older than 0.0.7 keeps to its own 3 s.
|
||||
speedWindow = 7 * time.Second
|
||||
// speedTaskTimeout is how long a speed test may take. One that is not done
|
||||
// by then is answered with what the server has counted itself.
|
||||
speedTaskTimeout = 15 * time.Second
|
||||
speedTaskTimeout = 35 * time.Second
|
||||
// speedDownCap bounds one download stream; speedDownFor ends it if the
|
||||
// agent does not hang up first.
|
||||
speedDownCap = 256 << 20
|
||||
speedDownFor = 6 * time.Second
|
||||
speedDownCap = 1 << 30
|
||||
speedDownFor = 2 * speedWindow
|
||||
speedUpCap = 64 << 20
|
||||
// speedRelayUpFor is how long the agent's upload is passed on to the
|
||||
// browser: the agent's own window with slack.
|
||||
speedRelayUpFor = 4 * time.Second
|
||||
speedRelayUpFor = speedWindow + time.Second
|
||||
)
|
||||
|
||||
// statCache holds the last sample per agent and serializes its refresh.
|
||||
@@ -71,7 +74,7 @@ func (s *Server) handleStatusPage(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
s.render(w, "status.html", map[string]any{"Agent": a})
|
||||
s.render(w, "status.html", map[string]any{"Agent": a, "RelayUpMs": speedRelayUpFor.Milliseconds()})
|
||||
}
|
||||
|
||||
// runTask runs a one-shot task on the agent and waits for its result.
|
||||
@@ -144,7 +147,6 @@ func (s *Server) handleAgentSpeed(w http.ResponseWriter, r *http.Request) {
|
||||
relay := r.URL.Query().Get("relay") != ""
|
||||
m := s.meters.start(id)
|
||||
defer s.meters.stop(id, m)
|
||||
var args []byte
|
||||
if relay {
|
||||
rl := s.relays.get(id)
|
||||
if rl == nil {
|
||||
@@ -152,8 +154,8 @@ func (s *Server) handleAgentSpeed(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
defer s.relays.drop(id, rl)
|
||||
args, _ = json.Marshal(proto.SysSpeedArgs{Relay: true})
|
||||
}
|
||||
args, _ := json.Marshal(proto.SysSpeedArgs{Relay: relay, WindowMs: int(speedWindow.Milliseconds())})
|
||||
res, err := s.runTask(id, proto.TaskSysSpeed, args, speedTaskTimeout)
|
||||
if err != nil {
|
||||
part, ok := m.result()
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<h2>Скорость соединения</h2>
|
||||
<p class="muted">Клиент замеряет свой канал до хоста панели - тот же, по которому идут терминал, файлы и http-проброс.
|
||||
С галочкой «До браузера» данные идут дальше, через панель до этого браузера и обратно: так виден весь путь клиент - панель - браузер.
|
||||
Замер занимает около 7 секунд, не дольше 20, и на это время нагружает канал.</p>
|
||||
Замер занимает около 15 секунд, не дольше 40, и на это время нагружает канал.</p>
|
||||
<div class="row">
|
||||
<button id="speed-btn" type="button">Замерить скорость</button>
|
||||
<label class="check" title="Данные пойдут не только между клиентом и хостом панели, а через панель до этого браузера и обратно">
|
||||
@@ -225,7 +225,7 @@
|
||||
return rd.read().then(function (c) {
|
||||
if (c.done) return done();
|
||||
last = performance.now();
|
||||
if (!st.start) { st.start = last; setTimeout(st.stop, 4000); onFirst(); }
|
||||
if (!st.start) { st.start = last; setTimeout(st.stop, {{.RelayUpMs}}); onFirst(); }
|
||||
else st.n += c.value.length;
|
||||
return pump();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user