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 }