diff --git a/speedtest/data_manager.go b/speedtest/data_manager.go index 5d80720..04546ac 100644 --- a/speedtest/data_manager.go +++ b/speedtest/data_manager.go @@ -55,7 +55,7 @@ type Chunk interface { Read(b []byte) (n int, err error) } -const readChunkSize = 1024 * 32 // 32 KBytes +const readChunkSize = 1024 // 1 KBytes with higher frequency rate feedback type DataType int32 @@ -448,23 +448,38 @@ func (dc *DataChunk) GetParent() Manager { return dc.manager } -func (dc *DataChunk) Read(b []byte) (n int, err error) { - if !dc.manager.running { - return n, io.EOF - } - if dc.remainOrDiscardSize < readChunkSize { - if dc.remainOrDiscardSize <= 0 { +// WriteTo Used to hook all traffic. +func (dc *DataChunk) WriteTo(w io.Writer) (written int64, err error) { + nw := 0 + nr := readChunkSize + for { + if !dc.manager.running || dc.remainOrDiscardSize <= 0 { dc.endTime = time.Now() - return n, io.EOF + return written, io.EOF + } + if dc.remainOrDiscardSize < readChunkSize { + nr = int(dc.remainOrDiscardSize) + nw, err = w.Write((*dc.manager.repeatByte)[:nr]) + } else { + nw, err = w.Write(*dc.manager.repeatByte) + } + if err != nil { + return + } + n64 := int64(nw) + written += n64 + dc.remainOrDiscardSize -= n64 + dc.manager.AddTotalUpload(n64) + if nr != nw { + return written, io.ErrShortWrite } - n = copy(b, (*dc.manager.repeatByte)[:dc.remainOrDiscardSize]) - } else { - n = copy(b, *dc.manager.repeatByte) } - n64 := int64(n) - dc.remainOrDiscardSize -= n64 - atomic.AddInt64(&dc.manager.upload.totalDataVolume, n64) - return +} + +// Please don't call it, only used to wrapped by [io.NopCloser] +// We use [DataChunk.WriteTo] that implements [io.WriterTo] to bypass this function. +func (dc *DataChunk) Read(b []byte) (n int, err error) { + panic("unexpected call: only used to implement the io.Reader") } // calcMAFilter Median-Averaging Filter diff --git a/speedtest/request.go b/speedtest/request.go index 54acd6b..f188d56 100644 --- a/speedtest/request.go +++ b/speedtest/request.go @@ -186,13 +186,11 @@ func downloadRequest(ctx context.Context, s *Server, w int) error { func uploadRequest(ctx context.Context, s *Server, w int) error { size := ulSizes[w] dc := s.Context.NewChunk().UploadHandler(int64(size*100-51) * 10) - req, err := http.NewRequestWithContext(ctx, http.MethodPost, s.URL, dc) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, s.URL, io.NopCloser(dc)) if err != nil { return err } - req.ContentLength = dc.(*DataChunk).ContentLength dbg.Printf("Len=%d, XulURL: %s\n", req.ContentLength, s.URL) - req.Header.Set("Content-Type", "application/octet-stream") resp, err := s.Context.doer.Do(req) if err != nil {