-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
158 lines (140 loc) · 3.69 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package main
import (
"context"
"fmt"
"io/ioutil"
"log"
"os"
"os/signal"
"strconv"
"syscall"
"time"
"github.com/e11jah/air-force/ping"
"github.com/e11jah/air-force/subscribe"
"github.com/spf13/cobra"
)
var (
debug bool
showVersion bool
version string
gitCommit string
url string
counter int
pingTimeout string
interval string
sigs chan os.Signal
)
func init() {
rootCmd.Flags().BoolVarP(&debug, "debug", "D", false, "show the debug log")
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
rootCmd.Flags().IntVarP(&counter, "counter", "c", 4, "ping counter")
rootCmd.Flags().StringVarP(&pingTimeout, "timeout", "T", "1s", `connect timeout for every ping, units are "ns", "us" (or "µs"), "ms", "s", "m", "h"`)
rootCmd.Flags().StringVarP(&interval, "interval", "I", "500ms", `ping interval, units are "ns", "us" (or "µs"), "ms", "s", "m", "h"`)
}
var rootCmd = cobra.Command{
Use: "test speed of tcp ping for nodes of your subscribe link, Usage: air-force \"your subscribe link\"",
Short: "test speed of tcp ping ",
Run: func(cmd *cobra.Command, args []string) {
if showVersion {
fmt.Printf("version: %s\n", version)
fmt.Printf("git: %s\n", gitCommit)
return
}
if len(args) != 1 {
cmd.Usage()
return
}
var (
timeoutDuration time.Duration
intervalDuration time.Duration
)
if res, err := strconv.Atoi(pingTimeout); err == nil {
timeoutDuration = time.Duration(res) * time.Millisecond
} else {
timeoutDuration, err = time.ParseDuration(pingTimeout)
if err != nil {
fmt.Printf("parse timeout failed, %s\n", err)
cmd.Usage()
return
}
}
if res, err := strconv.Atoi(interval); err == nil {
intervalDuration = time.Duration(res) * time.Millisecond
} else {
intervalDuration, err = time.ParseDuration(interval)
if err != nil {
fmt.Printf("parse interval failed, %s\n", err)
cmd.Usage()
return
}
}
if !debug {
log.SetOutput(ioutil.Discard)
}
url = args[0]
ctx := context.Background()
configs, err := subscribe.LoadConfigs(ctx, url)
if err != nil {
fmt.Printf("can not subscribe url '%s', err: %s\n", url, err)
return
}
if len(configs) < 1 {
fmt.Printf("can not load configs from url '%s', plz see debug info", url)
return
}
totalTimeout := timeoutDuration * time.Duration(counter*len(configs))
ctx, cancel := context.WithTimeout(ctx, totalTimeout)
defer cancel()
pinger := ping.NewTCPing(1)
defer pinger.Close()
for _, cfg := range configs {
port, err := strconv.Atoi(cfg.Port)
if err != nil {
log.Printf("parse port of config '%v' error, %s\n", cfg, err)
continue
}
go pinger.AsyncPing(ctx, &ping.Target{
Protocol: ping.TCP,
Name: cfg.Name,
Host: cfg.Addr,
Port: port,
Counter: counter,
Interval: intervalDuration,
Timeout: timeoutDuration,
})
}
resultCh := pinger.GetResult()
cnt := len(configs)
var fastestResult *ping.Result
loop:
for {
select {
case <-sigs:
fmt.Println("exit")
return
case <-ctx.Done():
fmt.Printf("timeout: %s, context exit: %s\n", totalTimeout, ctx.Err())
return
case result := <-resultCh:
cnt--
if fastestResult == nil {
fastestResult = result
} else if result.Success >= fastestResult.Success && result.Avg() < fastestResult.Avg() {
fastestResult = result
}
if cnt <= 0 {
break loop
}
}
}
fmt.Printf("\nfastest ping result: %s\n", fastestResult)
},
}
func main() {
sigs = make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, "Error:", err)
os.Exit(1)
}
}