github.com/ocurr/cryorio@v0.0.0-20220116160810-2fb94073801b/roborio/roborio.go (about)

     1  package roborio
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  )
     8  
     9  // ErrorNoConnection represents a state where a roborio is unavailable at the specified addresses.
    10  var ErrorNoConnection = errors.New("unable to connect to roborio")
    11  var ErrorFileNotExist = errors.New("file does not exist")
    12  
    13  type Roborio struct {
    14  	conn     Conn
    15  	dial     DialFunc
    16  	user     string
    17  	pass     string
    18  	team     int
    19  	addrs    []string
    20  	currAddr int
    21  	port     int
    22  }
    23  
    24  type Option func(*Roborio)
    25  
    26  func Addresses(addrs ...string) Option {
    27  	return func(r *Roborio) {
    28  		r.addrs = addrs
    29  	}
    30  }
    31  
    32  func Team(team int) Option {
    33  	return func(r *Roborio) {
    34  		r.team = team
    35  	}
    36  }
    37  
    38  func Port(port int) Option {
    39  	return func(r *Roborio) {
    40  		r.port = port
    41  	}
    42  }
    43  
    44  func NewRoborio(dial DialFunc, user, pass string, options ...Option) (*Roborio, error) {
    45  	rio := &Roborio{port: 22, dial: dial}
    46  
    47  	for _, option := range options {
    48  		option(rio)
    49  	}
    50  
    51  	if rio.team == 0 {
    52  		var err error
    53  		rio.team, err = GetTeamNumber()
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  	}
    58  
    59  	if rio.addrs == nil {
    60  		rio.addrs = GetAddresses(rio.team)
    61  	}
    62  
    63  	return rio, nil
    64  }
    65  
    66  // Connect attempts to open a connection to the roborio using the list of addresses.
    67  // If Connect fails to open a connection to the roborio it will cycle to the next address
    68  // in the list on the next call to Connect. If there are no more addresses it returns ErrorNoConnection.
    69  func (r *Roborio) Connect() error {
    70  	if r.currAddr > len(r.addrs) {
    71  		return ErrorNoConnection
    72  	}
    73  	conn, err := r.dial(r.user, r.pass, fmt.Sprintf("%s:%d", r.addrs[r.currAddr], r.port))
    74  	if err != nil {
    75  		r.currAddr++
    76  		return fmt.Errorf("unable to connect to roborio at address %s %w", r.addrs[r.currAddr-1], err)
    77  	}
    78  
    79  	r.conn = conn
    80  	return nil
    81  }
    82  
    83  func (r *Roborio) Disconnect() error {
    84  	return r.conn.Close()
    85  }
    86  
    87  func (r *Roborio) Exec(command string) ([]byte, error) {
    88  	return r.conn.Exec(command)
    89  }
    90  
    91  func (r *Roborio) ListDir() ([]byte, error) {
    92  	return r.Exec("ls")
    93  }
    94  
    95  func (r *Roborio) Copy(origin, dest string) ([]byte, error) {
    96  	return r.Exec(fmt.Sprintf("cp %s %s", origin, dest))
    97  }
    98  
    99  func (r *Roborio) Touch(name string) ([]byte, error) {
   100  	return r.Exec("touch " + name)
   101  }
   102  
   103  func (r *Roborio) Remove(pattern string) ([]byte, error) {
   104  	return r.Exec("rm " + pattern)
   105  }
   106  
   107  func (r *Roborio) BackupFile(src, dest string) error {
   108  	out, _ := r.ListDir()
   109  	if !strings.Contains(string(out), src) {
   110  		return ErrorFileNotExist
   111  	}
   112  	dest = fmt.Sprintf("%s.backup", dest)
   113  
   114  	_, err := r.Copy(src, dest)
   115  	if err != nil {
   116  		return fmt.Errorf("unable to backup file: %w", err)
   117  	}
   118  	return nil
   119  }