github.com/viant/toolbox@v0.34.5/ssh/replay_command.go (about) 1 package ssh 2 3 import ( 4 "fmt" 5 "github.com/viant/toolbox" 6 "io/ioutil" 7 "os" 8 "path" 9 "sort" 10 "strings" 11 ) 12 13 //ReplayCommand represent a replay command 14 type ReplayCommand struct { 15 Stdin string 16 Index int 17 Stdout []string 18 Error string 19 } 20 21 //replayCommands represnets command grouped by stdin 22 type ReplayCommands struct { 23 Commands map[string]*ReplayCommand 24 Keys []string 25 BaseDir string 26 } 27 28 //Register register stdin and corresponding stdout conversation 29 func (c *ReplayCommands) Register(stdin, stdout string) { 30 if _, has := c.Commands[stdin]; !has { 31 c.Commands[stdin] = &ReplayCommand{ 32 Stdin: stdin, 33 Stdout: make([]string, 0), 34 } 35 c.Keys = append(c.Keys, stdin) 36 } 37 c.Commands[stdin].Stdout = append(c.Commands[stdin].Stdout, stdout) 38 } 39 40 //return stdout pointed by index and increases index or empty string if exhausted 41 func (c *ReplayCommands) Next(stdin string) string { 42 var stdout = c.Commands[stdin].Stdout 43 var index = c.Commands[stdin].Index 44 if index < len(stdout) { 45 c.Commands[stdin].Index++ 46 return stdout[index] 47 } 48 return "" 49 } 50 51 func (c *ReplayCommands) Enable(source interface{}) (err error) { 52 switch value := source.(type) { 53 case *service: 54 value.replayCommands = c 55 value.recordSession = true 56 case *multiCommandSession: 57 value.replayCommands = c 58 value.recordSession = true 59 default: 60 err = fmt.Errorf("unsupported type: %T", source) 61 } 62 return err 63 } 64 65 func (c *ReplayCommands) Disable(source interface{}) (err error) { 66 switch value := source.(type) { 67 case *service: 68 value.replayCommands = nil 69 value.recordSession = false 70 case *multiCommandSession: 71 value.replayCommands = nil 72 value.recordSession = false 73 default: 74 err = fmt.Errorf("unsupported type: %T", source) 75 } 76 return err 77 } 78 79 //Store stores replay command in the base directory 80 func (c *ReplayCommands) Store() error { 81 err := toolbox.CreateDirIfNotExist(c.BaseDir) 82 if err != nil { 83 return err 84 } 85 for i, key := range c.Keys { 86 var command = c.Commands[key] 87 var filenamePrefix = path.Join(c.BaseDir, fmt.Sprintf("%03d", i+1)) 88 var stdinFilename = filenamePrefix + "_000.stdin" 89 err := ioutil.WriteFile(stdinFilename, []byte(command.Stdin), 0644) 90 if err != nil { 91 return err 92 } 93 for j, stdout := range command.Stdout { 94 var stdoutFilename = fmt.Sprintf("%v_%03d.stdout", filenamePrefix, j+1) 95 err := ioutil.WriteFile(stdoutFilename, []byte(stdout), 0644) 96 if err != nil { 97 return err 98 } 99 } 100 } 101 return nil 102 } 103 104 //Load loads replay command from base directory 105 func (c *ReplayCommands) Load() error { 106 parent, err := os.Open(c.BaseDir) 107 if err != nil { 108 return err 109 } 110 files, err := parent.Readdir(1000) 111 if err != nil { 112 return err 113 } 114 var stdinMap = make(map[string]string) 115 var stdoutMap = make(map[string]string) 116 117 for _, candidate := range files { 118 ext := path.Ext(candidate.Name()) 119 var contentMap map[string]string 120 if ext == ".stdin" { 121 contentMap = stdinMap 122 } else if ext == ".stdout" { 123 contentMap = stdoutMap 124 } else { 125 continue 126 } 127 var filename = path.Join(c.BaseDir, candidate.Name()) 128 content, err := ioutil.ReadFile(filename) 129 if err != nil { 130 return nil 131 } 132 contentMap[candidate.Name()] = string(content) 133 } 134 135 for key, stdin := range stdinMap { 136 var prefix = key[:len(key)-10] 137 var candidateKeys = toolbox.MapKeysToStringSlice(stdoutMap) 138 sort.Strings(candidateKeys) 139 for _, candidateKey := range candidateKeys { 140 if strings.HasPrefix(candidateKey, prefix) { 141 stdout := stdoutMap[candidateKey] 142 c.Register(stdin, stdout) 143 } 144 } 145 } 146 return nil 147 } 148 149 //Shell returns command shell 150 func (c *ReplayCommands) Shell() string { 151 for _, candidate := range c.Commands { 152 if strings.HasPrefix(candidate.Stdin, "PS1=") && len(candidate.Stdout) > 0 { 153 return candidate.Stdout[0] 154 } 155 } 156 return "" 157 } 158 159 //System returns system name 160 func (c *ReplayCommands) System() string { 161 for _, candidate := range c.Commands { 162 if strings.HasPrefix(candidate.Stdin, "uname -s") && len(candidate.Stdout) > 0 { 163 return strings.ToLower(candidate.Stdout[0]) 164 } 165 } 166 return "" 167 } 168 169 //NewReplayCommands create a new replay commands or error if provided basedir does not exists and can not be created 170 func NewReplayCommands(basedir string) (*ReplayCommands, error) { 171 if !toolbox.FileExists(basedir) { 172 err := os.MkdirAll(basedir, 0744) 173 if err != nil { 174 return nil, err 175 } 176 } 177 return &ReplayCommands{ 178 Commands: make(map[string]*ReplayCommand), 179 Keys: make([]string, 0), 180 BaseDir: basedir, 181 }, nil 182 }