Skip to content

Commit ddd2f6a

Browse files
committed
Fix: Race Conditions When Setting Up ReSync On Fresh Server.
1 parent 309a26d commit ddd2f6a

7 files changed

Lines changed: 56 additions & 35 deletions

File tree

RemotelyMod/libs/ReScreen-1.0.jar

986 Bytes
Binary file not shown.
662 Bytes
Binary file not shown.

libs/ReScreen-1.0.jar

986 Bytes
Binary file not shown.

libs/Rebase-1.0-SNAPSHOT.jar

662 Bytes
Binary file not shown.

src/main/java/redxax/oxy/remotely/data/flow/ReSyncConnectionManager.java

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import java.util.concurrent.TimeUnit;
2222

2323
public class ReSyncConnectionManager {
24-
private static final String RESYNC_API_KEY_KEY = "resyncApiKey";
25-
private static final String RESYNC_PORT_KEY = "resyncPort";
2624
private final RemotelyClient client;
2725
private final ReStudioApiClient apiClient;
2826
private final Map<String, ReSyncFlowClient> flowClients = new ConcurrentHashMap<>();
@@ -70,6 +68,11 @@ public ReSyncFlowClient ensureFlowClient(String serverId) {
7068

7169
private ReSyncFlowClient ensureFlowClient(String serverId, ReSyncConnectionProfile profile, boolean showNotifications, boolean connectIfNeeded) {
7270
ReSyncFlowClient flowClient = flowClients.get(serverId);
71+
if (flowClient != null && profile != null && !flowClient.isConnectedState() && !flowClient.matchesDirectProfile(profile.wsUrl(), profile.apiKey())) {
72+
flowClient.shutdown();
73+
flowClients.remove(serverId);
74+
flowClient = null;
75+
}
7376
if (flowClient == null) {
7477
if (profile != null && profile.wsUrl() != null && !profile.wsUrl().isBlank()) {
7578
flowClient = new ReSyncFlowClient(serverId, apiClient, profile.wsUrl(), profile.apiKey(), client);
@@ -120,36 +123,14 @@ public ReSyncConnectionProfile resolveConnectionProfile(String serverId, ClientS
120123
return null;
121124
}
122125
Instance instance = findInstanceByServerId(serverId, null);
123-
if (instance == null || instance.getBackendConfig() == null || instance.getBackendConfig().credentials == null) {
124-
return tryReadReSyncConfigFromBackend(instance);
126+
if (instance == null || instance.getBackendConfig() == null) {
127+
return null;
125128
}
126129
BackendConfig backendConfig = instance.getBackendConfig();
127130
if ("RESTUDIO".equalsIgnoreCase(backendConfig.type)) {
128131
return null;
129132
}
130-
Map<String, String> credentials = backendConfig.credentials;
131-
String port = safeText(credentials.get(RESYNC_PORT_KEY));
132-
String host;
133-
if ("LOCAL".equalsIgnoreCase(backendConfig.type)) {
134-
host = "127.0.0.1";
135-
} else {
136-
host = safeText(credentials.get("host"));
137-
}
138-
String apiKey = safeText(credentials.get(RESYNC_API_KEY_KEY));
139-
if (port.isBlank() || apiKey.isBlank()) {
140-
ReSyncConnectionProfile fsProfile = tryReadReSyncConfigFromBackend(instance);
141-
if (fsProfile != null) {
142-
return fsProfile;
143-
}
144-
}
145-
String wsUrl = null;
146-
if (!host.isBlank() && !port.isBlank()) {
147-
wsUrl = normalizeWsUrl(host + ":" + port);
148-
}
149-
if (apiKey.isBlank()) {
150-
return new ReSyncConnectionProfile(wsUrl, null);
151-
}
152-
return new ReSyncConnectionProfile(wsUrl, apiKey);
133+
return tryReadReSyncConfigFromBackend(instance);
153134
}
154135

155136
public String getFlowAvailabilityIssue(String serverId, ClientServerView server) {

src/main/java/redxax/oxy/remotely/data/flow/ReSyncFlowClient.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.LinkedHashMap;
4444
import java.util.List;
4545
import java.util.Map;
46+
import java.util.Objects;
4647
import java.util.Queue;
4748
import java.util.Set;
4849
import java.util.UUID;
@@ -152,6 +153,11 @@ public CompletableFuture<Void> connect() {
152153
if (isConnected() || connecting.get()) {
153154
return CompletableFuture.completedFuture(null);
154155
}
156+
WebSocketClient existingClient = wsClient.get();
157+
if (existingClient != null && existingClient.isOpen() && !authenticated.get()) {
158+
existingClient.close();
159+
wsClient.compareAndSet(existingClient, null);
160+
}
155161
connecting.set(true);
156162
nodeRegistrySynced = false;
157163
scheduleConnectTimeout();
@@ -309,7 +315,9 @@ private void sendHandshake() {
309315
buffer.put(CLIENT_VERSION.getBytes());
310316

311317
sendFrame(0, buffer.array(), (short) 0);
318+
}
312319

320+
private void subscribeStartupChannels() {
313321
sendSubscribe("flow", null);
314322
sendSubscribe("player_tracking", null);
315323
sendSubscribe("world_management", null);
@@ -474,6 +482,7 @@ private void handleHandshakeResponse(byte[] payload) {
474482
connecting.set(false);
475483
cancelConnectTimeout();
476484
System.out.println("[ReSyncFlow] Handshake complete, client authenticated");
485+
subscribeStartupChannels();
477486
startHeartbeat();
478487
requestNodeRegistry();
479488
requestJobSnapshots();
@@ -512,8 +521,9 @@ private void scheduleConnectTimeout() {
512521
}
513522
connecting.set(false);
514523
WebSocketClient client = wsClient.get();
515-
if (client != null && !client.isOpen()) {
524+
if (client != null && !authenticated.get()) {
516525
client.close();
526+
wsClient.compareAndSet(client, null);
517527
}
518528
if (errorListener != null) {
519529
errorListener.onError(null, "ReSync Connection Timed Out");
@@ -1663,6 +1673,10 @@ public boolean isConnectedState() {
16631673
return isConnected();
16641674
}
16651675

1676+
public boolean matchesDirectProfile(String wsUrl, String apiKey) {
1677+
return Objects.equals(normalizeWsUrl(directWsUrl), normalizeWsUrl(wsUrl)) && Objects.equals(directApiKey, apiKey);
1678+
}
1679+
16661680
private boolean isConnected() {
16671681
WebSocketClient client = wsClient.get();
16681682
return client != null && client.isOpen() && authenticated.get();
@@ -1671,7 +1685,8 @@ private boolean isConnected() {
16711685
private void ensureConnected() {
16721686
WebSocketClient client = wsClient.get();
16731687
if (client != null && client.isOpen() && !authenticated.get()) {
1674-
return;
1688+
client.close();
1689+
wsClient.compareAndSet(client, null);
16751690
}
16761691
connect();
16771692
}

src/main/java/redxax/oxy/remotely/flow/ui/FlowManagerScreen.java

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public void tick() {
199199
enterReadyState();
200200
return;
201201
}
202-
if ((startupState == StartupState.LOADING || startupState == StartupState.SERVER_STOPPED) && !startupProbeRunning) {
202+
if ((startupState == StartupState.LOADING || startupState == StartupState.SERVER_STOPPED || startupState == StartupState.INSTALLED) && !startupProbeRunning) {
203203
beginStartupProbe(false);
204204
}
205205
}
@@ -226,6 +226,7 @@ private void ensureStartupWidgets() {
226226
.accentType(ThemeManager.getAccent("nice"))
227227
.size(180, 20)
228228
.autoWidthOnTextChange(true)
229+
.entranceAnimation(false)
229230
.onClick(this::runSetupFlow)
230231
.build();
231232
setupReSyncButton.setVisible(false);
@@ -238,6 +239,7 @@ private void ensureStartupWidgets() {
238239
.accentType(ThemeManager.getAccent("nice"))
239240
.size(180, 20)
240241
.autoWidthOnTextChange(true)
242+
.entranceAnimation(false)
241243
.onClick(this::openServerScreen)
242244
.build();
243245
welcomeServerButton.setVisible(false);
@@ -323,7 +325,10 @@ private void probeStartupStateAsync() {
323325
enterReadyState();
324326
return;
325327
}
326-
if (startupState == StartupState.INSTALLED || startupState == StartupState.INSTALLING) {
328+
if (startupState == StartupState.INSTALLING) {
329+
return;
330+
}
331+
if (startupState == StartupState.INSTALLED && resolvedState != StartupState.READY && resolvedState != StartupState.LOADING) {
327332
return;
328333
}
329334
switch (resolvedState) {
@@ -367,6 +372,9 @@ private StartupState computeStartupState() {
367372
if (!isRunning) {
368373
return StartupState.SERVER_STOPPED;
369374
}
375+
if (flowManager.getFlowAvailabilityIssue(serverId, server) != null) {
376+
return StartupState.SETUP;
377+
}
370378
return StartupState.LOADING;
371379
}
372380
if (flowManager.isFlowClientConnected(serverId)) {
@@ -697,8 +705,10 @@ private boolean setupForNonReStudio() throws Exception {
697705

698706
Path serverPath = Path.of(instance.getPath());
699707
Path pluginsPath = serverPath.resolve(resolvePluginsDirectory(instance));
708+
Path reSyncJarPath = pluginsPath.resolve("ReSync.jar");
700709
ensureDirectory(fs, pluginsPath);
701-
transfer.downloadFile(RESYNC_RELEASE_URL, pluginsPath.resolve("ReSync.jar"), null).get(90, TimeUnit.SECONDS);
710+
transfer.downloadFile(RESYNC_RELEASE_URL, reSyncJarPath, null).get(90, TimeUnit.SECONDS);
711+
registerReSyncResource(instance, reSyncJarPath);
702712

703713
Path configDir = pluginsPath.resolve("ReSync");
704714
ensureDirectory(fs, configDir);
@@ -718,13 +728,28 @@ private boolean setupForNonReStudio() throws Exception {
718728
backendConfig.credentials = new HashMap<>();
719729
}
720730
backendConfig.credentials.put("resyncEnabled", "true");
721-
backendConfig.credentials.put("resyncPort", String.valueOf(RESYNC_PORT));
722-
backendConfig.credentials.put("resyncApiKey", apiKey);
723731
instance.save();
724732
}
725733
return true;
726734
}
727735

736+
private void registerReSyncResource(Instance instance, Path reSyncJarPath) {
737+
if (instance == null || reSyncJarPath == null) {
738+
return;
739+
}
740+
try {
741+
boolean remoteBackend = instance.getBackendConfig() != null && !"LOCAL".equalsIgnoreCase(instance.getBackendConfig().type);
742+
if (remoteBackend) {
743+
Rebase.get().getResourceManager().invalidateCache(instance);
744+
Rebase.get().getResourceManager().getResources(instance).get(30, TimeUnit.SECONDS);
745+
return;
746+
}
747+
Rebase.get().getResourceManager().loadResource(instance, reSyncJarPath).get(30, TimeUnit.SECONDS);
748+
} catch (Exception ignored) {
749+
Rebase.get().getResourceManager().invalidateCache(instance);
750+
}
751+
}
752+
728753
private String generateApiKey() {
729754
byte[] key = new byte[32];
730755
secureRandom.nextBytes(key);
@@ -4223,7 +4248,7 @@ public void refresh() {
42234248
enterReadyState();
42244249
return;
42254250
}
4226-
if (startupState == StartupState.LOADING || startupState == StartupState.SERVER_STOPPED) {
4251+
if (startupState == StartupState.LOADING || startupState == StartupState.SERVER_STOPPED || startupState == StartupState.INSTALLED) {
42274252
beginStartupProbe(false);
42284253
}
42294254
return;

0 commit comments

Comments
 (0)