| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- // Defines a wrapper around the system ping binary.
- //
- // NOTE(os): may fail with non-unix compliant system ping binaries.
- package pingo
- import (
- "errors"
- "os/exec"
- "strconv"
- "strings"
- )
- // runPing returns the byte array as returned by [exec.Command]
- //
- // NOTE(os): this function may fail on non-unix compliant implementations of the Ping spec.
- func runPing(address string) (delay *[]byte, err error) {
- out, err := exec.Command("ping", address, "-c 1").Output()
- if err != nil {
- return nil, err
- }
- return &out, err
- }
- // splitBytesToLines splits bytes as returned by [pingstats.runPing] into an
- // array of strings by newline
- func splitBytesToLines(bytes *[]byte) (lines []string) {
- return strings.Split(strings.ReplaceAll(string(*bytes), "\r\n", "\n"), "\n")
- }
- // Ping returns the delay of a single Ping as reported by the system Ping binary.
- //
- // If the function is unable to resolve the system binary output or fails to
- // successfully resolve a Ping, it will always return -1.
- //
- // NOTE(os): this function may fail on non-unix compliant implementations of the Ping spec.
- func Ping(address string) (delay float64, err error) {
- out, err := runPing(address)
- if err != nil {
- return -1, err
- }
- lines := splitBytesToLines(out)
- for i := 0; i < len(lines); i++ {
- if strings.Contains(lines[i], "bytes from") {
- position := strings.Index(lines[i], "time=")
- before, _, success := strings.Cut(lines[i][position:], " ")
- if !success {
- return -1, errors.New("Line does not match pattern!")
- }
- _, after, success := strings.Cut(before, "=")
- if !success {
- return -1, errors.New("Line does not match pattern!")
- }
- delay, _ := strconv.ParseFloat(after, 64)
- return delay, nil
- }
- }
- return -1, errors.New("could not resolve host: " + address)
- }
- type Address struct {
- Address string
- results []float64
- max_results int
- }
- func (a Address) Truncate() []float64 {
- if len(a.results) > a.max_results {
- a.results = a.results[len(a.results)-a.max_results : len(a.results)] // return modified slice missing first index
- }
- return a.results
- }
- // Wraps [Ping]
- func (a Address) Ping() (delay float64, err error) {
- return Ping(a.Address)
- }
- // Poll the affiliated Address and appends it to a.results
- func (a Address) Poll() (results []float64, err error) {
- delay, err := a.Ping()
- a.results = append(a.results, delay)
- a.results = a.Truncate() // enforce max length
- return a.results, err
- }
- // Last returns the last result in [Address.results]. Returns -1 if no previous result
- func (a Address) Last() (delay float64) {
- if len(a.results) > 0 {
- return a.results[len(a.results)-1]
- } else {
- return -1
- }
- }
|