solar-toolkit/command/command.go

69 lines
1.3 KiB
Go
Raw Normal View History

package command
import (
"bufio"
"fmt"
"io"
2022-07-15 02:40:30 +00:00
"log"
"time"
)
2022-07-15 02:40:30 +00:00
type Command interface {
String() string
2022-07-15 02:40:30 +00:00
ValidateResponse([]byte) ([]byte, error)
}
2022-07-15 02:40:30 +00:00
type Conn interface {
io.ReadWriter
SetDeadline(time.Time) error
}
const (
2023-07-16 06:56:01 +00:00
maxAttempts = 4
timeout = time.Second * 10
readBufferSizeBytes = 8_192
2022-07-15 02:40:30 +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)
_, 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])
}