@@ -24,17 +24,10 @@ type senderFunc func(ctx context.Context,
2424 measurerCh <- chan model.Measurement , results chan <- model.WireMeasurement ,
2525 errCh chan <- error )
2626
27+ // Measurer is an interface for collecting connection metrics.
2728type Measurer interface {
2829 Start (context.Context , net.Conn ) <- chan model.Measurement
29- }
30-
31- // DefaultMeasurer is the default throughput1 measurer that wraps the measurer
32- // package's Start function.
33- type DefaultMeasurer struct {}
34-
35- func (* DefaultMeasurer ) Start (ctx context.Context ,
36- c net.Conn ) <- chan model.Measurement {
37- return measurer .Start (ctx , c )
30+ Measure (ctx context.Context ) model.Measurement
3831}
3932
4033// Protocol is the implementation of the throughput1 protocol.
@@ -59,7 +52,7 @@ func New(conn *websocket.Conn) *Protocol {
5952 connInfo : netx .ToConnInfo (conn .UnderlyingConn ()),
6053 // Seed randomness source with the current time.
6154 rnd : rand .New (rand .NewSource (time .Now ().UnixMilli ())),
62- measurer : & DefaultMeasurer {} ,
55+ measurer : measurer . New () ,
6356 }
6457}
6558
@@ -185,51 +178,59 @@ func (p *Protocol) receiver(ctx context.Context,
185178 }
186179}
187180
181+ func (p * Protocol ) sendWireMeasurement (ctx context.Context , m model.Measurement ) (* model.WireMeasurement , error ) {
182+ wm := model.WireMeasurement {}
183+ p .once .Do (func () {
184+ wm = p .createWireMeasurement (ctx )
185+ })
186+ wm .Measurement = m
187+ wm .Application = model.ByteCounters {
188+ BytesSent : p .applicationBytesSent .Load (),
189+ BytesReceived : p .applicationBytesReceived .Load (),
190+ }
191+ // Encode as JSON separately so we can read the message size before
192+ // sending.
193+ jsonwm , err := json .Marshal (wm )
194+ if err != nil {
195+ log .Printf ("failed to encode measurement (ctx: %p, err: %v)" , ctx , err )
196+ return nil , err
197+ }
198+ err = p .conn .WriteMessage (websocket .TextMessage , jsonwm )
199+ if err != nil {
200+ log .Printf ("failed to write measurement JSON (ctx: %p, err: %v)" , ctx , err )
201+ return nil , err
202+ }
203+ p .applicationBytesSent .Add (int64 (len (jsonwm )))
204+ return & wm , nil
205+ }
206+
188207func (p * Protocol ) sendCounterflow (ctx context.Context ,
189208 measurerCh <- chan model.Measurement , results chan <- model.WireMeasurement ,
190209 errCh chan <- error ) {
191210 byteLimit := int64 (p .byteLimit )
192211 for {
193212 select {
194213 case <- ctx .Done ():
214+ // Attempt to send final write message before close. Ignore errors.
215+ p .sendWireMeasurement (ctx , p .measurer .Measure (ctx ))
195216 p .close (ctx )
196217 return
197218 case m := <- measurerCh :
198- wm := model.WireMeasurement {}
199- p .once .Do (func () {
200- wm = p .createWireMeasurement (ctx )
201- })
202- wm .Measurement = m
203- wm .Application = model.ByteCounters {
204- BytesSent : p .applicationBytesSent .Load (),
205- BytesReceived : p .applicationBytesReceived .Load (),
206- }
207- // Encode as JSON separately so we can read the message size before
208- // sending.
209- jsonwm , err := json .Marshal (wm )
219+ wm , err := p .sendWireMeasurement (ctx , m )
210220 if err != nil {
211- log .Printf ("failed to encode measurement (ctx: %p, err: %v)" ,
212- ctx , err )
213221 errCh <- err
214222 return
215223 }
216- err = p .conn .WriteMessage (websocket .TextMessage , jsonwm )
217- if err != nil {
218- log .Printf ("failed to write measurement JSON (ctx: %p, err: %v)" , ctx , err )
219- errCh <- err
220- return
221- }
222- p .applicationBytesSent .Add (int64 (len (jsonwm )))
223-
224224 // This send is non-blocking in case there is no one to read the
225225 // Measurement message and the channel's buffer is full.
226226 select {
227- case results <- wm :
227+ case results <- * wm :
228228 default :
229229 }
230230
231231 // End the test once enough bytes have been received.
232232 if byteLimit > 0 && m .TCPInfo != nil && m .TCPInfo .BytesReceived >= byteLimit {
233+ // WireMessage was just sent above, so we do not need to send another.
233234 p .close (ctx )
234235 return
235236 }
@@ -254,39 +255,21 @@ func (p *Protocol) sender(ctx context.Context, measurerCh <-chan model.Measureme
254255 for {
255256 select {
256257 case <- ctx .Done ():
258+ // Attempt to send final write message before close. Ignore errors.
259+ p .sendWireMeasurement (ctx , p .measurer .Measure (ctx ))
257260 p .close (ctx )
258261 return
259262 case m := <- measurerCh :
260- wm := model.WireMeasurement {}
261- p .once .Do (func () {
262- wm = p .createWireMeasurement (ctx )
263- })
264- wm .Measurement = m
265- wm .Application = model.ByteCounters {
266- BytesReceived : p .applicationBytesReceived .Load (),
267- BytesSent : p .applicationBytesSent .Load (),
268- }
269- // Encode as JSON separately so we can read the message size before
270- // sending.
271- jsonwm , err := json .Marshal (wm )
272- if err != nil {
273- log .Printf ("failed to encode measurement (ctx: %p, err: %v)" ,
274- ctx , err )
275- errCh <- err
276- return
277- }
278- err = p .conn .WriteMessage (websocket .TextMessage , jsonwm )
263+ wm , err := p .sendWireMeasurement (ctx , m )
279264 if err != nil {
280- log .Printf ("failed to write measurement JSON (ctx: %p, err: %v)" , ctx , err )
281265 errCh <- err
282266 return
283267 }
284- p .applicationBytesSent .Add (int64 (len (jsonwm )))
285268
286269 // This send is non-blocking in case there is no one to read the
287270 // Measurement message and the channel's buffer is full.
288271 select {
289- case results <- wm :
272+ case results <- * wm :
290273 default :
291274 }
292275 default :
@@ -300,6 +283,11 @@ func (p *Protocol) sender(ctx context.Context, measurerCh <-chan model.Measureme
300283
301284 bytesSent := int (p .applicationBytesSent .Load ())
302285 if p .byteLimit > 0 && bytesSent >= p .byteLimit {
286+ _ , err := p .sendWireMeasurement (ctx , p .measurer .Measure (ctx ))
287+ if err != nil {
288+ errCh <- err
289+ return
290+ }
303291 p .close (ctx )
304292 return
305293 }
0 commit comments