Skip to content

Commit b175087

Browse files
committed
added basic console system
1 parent 94629d8 commit b175087

File tree

9 files changed

+254
-4
lines changed

9 files changed

+254
-4
lines changed

backend/common/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ dependencies {
1313
testImplementation platform('org.junit:junit-bom:5.10.0')
1414
testImplementation 'org.junit.jupiter:junit-jupiter'
1515
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
16+
implementation 'org.jline:jline:3.27.1'
17+
compileOnly 'org.projectlombok:lombok:1.18.34'
18+
annotationProcessor 'org.projectlombok:lombok:1.18.34'
1619
}
1720

1821
test {
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package console;
2+
3+
import console.command.CommandDispatcher;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
import org.jline.reader.EndOfFileException;
7+
import org.jline.reader.LineReader;
8+
import org.jline.reader.LineReaderBuilder;
9+
import org.jline.reader.UserInterruptException;
10+
import org.jline.reader.impl.completer.StringsCompleter;
11+
import org.jline.terminal.Terminal;
12+
import org.jline.terminal.TerminalBuilder;
13+
14+
import java.io.IOException;
15+
16+
@Setter
17+
@Getter
18+
public class ConsoleReader extends Thread {
19+
private CommandDispatcher dispatcher;
20+
private String prompt;
21+
private Terminal terminal;
22+
private LineReader reader;
23+
24+
public ConsoleReader() {
25+
try {
26+
this.setName("ConsoleReader");
27+
this.prompt = "devbox>";
28+
this.dispatcher = new CommandDispatcher();
29+
this.terminal = TerminalBuilder.builder()
30+
.system(true)
31+
.dumb(true)
32+
.build();
33+
this.reader = LineReaderBuilder.builder()
34+
.terminal(terminal)
35+
.build();
36+
} catch (IOException e) {
37+
e.printStackTrace();
38+
}
39+
}
40+
41+
public void flush() {
42+
this.terminal.flush();
43+
}
44+
45+
public void println(String msg) {
46+
this.terminal.writer().println(msg);
47+
}
48+
49+
public void print(String msg) {
50+
this.terminal.writer().print(msg);
51+
}
52+
53+
public ConsoleReader(String prompt) {
54+
try {
55+
this.setName("ConsoleReader");
56+
this.prompt = prompt;
57+
this.dispatcher = new CommandDispatcher();
58+
this.terminal = TerminalBuilder.builder()
59+
.system(true)
60+
.build();
61+
this.reader = LineReaderBuilder.builder()
62+
.terminal(terminal)
63+
.completer(new StringsCompleter(this.dispatcher.getCommandNames()))
64+
.build();
65+
} catch (IOException e) {
66+
e.printStackTrace();
67+
}
68+
}
69+
70+
@Override
71+
public void run() {
72+
while (!this.isInterrupted()) {
73+
try {
74+
String line = reader.readLine(this.prompt);
75+
dispatcher.execute(line);
76+
} catch (UserInterruptException | EndOfFileException e) {
77+
break;
78+
}
79+
}
80+
}
81+
82+
public void shutdown() {
83+
this.interrupt();
84+
}
85+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package console.command;
2+
3+
public interface Command {
4+
void execute(String[] args);
5+
String getName();
6+
String getDescription();
7+
String getUsage();
8+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package console.command;
2+
3+
import java.util.Arrays;
4+
import java.util.Collection;
5+
import java.util.function.Consumer;
6+
7+
public class CommandDispatcher {
8+
private final CommandMap commandMap;
9+
10+
public CommandDispatcher() {
11+
this.commandMap = new CommandMap();
12+
}
13+
14+
public void register(String name, String desc, String usage, Consumer<String[]> command) {
15+
this.commandMap.put(name.toLowerCase(), new Command() {
16+
@Override
17+
public void execute(String[] args) {
18+
command.accept(args);
19+
}
20+
21+
@Override
22+
public String getName() {
23+
return name;
24+
}
25+
26+
@Override
27+
public String getDescription() {
28+
return desc;
29+
}
30+
31+
@Override
32+
public String getUsage() {
33+
return usage;
34+
}
35+
});
36+
}
37+
38+
public Collection<String> getCommandNames() {
39+
return this.commandMap.keySet();
40+
}
41+
42+
public void register(Command command) {
43+
this.commandMap.put(command.getName().toLowerCase(), command);
44+
}
45+
46+
public void execute(String input) {
47+
String[] split = input.trim().split("\\s+");
48+
if (split.length == 0) return;
49+
50+
String cmd = split[0].toLowerCase();
51+
String[] args = Arrays.copyOfRange(split, 1, split.length);
52+
53+
Command command = this.commandMap.get(cmd);
54+
if (command != null) {
55+
command.execute(args);
56+
} else {
57+
System.out.println("Unknown Command: " + cmd);
58+
}
59+
}
60+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package console.command;
2+
3+
import java.util.HashMap;
4+
5+
public class CommandMap extends HashMap<String, Command> {
6+
7+
public CommandMap() {
8+
super();
9+
}
10+
11+
public void addCommand(Command command) {
12+
this.put(command.getName(), command);
13+
}
14+
15+
public Command getCommand(String name) {
16+
return this.get(name);
17+
}
18+
19+
public void removeCommand(String name) {
20+
this.remove(name);
21+
}
22+
}

backend/master/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
}
44

55
dependencies {
6-
6+
implementation project(":backend:common")
77
}
88

99
shadowJar {
Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,44 @@
11
package com.interguess.devbox.backend.master;
22

3+
import console.ConsoleReader;
4+
35
public class MasterBootstrap {
6+
private ConsoleReader reader;
47

5-
public static void main(String[] args) {
8+
public MasterBootstrap(String[] args) {
9+
this.reader = new ConsoleReader();
10+
11+
this.reader.getDispatcher().register(
12+
"echo",
13+
"This Command respond the inputed text",
14+
"echo <inputText>",
15+
(echoArgs) -> {
16+
if(echoArgs.length == 0) return;
17+
this.reader.println("[DevBox] Response from Master: " + echoArgs[0]);
18+
}
19+
);
620

21+
this.reader.getDispatcher().register(
22+
"exit",
23+
"This Command exit Master",
24+
"exit",
25+
(exitArgs) -> {
26+
shutdown();
27+
}
28+
);
29+
30+
this.reader.start();
31+
this.reader.println("[DevBox] Master started");
32+
}
33+
34+
private void shutdown() {
35+
this.reader.println("[DevBox] Master is shutting down");
36+
this.reader.flush();
37+
this.reader.shutdown();
38+
System.exit(0);
39+
}
40+
41+
public static void main(String[] args) {
42+
new MasterBootstrap(args);
743
}
844
}

backend/worker/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
}
44

55
dependencies {
6-
6+
implementation project(":backend:common")
77
}
88

99
shadowJar {
Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,44 @@
11
package com.interguess.devbox.backend.worker;
22

3+
import console.ConsoleReader;
4+
35
public class WorkerBootstrap {
6+
private ConsoleReader reader;
7+
8+
public WorkerBootstrap(String[] args) {
9+
this.reader = new ConsoleReader();
10+
11+
this.reader.getDispatcher().register(
12+
"echo",
13+
"This Command respond the inputed text",
14+
"echo <inputText>",
15+
(echoArgs) -> {
16+
if(echoArgs.length == 0) return;
17+
this.reader.println("[DevBox] Response from Worker: " + echoArgs[0]);
18+
}
19+
);
20+
21+
this.reader.getDispatcher().register(
22+
"exit",
23+
"This Command exit Worker",
24+
"exit",
25+
(exitArgs) -> {
26+
shutdown();
27+
}
28+
);
29+
30+
this.reader.start();
31+
this.reader.println("[DevBox] Worker started");
32+
}
33+
34+
private void shutdown() {
35+
this.reader.println("[DevBox] Worker is shutting down");
36+
this.reader.flush();
37+
this.reader.shutdown();
38+
System.exit(0);
39+
}
440

541
public static void main(String[] args) {
6-
42+
new WorkerBootstrap(args);
743
}
844
}

0 commit comments

Comments
 (0)