package de.kroesch.clt.net;
import static de.kroesch.clt.Settings.PROMPT;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayDeque;
import java.util.Properties;
import java.util.Queue;
import javax.management.relation.Role;
import de.kroesch.clt.InternalEnvironment;
import de.kroesch.clt.Parser;
import de.kroesch.clt.internal.Internal;
import de.kroesch.clt.security.AuthCommand;
import de.kroesch.clt.security.Authority;
/**
* Attaches to a dedicated port and serves Telnet-like interface.
*
* This implementation is single-threaded, because only one master
* should have access to the bot.
*
* @author Karsten Kroesch <karsten@kroesch.de>
*
*/
public class TerminalDaemon implements InternalEnvironment {
private static final int DEFAULT_PORT = 12880;
private static final int TIMEOUT = 10000;
private final ServerSocket server;
private final Properties properties;
private final Parser parser;
private final Queue<Runnable> commandStack = new ArrayDeque<Runnable>();
private String lastErrorMessage = "OK";
private PrintWriter writer;
private BufferedReader reader;
private Authority authority = new Authority();
public TerminalDaemon(int port) throws IOException {
parser = new Parser(this);
properties = new Properties();
// TODO: Read properties
set(PROMPT.key(), "");
server = new ServerSocket(port);
}
public TerminalDaemon() throws IOException {
this(DEFAULT_PORT);
}
/*
* Create Socket and read commands
*/
private void read() throws IOException {
final Socket socket = server.accept();
socket.setSoTimeout(TIMEOUT);
writer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer.printf("FreXBot V%s -- The friendly, extensible Bot\n", VERSION);
writer.printf("Timeout is %d milliseconds.\n", TIMEOUT);
writer.printf("\n%s> ", get(PROMPT.key()));
writer.flush();
String commandLine = "";
for (;;) {
boolean timeout = false;
try {
commandLine = reader.readLine();
} catch (SocketTimeoutException e) {
timeout = true;
}
if ("exit".equals(commandLine) || timeout) {
writer.write("Goodbye\n");
writer.flush();
socket.close();
break;
}
Runnable consoleCommand = parser.parseCommand(commandLine);
if (! (consoleCommand instanceof Internal)) commandStack.add(consoleCommand);
try {
// TODO:
// if (consoleCommand instanceof AuthCommand) {
// AuthCommand cmd = (AuthCommand) consoleCommand;
// if (! authority.authorize(cmd))
// throw new SecurityException("Not authorized.");
// }
consoleCommand.run();
lastErrorMessage = "OK";
} catch(Exception ex) {
ex.printStackTrace();
writer.printf("?Error during execution: %s\n", ex.getMessage());
lastErrorMessage = ex.getMessage();
}
writer.printf("\n%s> ", get(PROMPT.key()));
writer.flush();
}
}
public PrintWriter writer() {
return writer;
}
public String get(String key) {
return properties.getProperty(key);
}
public void set(String key, String value) {
properties.setProperty(key, value);
}
public Queue<Runnable> history() {
return commandStack;
}
public String lastError() {
return lastErrorMessage;
}
public void setLastErrorMessage(String message) {
this.lastErrorMessage = message;
}
public Properties getProperties() {
return properties;
}
public Parser parser() {
return parser;
}
public String expect(String question, String choices) {
writer.printf("%s [%s]: ", question, choices);
writer.flush();
try {
return reader.readLine();
} catch (IOException e) {
throw new RuntimeException("Cannot read from socket");
}
}
public Authority authority() {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) throws IOException {
TerminalDaemon daemon = new TerminalDaemon();
for (;;) {
daemon.read();
}
}
}