mirror of
https://github.com/status-im/status-go.git
synced 2025-01-12 07:35:02 +00:00
38308d48f2
* feat_: log error and stacktrace when panic in goroutine * test_: add test TestSafeGo * chore_: rename logAndCall to call * chore_: rename SafeGo to Go * chore_: make lint-fix * chore_: use t.Cleanup * chore_: Revert "chore_: use t.Cleanup" This reverts commit 4eb420d179cc0e208e84c13cb941e6b3d1ed9819. * chore_: Revert "chore_: make lint-fix" This reverts commit fcc995f157e671a4229b47419c3a0e4004b5fdab. * chore_: Revert "chore_: rename SafeGo to Go" This reverts commit a6d73d6df583f313032d79aac62f66328039cb55. * chore_: Revert "chore_: rename logAndCall to call" This reverts commit 8fbe993bedb9fbba67349a44f151e2dd5e3bc4cc. * chore_: Revert "test_: add test TestSafeGo" This reverts commit a1fa91839f3960398980c6bf456e6462ec944819. * chore_: Revert "feat_: log error and stacktrace when panic in goroutine" This reverts commit f612dd828fa2ce410d0e806fe773ecbe3e86a68a. * feat_: log error and stacktrace when panic in goroutine * chore_: make lint-fix * chore_: rename logAndCall to call * chore_: renaming LogOnPanic * chore_: update rest goroutine function calls * chore_: make lint-fix
103 lines
2.3 KiB
Go
103 lines
2.3 KiB
Go
package rtt
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
errors "github.com/pkg/errors"
|
|
tcp "github.com/status-im/tcp-shaker"
|
|
|
|
gocommon "github.com/status-im/status-go/common"
|
|
)
|
|
|
|
type Result struct {
|
|
Addr string
|
|
RTTMs int
|
|
Err error
|
|
}
|
|
|
|
// timeoutError indicates an error due to TCP connection timeout.
|
|
// tcp-shaker returns an error implementing this interface in such a case.
|
|
type timeoutError interface {
|
|
Timeout() bool
|
|
}
|
|
|
|
func runCheck(c *tcp.Checker, address string, timeout time.Duration) Result {
|
|
// mesaure RTT
|
|
start := time.Now()
|
|
// TCP Ping
|
|
err := c.CheckAddr(address, timeout)
|
|
// measure RTT
|
|
elapsed := time.Since(start)
|
|
latency := int(elapsed.Nanoseconds() / 1e6)
|
|
|
|
if err != nil { // don't confuse users with valid latency values on error
|
|
latency = -1
|
|
switch err.(type) {
|
|
case timeoutError:
|
|
err = errors.Wrap(err, "tcp check timeout")
|
|
case tcp.ErrConnect:
|
|
err = errors.Wrap(err, "unable to connect")
|
|
}
|
|
}
|
|
|
|
return Result{
|
|
Addr: address,
|
|
RTTMs: latency,
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
func waitForResults(errCh <-chan error, resCh <-chan Result) (results []Result, err error) {
|
|
for {
|
|
select {
|
|
case err = <-errCh:
|
|
return nil, err
|
|
case res, ok := <-resCh:
|
|
if !ok {
|
|
return
|
|
}
|
|
results = append(results, res)
|
|
}
|
|
}
|
|
}
|
|
|
|
func CheckHosts(addresses []string, timeout time.Duration) ([]Result, error) {
|
|
c := tcp.NewChecker()
|
|
|
|
// channel for receiving possible checking loop failure
|
|
errCh := make(chan error, 1)
|
|
|
|
// stop the checking loop when function exists
|
|
ctx, stopChecker := context.WithCancel(context.Background())
|
|
defer stopChecker()
|
|
|
|
// loop that queries Epoll and pipes events to CheckAddr() calls
|
|
go func() {
|
|
defer gocommon.LogOnPanic()
|
|
errCh <- c.CheckingLoop(ctx)
|
|
}()
|
|
// wait for CheckingLoop to prepare the epoll/kqueue
|
|
<-c.WaitReady()
|
|
|
|
// channel for returning results from concurrent checks
|
|
resCh := make(chan Result, len(addresses))
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < len(addresses); i++ {
|
|
wg.Add(1)
|
|
go func(address string, resCh chan<- Result) {
|
|
defer gocommon.LogOnPanic()
|
|
defer wg.Done()
|
|
resCh <- runCheck(c, address, timeout)
|
|
}(addresses[i], resCh)
|
|
}
|
|
// wait for all the routines to finish before closing results channel
|
|
wg.Wait()
|
|
close(resCh)
|
|
|
|
// wait for the results for all addresses or a checking loop error
|
|
return waitForResults(errCh, resCh)
|
|
}
|