Use interruptible readLine

This commit is contained in:
Andrea Cavalli 2021-10-24 00:22:47 +02:00
parent 52541b0ca8
commit e4bda0a3c7
2 changed files with 47 additions and 15 deletions

View File

@ -26,7 +26,7 @@
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-java</artifactId>
<version>2.7.8.35</version>
<version>2.7.8.36</version>
</dependency>
<!-- TDLight natives -->

View File

@ -1,27 +1,59 @@
package it.tdlight.common.utils;
import java.io.Console;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicReference;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class ScannerUtils {
private static final Object lock = new Object();
private static Scanner SCANNER = null;
private static final Object LOCK = new Object();
private static InputStreamReader scanner = null;
public static String askParameter(String displayName, String question) {
synchronized (LOCK) {
Console console = System.console();
if (console != null) {
return console.readLine("[%s] %s", displayName, question);
} else {
synchronized (lock) {
if (SCANNER == null) {
SCANNER = new Scanner(System.in);
Runtime.getRuntime().addShutdownHook(new Thread(() -> SCANNER.close()));
}
if (scanner == null) {
scanner = new InputStreamReader(System.in);
}
System.out.printf("[%s] %s: ", displayName, question);
return SCANNER.nextLine();
try {
return interruptibleReadLine(scanner);
} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
}
}
}
}
/**
* https://stackoverflow.com/questions/3595926/how-to-interrupt-bufferedreaders-readline
*/
private static String interruptibleReadLine(Reader reader) throws InterruptedException, IOException {
Pattern line = Pattern.compile("^(.*)\\R");
Matcher matcher;
boolean interrupted;
StringBuilder result = new StringBuilder();
int chr = -1;
do {
if (reader.ready()) {
chr = reader.read();
}
if (chr > -1) {
result.append((char) chr);
}
matcher = line.matcher(result.toString());
interrupted = Thread.interrupted(); // resets flag, call only once
} while (!interrupted && !matcher.matches());
if (interrupted) {
throw new InterruptedException();
}
return (matcher.matches() ? matcher.group(1) : "");
}
}