2022-07-10 08:47:12 +00:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2022-07-15 02:40:30 +00:00
|
|
|
"log"
|
|
|
|
"time"
|
2022-07-10 08:47:12 +00:00
|
|
|
)
|
|
|
|
|
2022-07-15 02:40:30 +00:00
|
|
|
type Command interface {
|
2022-07-10 08:47:12 +00:00
|
|
|
String() string
|
2022-07-15 02:40:30 +00:00
|
|
|
ValidateResponse([]byte) ([]byte, error)
|
2022-07-10 08:47:12 +00:00
|
|
|
}
|
|
|
|
|
2022-07-15 02:40:30 +00:00
|
|
|
type Conn interface {
|
|
|
|
io.ReadWriter
|
|
|
|
SetDeadline(time.Time) error
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
maxAttempts = 3
|
2022-07-15 19:14:55 +00:00
|
|
|
timeout = time.Second * 5
|
2022-07-15 02:40:30 +00:00
|
|
|
readBufferSizeBytes = 4_096
|
|
|
|
)
|
|
|
|
|
2022-07-11 18:01:28 +00:00
|
|
|
// Send writes the command to the provided Writer, and reads and validates the
|
|
|
|
// response.
|
2022-07-15 02:40:30 +00:00
|
|
|
func Send(cmd Command, conn Conn) ([]byte, error) {
|
|
|
|
var (
|
|
|
|
resp []byte
|
|
|
|
err error
|
|
|
|
attempts int
|
|
|
|
)
|
|
|
|
|
|
|
|
for {
|
|
|
|
if resp, err = tryRequest(cmd, conn); err != nil {
|
|
|
|
attempts++
|
|
|
|
log.Printf("error executing command (attempt %d): %s", attempts, err)
|
|
|
|
if attempts <= 3 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("error executing command: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func tryRequest(cmd Command, conn Conn) ([]byte, error) {
|
|
|
|
if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil {
|
|
|
|
return nil, fmt.Errorf("error setting deadline: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
p := make([]byte, readBufferSizeBytes)
|
2022-07-10 08:47:12 +00:00
|
|
|
_, err := fmt.Fprint(conn, cmd.String())
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error writing to socket: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
r := bufio.NewReader(conn)
|
|
|
|
n, err := r.Read(p)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error reading from socket: %s", err)
|
|
|
|
}
|
|
|
|
|
2022-07-15 02:40:30 +00:00
|
|
|
return cmd.ValidateResponse(p[:n])
|
2022-07-10 08:47:12 +00:00
|
|
|
}
|