Skip to content

Commit fa801c5

Browse files
committed
Merge remote-tracking branch 'origin/master' into prevent-tooltip-flicker
2 parents 33bb604 + 15a8055 commit fa801c5

File tree

13 files changed

+53
-50
lines changed

13 files changed

+53
-50
lines changed

client/client.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ import (
2121
"github.com/TwiN/gocache/v2"
2222
"github.com/TwiN/logr"
2323
"github.com/TwiN/whois"
24+
"github.com/gorilla/websocket"
2425
"github.com/ishidawataru/sctp"
2526
"github.com/miekg/dns"
2627
ping "github.com/prometheus-community/pro-bing"
2728
"github.com/registrobr/rdap"
2829
"github.com/registrobr/rdap/protocol"
2930
"golang.org/x/crypto/ssh"
30-
"golang.org/x/net/websocket"
3131
)
3232

3333
const (
@@ -394,48 +394,53 @@ func ShouldRunPingerAsPrivileged() bool {
394394
// QueryWebSocket opens a websocket connection, write `body` and return a message from the server
395395
func QueryWebSocket(address, body string, headers map[string]string, config *Config) (bool, []byte, error) {
396396
const (
397-
Origin = "http://localhost/"
398-
MaximumMessageSize = 1024 // in bytes
397+
Origin = "http://localhost/"
399398
)
400-
wsConfig, err := websocket.NewConfig(address, Origin)
401-
if err != nil {
402-
return false, nil, fmt.Errorf("error configuring websocket connection: %w", err)
403-
}
404-
if headers != nil {
405-
if wsConfig.Header == nil {
406-
wsConfig.Header = make(http.Header)
407-
}
408-
for name, value := range headers {
409-
wsConfig.Header.Set(name, value)
399+
var (
400+
dialer = websocket.Dialer{
401+
EnableCompression: true,
410402
}
403+
wsHeaders = make(http.Header)
404+
)
405+
406+
wsHeaders.Set("Origin", Origin)
407+
for name, value := range headers {
408+
wsHeaders.Set(name, value)
411409
}
410+
411+
ctx := context.Background()
412412
if config != nil {
413-
wsConfig.Dialer = &net.Dialer{Timeout: config.Timeout}
414-
wsConfig.TlsConfig = &tls.Config{
413+
if config.Timeout > 0 {
414+
var cancel context.CancelFunc
415+
ctx, cancel = context.WithTimeout(ctx, config.Timeout)
416+
defer cancel()
417+
}
418+
dialer.TLSClientConfig = &tls.Config{
415419
InsecureSkipVerify: config.Insecure,
416420
}
417421
if config.HasTLSConfig() && config.TLS.isValid() == nil {
418-
wsConfig.TlsConfig = configureTLS(wsConfig.TlsConfig, *config.TLS)
422+
dialer.TLSClientConfig = configureTLS(dialer.TLSClientConfig, *config.TLS)
419423
}
420424
}
421425
// Dial URL
422-
ws, err := websocket.DialConfig(wsConfig)
426+
ws, _, err := dialer.DialContext(ctx, address, wsHeaders)
423427
if err != nil {
424428
return false, nil, fmt.Errorf("error dialing websocket: %w", err)
425429
}
426430
defer ws.Close()
427431
body = parseLocalAddressPlaceholder(body, ws.LocalAddr())
428432
// Write message
429-
if _, err := ws.Write([]byte(body)); err != nil {
433+
if err := ws.WriteMessage(websocket.TextMessage, []byte(body)); err != nil {
430434
return false, nil, fmt.Errorf("error writing websocket body: %w", err)
431435
}
432436
// Read message
433-
var n int
434-
msg := make([]byte, MaximumMessageSize)
435-
if n, err = ws.Read(msg); err != nil {
437+
msgType, msg, err := ws.ReadMessage()
438+
if err != nil {
436439
return false, nil, fmt.Errorf("error reading websocket message: %w", err)
440+
} else if msgType != websocket.TextMessage && msgType != websocket.BinaryMessage {
441+
return false, nil, fmt.Errorf("unexpected websocket message type: %d, expected %d or %d", msgType, websocket.TextMessage, websocket.BinaryMessage)
437442
}
438-
return true, msg[:n], nil
443+
return true, msg, nil
439444
}
440445

441446
func QueryDNS(queryType, queryName, url string) (connected bool, dnsRcode string, body []byte, err error) {

client/client_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
)
1818

1919
func TestGetHTTPClient(t *testing.T) {
20+
t.Parallel()
2021
cfg := &Config{
2122
Insecure: false,
2223
IgnoreRedirect: false,
@@ -42,6 +43,7 @@ func TestGetHTTPClient(t *testing.T) {
4243
}
4344

4445
func TestRdapQuery(t *testing.T) {
46+
t.Parallel()
4547
if _, err := rdapQuery("1.1.1.1"); err == nil {
4648
t.Error("expected an error due to the invalid domain type")
4749
}
@@ -157,7 +159,6 @@ func TestShouldRunPingerAsPrivileged(t *testing.T) {
157159
}
158160
}
159161

160-
161162
func TestCanPerformStartTLS(t *testing.T) {
162163
type args struct {
163164
address string
@@ -289,6 +290,7 @@ func TestCanPerformTLS(t *testing.T) {
289290
}
290291

291292
func TestCanCreateConnection(t *testing.T) {
293+
t.Parallel()
292294
connected, _ := CanCreateNetworkConnection("tcp", "127.0.0.1", "", &Config{Timeout: 5 * time.Second})
293295
if connected {
294296
t.Error("should've failed, because there's no port in the address")
@@ -303,6 +305,7 @@ func TestCanCreateConnection(t *testing.T) {
303305
// performs a Client Credentials OAuth2 flow and adds the obtained token as a `Authorization`
304306
// header to all outgoing HTTP calls.
305307
func TestHttpClientProvidesOAuth2BearerToken(t *testing.T) {
308+
t.Parallel()
306309
defer InjectHTTPClient(nil)
307310
oAuth2Config := &OAuth2Config{
308311
ClientID: "00000000-0000-0000-0000-000000000000",
@@ -358,6 +361,7 @@ func TestHttpClientProvidesOAuth2BearerToken(t *testing.T) {
358361
}
359362

360363
func TestQueryWebSocket(t *testing.T) {
364+
t.Parallel()
361365
_, _, err := QueryWebSocket("", "body", nil, &Config{Timeout: 2 * time.Second})
362366
if err == nil {
363367
t.Error("expected an error due to the address being invalid")
@@ -369,6 +373,7 @@ func TestQueryWebSocket(t *testing.T) {
369373
}
370374

371375
func TestTlsRenegotiation(t *testing.T) {
376+
t.Parallel()
372377
scenarios := []struct {
373378
name string
374379
cfg TLSConfig
@@ -412,6 +417,7 @@ func TestTlsRenegotiation(t *testing.T) {
412417
}
413418

414419
func TestQueryDNS(t *testing.T) {
420+
t.Parallel()
415421
scenarios := []struct {
416422
name string
417423
inputDNS dns.Config
@@ -468,7 +474,7 @@ func TestQueryDNS(t *testing.T) {
468474
},
469475
inputURL: "8.8.8.8",
470476
expectedDNSCode: "NOERROR",
471-
expectedBody: "*.iana-servers.net.",
477+
expectedBody: "*.ns.cloudflare.com.",
472478
},
473479
{
474480
name: "test Config with type PTR",
@@ -541,6 +547,7 @@ func TestQueryDNS(t *testing.T) {
541547
}
542548

543549
func TestCheckSSHBanner(t *testing.T) {
550+
t.Parallel()
544551
cfg := &Config{Timeout: 3}
545552
t.Run("no-auth-ssh", func(t *testing.T) {
546553
connected, status, err := CheckSSHBanner("tty.sdf.org", cfg)

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require (
2020
github.com/gofiber/fiber/v2 v2.52.9
2121
github.com/google/go-github/v48 v48.2.0
2222
github.com/google/uuid v1.6.0
23+
github.com/gorilla/websocket v1.5.3
2324
github.com/ishidawataru/sctp v0.0.0-20230406120618-7ff4192f6ff2
2425
github.com/lib/pq v1.10.9
2526
github.com/miekg/dns v1.1.68
@@ -29,7 +30,6 @@ require (
2930
github.com/valyala/fasthttp v1.67.0
3031
github.com/wcharczuk/go-chart/v2 v2.1.2
3132
golang.org/x/crypto v0.45.0
32-
golang.org/x/net v0.47.0
3333
golang.org/x/oauth2 v0.32.0
3434
golang.org/x/sync v0.18.0
3535
google.golang.org/api v0.252.0
@@ -93,6 +93,7 @@ require (
9393
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
9494
golang.org/x/image v0.18.0 // indirect
9595
golang.org/x/mod v0.29.0 // indirect
96+
golang.org/x/net v0.47.0 // indirect
9697
golang.org/x/sys v0.38.0 // indirect
9798
golang.org/x/text v0.31.0 // indirect
9899
golang.org/x/tools v0.38.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU
101101
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
102102
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
103103
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
104+
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
105+
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
104106
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
105107
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
106108
github.com/ishidawataru/sctp v0.0.0-20230406120618-7ff4192f6ff2 h1:i2fYnDurfLlJH8AyyMOnkLHnHeP8Ff/DDpuZA/D3bPo=

web/app/src/components/EndpointCard.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ const formattedResponseTime = computed(() => {
142142
return `~${avgMs}ms`
143143
} else {
144144
// Show min-max range
145-
const minMs = Math.round(min)
146-
const maxMs = Math.round(max)
145+
const minMs = Math.trunc(min)
146+
const maxMs = Math.trunc(max)
147147
// If min and max are the same, show single value
148148
if (minMs === maxMs) {
149149
return `${minMs}ms`

web/app/src/components/SuiteCard.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<div>
3232
<div class="flex items-center justify-between mb-1">
3333
<p class="text-xs text-muted-foreground">Success Rate: {{ successRate }}%</p>
34-
<p class="text-xs text-muted-foreground" v-if="averageDuration">{{ averageDuration }}ms avg</p>
34+
<p class="text-xs text-muted-foreground" v-if="averageDuration !== null">{{ averageDuration }}ms avg</p>
3535
</div>
3636
<div :class="['flex gap-0.5', lastHoverIndex !== null && 'cursor-pointer']"
3737
@mouseleave="clearTooltip()">
@@ -133,7 +133,7 @@ const averageDuration = computed(() => {
133133
134134
const total = props.suite.results.reduce((sum, r) => sum + (r.duration || 0), 0)
135135
// Convert nanoseconds to milliseconds
136-
return Math.round((total / props.suite.results.length) / 1000000)
136+
return Math.trunc((total / props.suite.results.length) / 1000000)
137137
})
138138
139139
const oldestResultTime = computed(() => {

web/app/src/components/Tooltip.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
{{ endpoint.success ? '✓' : '✗' }}
4747
</span>
4848
<span class="truncate">{{ endpoint.name }}</span>
49-
<span class="text-muted-foreground">({{ (endpoint.duration / 1000000).toFixed(0) }}ms)</span>
49+
<span class="text-muted-foreground">({{ Math.trunc(endpoint.duration / 1000000) }}ms)</span>
5050
</div>
5151
<div v-if="result.endpointResults.length > 5" class="text-xs text-muted-foreground">
5252
... and {{ result.endpointResults.length - 5 }} more
@@ -60,7 +60,7 @@
6060
{{ isSuiteResult ? 'Total Duration' : 'Response Time' }}
6161
</div>
6262
<div class="font-mono text-xs">
63-
{{ isSuiteResult ? (result.duration / 1000000).toFixed(0) : (result.duration / 1000000).toFixed(0) }}ms
63+
{{ Math.trunc(result.duration / 1000000) }}ms
6464
</div>
6565
</div>
6666

web/app/src/utils/format.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const formatDuration = (duration) => {
1010
const durationMs = duration / 1000000
1111

1212
if (durationMs < 1000) {
13-
return `${durationMs.toFixed(0)}ms`
13+
return `${Math.trunc(durationMs)}ms`
1414
} else {
1515
return `${(durationMs / 1000).toFixed(2)}s`
1616
}

web/app/src/views/EndpointDetails.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ const pageResponseTimeRange = computed(() => {
281281
}
282282
283283
if (!hasData) return 'N/A'
284-
const minMs = Math.round(min / 1000000)
285-
const maxMs = Math.round(max / 1000000)
284+
const minMs = Math.trunc(min / 1000000)
285+
const maxMs = Math.trunc(max / 1000000)
286286
// If min and max are the same, show single value
287287
if (minMs === maxMs) {
288288
return `${minMs}ms`

web/app/src/views/SuiteDetails.vue

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ import StepDetailsModal from '@/components/StepDetailsModal.vue'
153153
import Settings from '@/components/Settings.vue'
154154
import Loading from '@/components/Loading.vue'
155155
import { generatePrettyTimeAgo } from '@/utils/time'
156+
import { formatDuration } from '@/utils/format'
156157
157158
const router = useRouter()
158159
const route = useRoute()
@@ -238,19 +239,6 @@ const formatTimestamp = (timestamp) => {
238239
return date.toLocaleString()
239240
}
240241
241-
const formatDuration = (duration) => {
242-
if (!duration && duration !== 0) return 'N/A'
243-
244-
// Convert nanoseconds to milliseconds
245-
const durationMs = duration / 1000000
246-
247-
if (durationMs < 1000) {
248-
return `${durationMs.toFixed(0)}ms`
249-
} else {
250-
return `${(durationMs / 1000).toFixed(2)}s`
251-
}
252-
}
253-
254242
const calculateSuccessRate = (result) => {
255243
if (!result || !result.endpointResults || result.endpointResults.length === 0) {
256244
return 0

0 commit comments

Comments
 (0)