package io.fathom.cloud.commands; import java.io.IOException; import java.io.StreamTokenizer; import java.io.StringReader; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.sshd.server.Command; import org.apache.sshd.server.CommandFactory; import org.kohsuke.args4j.CmdLineException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Joiner; import com.google.common.collect.Lists; @Singleton public class SshCommandFactory implements CommandFactory { private static final Logger log = LoggerFactory.getLogger(SshCommandFactory.class); @Inject Cmdlets cmdlets; public Command parseCommand(Cmdlet cmdlet, List<String> tokens) throws CmdLineException { String line = Joiner.on(" ").join(tokens); try { List<String> args = tokens.subList(1, tokens.size()); cmdlet.parseArguments(line, args); } catch (CmdLineException e) { throw e; } catch (Exception e) { // TODO: Print nice message?? throw new IllegalArgumentException("Error parsing tokens", e); } return new SshCommand(cmdlet); } public Cmdlet buildCommand(List<String> tokens) throws CmdLineException { if (tokens.isEmpty()) { throw new IllegalArgumentException("Command is required"); } String command = tokens.get(0); Cmdlet cmdlet = cmdlets.getCommand(command); if (cmdlet == null) { cmdlet = cmdlets.getCommand("help"); } if (cmdlet == null) { throw new IllegalStateException("Unable to find cmdlet / help cmdlet"); } return cmdlet; } @Override public Command createCommand(String line) { log.info("Running SSH command: " + line); List<String> tokens = Lists.newArrayList(); StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(line)); tokenizer.resetSyntax(); tokenizer.wordChars(33, 128); tokenizer.wordChars(128 + 32, 255); tokenizer.whitespaceChars(0, ' '); tokenizer.quoteChar('"'); tokenizer.quoteChar('\''); boolean done = false; while (!done) { int nextToken; try { nextToken = tokenizer.nextToken(); } catch (IOException e) { log.warn("Error parsing line: {}", line); throw new IllegalArgumentException("Unable to parse line: " + line, e); } switch (nextToken) { case StreamTokenizer.TT_NUMBER: throw new IllegalStateException(); case StreamTokenizer.TT_WORD: tokens.add(tokenizer.sval); break; case StreamTokenizer.TT_EOF: done = true; break; case StreamTokenizer.TT_EOL: break; case '\"': case '\'': tokens.add(tokenizer.sval); break; default: log.warn("Error parsing line: {}", line); throw new IllegalArgumentException("Unable to parse line: " + line); } } Cmdlet cmdlet = null; try { cmdlet = buildCommand(tokens); Command command = parseCommand(cmdlet, tokens); return command; } catch (CmdLineException e) { Command command = new PrintErrorCommand(e.getMessage(), cmdlet); return command; } catch (Exception e) { log.warn("Error building command for line: " + line, e); Command command = new PrintErrorCommand("Error building command for line: " + line, cmdlet); return command; } } }