forked from cloverstd/tcping
/
ping.go
149 lines (129 loc) · 3.08 KB
/
ping.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
package ping
import (
"bytes"
"fmt"
"html/template"
"regexp"
"strconv"
"strings"
"time"
)
// Protocol ...
type Protocol int
func (protocol Protocol) String() string {
switch protocol {
case TCP:
return "tcp"
case HTTP:
return "http"
case HTTPS:
return "https"
}
return "unkown"
}
const (
// TCP is tcp protocol
TCP Protocol = iota
// HTTP is http protocol
HTTP
// HTTPS is https protocol
HTTPS
)
// NewProtocol convert protocol stirng to Protocol
func NewProtocol(protocol string) (Protocol, error) {
switch strings.ToLower(protocol) {
case TCP.String():
return TCP, nil
case HTTP.String():
return HTTP, nil
case HTTPS.String():
return HTTPS, nil
}
return 0, fmt.Errorf("protocol %s not support", protocol)
}
// Target is a ping
type Target struct {
Protocol Protocol
Host string
Port int
Counter int
Interval time.Duration
Timeout time.Duration
}
func (target Target) String() string {
return fmt.Sprintf("%s://%s:%d", target.Protocol, target.Host, target.Port)
}
// Pinger is a ping interface
type Pinger interface {
Start() <-chan struct{}
Stop()
Result() *Result
SetTarget(target *Target)
}
// Ping is a ping interface
type Ping interface {
Start() <-chan struct{}
Host() string
Port() int
Protocol() Protocol
Counter() int
Stop()
Result() Result
}
// Result ...
type Result struct {
Counter int
SuccessCounter int
Target *Target
MinDuration time.Duration
MaxDuration time.Duration
TotalDuration time.Duration
}
// Avg return the average time of ping
func (result Result) Avg() time.Duration {
if result.SuccessCounter == 0 {
return 0
}
return result.TotalDuration / time.Duration(result.SuccessCounter)
}
// Failed return failed counter
func (result Result) Failed() int {
return result.Counter - result.SuccessCounter
}
func (result Result) String() string {
const resultTpl = `
Ping statistics {{.Target}}
{{.Counter}} probes sent.
{{.SuccessCounter}} successful, {{.Failed}} failed.
Approximate trip times:
Minimum = {{.MinDuration}}, Maximum = {{.MaxDuration}}, Average = {{.Avg}}`
t := template.Must(template.New("result").Parse(resultTpl))
res := bytes.NewBufferString("")
t.Execute(res, result)
return res.String()
}
// CheckURI check uri
func CheckURI(uri string) (schema, host string, port int, matched bool) {
const reExp = `^((?P<schema>((ht|f)tp(s?))|tcp)\://)?((([a-zA-Z0-9_\-]+\.)+[a-zA-Z]{2,})|((?:(?:25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)((\.?\d)\.)){4})|(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9]))(:([0-9]+))?(/[a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~]*)?$`
pattern := regexp.MustCompile(reExp)
res := pattern.FindStringSubmatch(uri)
if len(res) == 0 {
return
}
matched = true
schema = res[2]
if schema == "" {
schema = "tcp"
}
host = res[6]
if res[17] == "" {
if schema == HTTPS.String() {
port = 443
} else {
port = 80
}
} else {
port, _ = strconv.Atoi(res[17])
}
return
}