11package tui
22
33import (
4+ "context"
45 "fmt"
56 "strconv"
67 "strings"
@@ -364,7 +365,11 @@ func viewConfig(m Model) string {
364365
365366 // Show binary status after E2E toggle when enabled
366367 if fd .id == fE2E && m .config .E2E {
367- b .WriteString (binaryStatus (strings .TrimSpace (m .configInputs [txtDomain ].Value ())))
368+ domain := strings .TrimSpace (m .configInputs [txtDomain ].Value ())
369+ pubkey := strings .TrimSpace (m .configInputs [txtPubkey ].Value ())
370+ testURL := strings .TrimSpace (m .configInputs [txtTestURL ].Value ())
371+ proxyAuth := strings .TrimSpace (m .configInputs [txtProxyAuth ].Value ())
372+ b .WriteString (binaryStatus (domain , pubkey , testURL , proxyAuth ))
368373 }
369374 }
370375
@@ -407,7 +412,17 @@ var nsCache struct {
407412 loading bool
408413}
409414
410- func binaryStatus (domain string ) string {
415+ // e2eCache stores the cached preflight e2e check result.
416+ var e2eCache struct {
417+ mu sync.Mutex
418+ key string // "domain|pubkey" — invalidate if either changes
419+ result scanner.PreflightE2EResult
420+ done bool
421+ loading bool
422+ cancel context.CancelFunc // cancels in-flight preflight when key changes
423+ }
424+
425+ func binaryStatus (domain , pubkey , testURL , proxyAuth string ) string {
411426 var b strings.Builder
412427 bins := []struct {
413428 name string
@@ -417,12 +432,16 @@ func binaryStatus(domain string) string {
417432 {"slipstream-client" , "slipstream-client" },
418433 {"curl" , "curl" },
419434 }
435+ var dnsttBin string
420436 for _ , bin := range bins {
421437 path , err := binutil .Find (bin .bin )
422438 if err != nil {
423439 b .WriteString (fmt .Sprintf (" %s %s\n " , redStyle .Render ("✘" ), dimStyle .Render (bin .name + " not found" )))
424440 } else {
425441 b .WriteString (fmt .Sprintf (" %s %s\n " , greenStyle .Render ("✔" ), dimStyle .Render (bin .name + " → " + path )))
442+ if bin .bin == "dnstt-client" {
443+ dnsttBin = path
444+ }
426445 }
427446 }
428447 // Verify NS delegation if domain is set (non-blocking)
@@ -447,7 +466,6 @@ func binaryStatus(domain string) string {
447466 go func (d string ) {
448467 hosts , ok := scanner .QueryNSMulti (d , 5 * time .Second )
449468 nsCache .mu .Lock ()
450- // Only store if domain hasn't changed while we were querying
451469 if nsCache .domain == d {
452470 nsCache .hosts = hosts
453471 nsCache .ok = ok
@@ -462,6 +480,49 @@ func binaryStatus(domain string) string {
462480 b .WriteString (fmt .Sprintf (" %s %s\n " , dimStyle .Render ("…" ), dimStyle .Render ("Checking NS delegation..." )))
463481 }
464482 }
483+ // Preflight e2e tunnel check (non-blocking, parallel)
484+ if dnsttBin != "" && domain != "" && pubkey != "" {
485+ cacheKey := domain + "|" + pubkey
486+ e2eCache .mu .Lock ()
487+ if e2eCache .key != cacheKey {
488+ // Cancel any in-flight preflight for the old key
489+ if e2eCache .cancel != nil {
490+ e2eCache .cancel ()
491+ e2eCache .cancel = nil
492+ }
493+ e2eCache .done = false
494+ e2eCache .loading = false
495+ }
496+ if e2eCache .done {
497+ r := e2eCache .result
498+ e2eCache .mu .Unlock ()
499+ if r .OK {
500+ b .WriteString (fmt .Sprintf (" %s %s\n " , greenStyle .Render ("✔" ), dimStyle .Render ("Tunnel preflight → connected via " + r .Resolver )))
501+ } else {
502+ b .WriteString (fmt .Sprintf (" %s %s\n " , redStyle .Render ("✘" ), redStyle .Render ("Tunnel preflight FAILED" )))
503+ }
504+ } else if ! e2eCache .loading {
505+ e2eCache .loading = true
506+ e2eCache .key = cacheKey
507+ ctx , cancel := context .WithCancel (context .Background ())
508+ e2eCache .cancel = cancel
509+ e2eCache .mu .Unlock ()
510+ go func (ctx context.Context , bin , d , pk , tu , pa , key string ) {
511+ r := scanner .PreflightE2EContext (ctx , bin , d , pk , tu , pa , 20 * time .Second )
512+ e2eCache .mu .Lock ()
513+ if e2eCache .key == key {
514+ e2eCache .result = r
515+ e2eCache .done = true
516+ e2eCache .loading = false
517+ }
518+ e2eCache .mu .Unlock ()
519+ }(ctx , dnsttBin , domain , pubkey , testURL , proxyAuth , cacheKey )
520+ b .WriteString (fmt .Sprintf (" %s %s\n " , dimStyle .Render ("…" ), dimStyle .Render ("Testing tunnel connectivity..." )))
521+ } else {
522+ e2eCache .mu .Unlock ()
523+ b .WriteString (fmt .Sprintf (" %s %s\n " , dimStyle .Render ("…" ), dimStyle .Render ("Testing tunnel connectivity..." )))
524+ }
525+ }
465526 return b .String ()
466527}
467528
0 commit comments