-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstart_dev.java
More file actions
executable file
·156 lines (136 loc) · 6.04 KB
/
start_dev.java
File metadata and controls
executable file
·156 lines (136 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS info.picocli:picocli:4.7.5
//DEPS org.zeroturnaround:zt-exec:1.12
//JAVA 21
//JAVA_OPTIONS --enable-preview
//RUNTIME_OPTIONS --enable-preview
//GAV org.nodejs:node:18.18.2
import picocli.CommandLine;
import picocli.CommandLine.Command;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.stream.LogOutputStream;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@Command(name = "start-dev", mixinStandardHelpOptions = true, version = "start-dev 1.0",
description = "Starts the Robot Wars development environment")
public class start_dev implements Callable<Integer> {
private static final String BACKEND_URL = "http://localhost:8080";
private static final String FRONTEND_URL = "http://localhost:3000";
private static final int BROWSER_LAUNCH_DELAY_SECONDS = 5;
private static final int BACKEND_CHECK_INTERVAL_MS = 500;
private static final int BACKEND_TIMEOUT_SECONDS = 120; // 2 minutes timeout
public static void main(String... args) {
int exitCode = new CommandLine(new start_dev()).execute(args);
System.exit(exitCode);
}
/**
* Checks if the backend server is up and running.
*
* @return true if the backend is ready, false otherwise
*/
private boolean isBackendReady() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(BACKEND_URL).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(1000);
connection.setReadTimeout(1000);
int responseCode = connection.getResponseCode();
return responseCode >= 200 && responseCode < 500; // Any non-server error response means server is up
} catch (IOException e) {
return false; // Connection failed, backend not ready
}
}
/**
* Waits for the backend to be ready, with a timeout.
*
* @return true if backend became ready within the timeout, false if it timed out
*/
private boolean waitForBackendReady() throws InterruptedException {
System.out.println("Waiting for backend server to be ready...");
long startTime = System.currentTimeMillis();
long timeoutMillis = TimeUnit.SECONDS.toMillis(BACKEND_TIMEOUT_SECONDS);
while (System.currentTimeMillis() - startTime < timeoutMillis) {
if (isBackendReady()) {
System.out.println("Backend server is ready!");
return true;
}
Thread.sleep(BACKEND_CHECK_INTERVAL_MS);
}
System.err.println("Timed out waiting for backend server to start");
return false;
}
@Override
public Integer call() throws Exception {
System.out.println("Starting Robot Wars development environment...");
// Start backend
CompletableFuture<Void> backendFuture = CompletableFuture.runAsync(() -> {
try {
System.out.println("Starting backend server (Quarkus dev mode)...");
String gradleCommand = System.getProperty("os.name").toLowerCase().contains("windows") ? "gradlew.bat" : "./gradlew";
new ProcessExecutor()
.command(gradleCommand, "quarkusDev")
.redirectOutput(new LogOutputStream() {
@Override
protected void processLine(String line) {
System.out.println("[BACKEND] " + line);
}
})
.start();
} catch (Exception e) {
System.err.println("Error starting backend: " + e.getMessage());
e.printStackTrace();
}
});
// Wait for backend to be ready before starting frontend
if (!waitForBackendReady()) {
System.err.println("Backend server failed to start in time. Exiting.");
return 1;
}
// Start frontend only after backend is ready
CompletableFuture<Void> frontendFuture = CompletableFuture.runAsync(() -> {
try {
System.out.println("Starting frontend server...");
new ProcessExecutor()
.command("npm", "start")
.redirectOutput(new LogOutputStream() {
@Override
protected void processLine(String line) {
System.out.println("[FRONTEND] " + line);
}
})
.directory(new File("frontend"))
.start();
} catch (Exception e) {
System.err.println("Error starting frontend: " + e.getMessage());
e.printStackTrace();
}
});
// Wait a bit for frontend to start before opening browser
System.out.println("Waiting for frontend server to start...");
Thread.sleep(TimeUnit.SECONDS.toMillis(BROWSER_LAUNCH_DELAY_SECONDS));
// Open browser
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
System.out.println("Opening browser to " + FRONTEND_URL);
Desktop.getDesktop().browse(new URI(FRONTEND_URL));
} else {
System.out.println("Could not open browser automatically. Please navigate to " + FRONTEND_URL);
}
System.out.println("\nDevelopment environment started!");
System.out.println("- Frontend: " + FRONTEND_URL);
System.out.println("- Backend: " + BACKEND_URL);
System.out.println("\nPress Ctrl+C to stop all servers.");
// Keep the main thread alive
Thread.currentThread().join();
return 0;
}
}