package chatty.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Start a process with the given command and send the resulting output to the
* listener.
*
* @author tduva
*/
public class Livestreamer extends Thread {
private final static Logger LOGGER = Logger.getLogger(Livestreamer.class.getName());
private final String command;
private final LivestreamerListener listener;
private Process process;
public Livestreamer(String command, LivestreamerListener listener) {
this.command = command;
this.listener = listener;
}
@Override
public void run() {
try {
Runtime rt = Runtime.getRuntime();
String[] cmd = split(command);
Process process = rt.exec(cmd);
this.process = process;
LOGGER.info("Livestreamer: Process "+id()+" started. ["+filterToken(command)+"]");
listener.processStarted(command);
// Read both output streams (output of the process, so input), so
// the process keeps running and to output it's output
InputStreamHelper errorStream = new InputStreamHelper(process.getErrorStream());
InputStreamHelper inputStream = new InputStreamHelper(process.getInputStream());
errorStream.start();
inputStream.start();
int exitValue = process.waitFor();
errorStream.join(1000);
inputStream.join(1000);
listener.processFinished(exitValue);
LOGGER.info("Livestreamer: Process "+id()+" finished.");
} catch (IOException ex) {
listener.message("Error: "+ex);
LOGGER.warning("Livestreamer: Error starting process / "+ex);
} catch (InterruptedException ex) {
listener.message("Error: "+ex);
LOGGER.warning("Livestreamer: "+ex);
}
}
private String id() {
return Integer.toHexString(process.hashCode());
}
public void kill() {
LOGGER.info("Livestreamer: Killing Process "+id());
process.destroy();
}
public static interface LivestreamerListener {
public void processStarted(String command);
public void message(String message);
public void processFinished(int exitValue);
}
/**
* Reads the given stream in it's own thread and outputs it.
*/
private class InputStreamHelper extends Thread {
private final InputStream input;
InputStreamHelper(InputStream input) {
this.input = input;
}
@Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) {
String line;
while ((line = reader.readLine()) != null) {
listener.message(line);
LOGGER.info("Livestreamer ("+id()+"): "+line);
}
} catch (IOException ex) {
listener.message("Error: "+ex);
LOGGER.warning("Livestreamer ("+id()+"): Error reading stream / "+ex);
}
}
}
// private static String join(String[] cmd) {
// StringBuilder b = new StringBuilder();
// for (String c : cmd) {
// if (!c.isEmpty()) {
// if (b.length() > 0) {
// b.append(" ");
// }
// b.append("\"");
// b.append(c);
// b.append("\"");
// }
// }
// return b.toString();
// }
/**
* Splits up a line of text into tokens by spaces, ignoring spaces for parts
* that are surrounded by brackets.
*
* <p>This can be used for splitting up parameters.</p>
*
* @param input The line of text to tokenize
* @return An array of tokens (tokens in brackets may be empty)
*/
private static String[] split(String input) {
List<String> result = new ArrayList<>();
Matcher m = Pattern.compile("\"([^\"]*)\"|([^\"\\s]+)").matcher(input);
while (m.find()) {
if (m.group(1) != null) {
result.add(m.group(1));
} else {
result.add(m.group(2));
}
}
//System.out.println(result);
return result.toArray(new String[result.size()]);
}
private static String filterToken(String input) {
return input.replaceAll("--twitch-oauth-token \\w+", "--twitch-oauth-token <token>");
}
public static final void main(String[] args) {
//split("\"a b c\" -h test");
System.out.println(filterToken("--twitch-oauth-token abcfwf --fwaf"));
}
}