Skip to content

Commit

Permalink
[add] http ping
Browse files Browse the repository at this point in the history
  • Loading branch information
cloverstd committed Jun 26, 2017
1 parent 1edaad7 commit 163b173
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 63 deletions.
21 changes: 19 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,31 @@ var rootCmd = cobra.Command{
return
}
}
var pinger ping.Ping
protocol, err := ping.NewProtocol(schema)
if err != nil {
fmt.Println(err)
cmd.Usage()
return
}
target := ping.Target{
Timeout: timeoutDuration,
Interval: intervalDuration,
Host: host,
Port: port,
Counter: counter,
Protocol: protocol,
}
var pinger ping.Pinger
if schema == ping.TCP.String() {
pinger = ping.NewTCPing(host, port, ping.TCP, counter, timeoutDuration, intervalDuration)
pinger = ping.NewTCPing()
} else if schema == ping.HTTP.String() {
pinger = ping.NewHTTPing()
} else {
fmt.Printf("schema: %s not support\n", schema)
cmd.Usage()
return
}
pinger.SetTarget(&target)
pingerDone := pinger.Start()
select {
case <-pingerDone:
Expand Down
105 changes: 105 additions & 0 deletions ping/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package ping

import (
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
)

// HTTPing ...
type HTTPing struct {
target *Target
done chan struct{}
result *Result
Method string
}

var _ Pinger = (*HTTPing)(nil)

// NewHTTPing return new HTTPing
func NewHTTPing() *HTTPing {
return &HTTPing{
done: make(chan struct{}),
Method: "GET",
}
}

// SetTarget ...
func (ping *HTTPing) SetTarget(target *Target) {
ping.target = target
if ping.result == nil {
ping.result = &Result{Target: target}
}
}

// Start ping
func (ping *HTTPing) Start() <-chan struct{} {
go func() {
t := time.NewTicker(ping.target.Interval)
for {
select {
case <-t.C:
if ping.result.Counter >= ping.target.Counter && ping.target.Counter != 0 {
ping.Stop()
return
}
duration, resp, err := ping.ping()
ping.result.Counter++

if err != nil {
fmt.Printf("Ping %s - failed: %s\n", ping.target, err)
} else {
defer resp.Body.Close()
length, _ := io.Copy(ioutil.Discard, resp.Body)
fmt.Printf("Ping %s - HTTP is open - time=%s status=%d bytes=%d\n", ping.target, duration, resp.StatusCode, length)
if ping.result.MinDuration == 0 {
ping.result.MinDuration = duration
}
if ping.result.MaxDuration == 0 {
ping.result.MaxDuration = duration
}
ping.result.SuccessCounter++
if duration > ping.result.MaxDuration {
ping.result.MaxDuration = duration
} else if duration < ping.result.MinDuration {
ping.result.MinDuration = duration
}
ping.result.TotalDuration += duration
}
case <-ping.done:
return
}
}
}()
return ping.done
}

// Result return ping result
func (ping *HTTPing) Result() *Result {
return ping.result
}

// Stop the tcping
func (ping *HTTPing) Stop() {
ping.done <- struct{}{}
}

func (ping HTTPing) ping() (time.Duration, *http.Response, error) {
var resp *http.Response
req, err := http.NewRequest(ping.Method, ping.target.String(), nil)
if err != nil {
return 0, nil, err
}
duration, errIfce := timeIt(func() interface{} {
client := http.Client{Timeout: ping.target.Timeout}
resp, err = client.Do(req)
return err
})
if errIfce != nil {
err := errIfce.(error)
return 0, nil, err
}
return time.Duration(duration), resp, nil
}
60 changes: 49 additions & 11 deletions ping/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,17 @@ package ping

import (
"bytes"
"fmt"
"html/template"
"regexp"
"strconv"
"strings"
"time"
)

// Protocol ...
type Protocol int

const (
// TCP is tcp protocol
TCP Protocol = iota
// HTTP is http protocol
HTTP
// HTTPS is https protocol
HTTPS
)

func (protocol Protocol) String() string {
switch protocol {
case TCP:
Expand All @@ -32,6 +25,51 @@ func (protocol Protocol) String() string {
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{}
Expand All @@ -50,7 +88,7 @@ type Ping interface {
type Result struct {
Counter int
SuccessCounter int
Pinger Ping
Target *Target

MinDuration time.Duration
MaxDuration time.Duration
Expand All @@ -72,7 +110,7 @@ func (result Result) Failed() int {

func (result Result) String() string {
const resultTpl = `
Ping statistics {{.Pinger.Protocol}}://{{.Pinger.Host}}:{{.Pinger.Port}}
Ping statistics {{.Target}}
{{.Counter}} probes sent.
{{.SuccessCounter}} successful, {{.Failed}} failed.
Approximate trip times:
Expand Down
75 changes: 25 additions & 50 deletions ping/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,78 +8,59 @@ import (

// TCPing ...
type TCPing struct {
host string
port int

protocol Protocol
counter int
timeout time.Duration
done chan struct{}
interval time.Duration
result Result
target *Target
done chan struct{}
result *Result
}

var _ Ping = (*TCPing)(nil)
var _ Pinger = (*TCPing)(nil)

// NewTCPing return a new TCPing
func NewTCPing(host string, port int, protocol Protocol, counter int, timeout time.Duration, interval time.Duration) *TCPing {
func NewTCPing() *TCPing {
tcping := TCPing{
host: host,
port: port,
protocol: protocol,
counter: counter,
timeout: timeout,
interval: interval,
done: make(chan struct{}),
}
tcping.result = Result{
Pinger: &tcping,
done: make(chan struct{}),
}
return &tcping
}

// Host return the host of ping
func (tcping TCPing) Host() string {
return tcping.host
}

// Port return the port of ping
func (tcping TCPing) Port() int {
return tcping.port
}

// Protocol return the ping protocol
func (tcping TCPing) Protocol() Protocol {
return tcping.protocol
// SetTarget set target for TCPing
func (tcping *TCPing) SetTarget(target *Target) {
tcping.target = target
if tcping.result == nil {
tcping.result = &Result{Target: target}
}
}

// Counter return the ping counter
func (tcping TCPing) Counter() int {
return tcping.counter
// Result return the result
func (tcping TCPing) Result() *Result {
return tcping.result
}

// Start the tcping
func (tcping *TCPing) Start() <-chan struct{} {
// Start a tcping
func (tcping TCPing) Start() <-chan struct{} {
go func() {
t := time.NewTicker(tcping.interval)
t := time.NewTicker(tcping.target.Interval)
for {
select {
case <-t.C:
if tcping.result.Counter >= tcping.counter && tcping.counter != 0 {
if tcping.result.Counter >= tcping.target.Counter && tcping.target.Counter != 0 {
tcping.Stop()
return
}
duration, err := tcping.ping()
tcping.result.Counter++

if err != nil {
fmt.Printf("Ping %s://%s:%d - failed: %s\n", tcping.protocol, tcping.host, tcping.port, err)
fmt.Printf("Ping %s - failed: %s\n", tcping.target, err)
} else {
fmt.Printf("Ping %s - Connected - time=%s\n", tcping.target, duration)

if tcping.result.MinDuration == 0 {
tcping.result.MinDuration = duration
}
if tcping.result.MaxDuration == 0 {
tcping.result.MaxDuration = duration
}
fmt.Printf("Ping %s://%s:%d - Connected - time=%s\n", tcping.protocol, tcping.host, tcping.port, duration)
tcping.result.SuccessCounter++
if duration > tcping.result.MaxDuration {
tcping.result.MaxDuration = duration
Expand All @@ -88,7 +69,6 @@ func (tcping *TCPing) Start() <-chan struct{} {
}
tcping.result.TotalDuration += duration
}
tcping.result.Counter++
case <-tcping.done:
return
}
Expand All @@ -104,7 +84,7 @@ func (tcping *TCPing) Stop() {

func (tcping TCPing) ping() (time.Duration, error) {
duration, errIfce := timeIt(func() interface{} {
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", tcping.host, tcping.port), tcping.timeout)
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", tcping.target.Host, tcping.target.Port), tcping.target.Timeout)
if err != nil {
return err
}
Expand All @@ -117,8 +97,3 @@ func (tcping TCPing) ping() (time.Duration, error) {
}
return time.Duration(duration), nil
}

// Result return Result
func (tcping TCPing) Result() Result {
return tcping.result
}

0 comments on commit 163b173

Please # to comment.