Skip to content

Commit 38ddf8b

Browse files
committed
refactor: improve architecture, type safety, and debug observability
- Add ScheduleHandle interface replacing Object-typed runSchedule/cancelSchedule across PlatformAdapter and all 4 adapter implementations - Move isPapiEnabled static boolean into PlatformFeatures via PAPI feature key, PlaceholderStage now receives PlatformFeatures via constructor injection - Rename velocity VelocityExecutor to LocalDispatcher to avoid naming collision with backends VelocityExecutor - Deduplicate resolveSecret into SecretLoader.resolve() static method - Deduplicate formatDuration into MM.formatDuration() with improved h/m/s output - Fix ScheduleManager to use shared Envelope.MAPPER instead of private ObjectMapper - Fix silently swallowed exceptions in InNode, SessionHub, and RedisClient - Add 15 debug logs at key decision points: message routing (InNode/OutNode), session lifecycle, pipeline stages, script loading, config loading, secret resolution, and reconnect handler
1 parent ab85642 commit 38ddf8b

27 files changed

Lines changed: 140 additions & 99 deletions

File tree

backends/bukkit/src/main/java/dev/objz/commandbridge/bukkit/Adapter.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import dev.objz.commandbridge.backends.net.out.ctx.PlayerUpdateContext;
1111
import dev.objz.commandbridge.backends.platform.PathsUtil;
1212
import dev.objz.commandbridge.backends.platform.PlatformAdapter;
13+
import dev.objz.commandbridge.backends.platform.ScheduleHandle;
1314
import dev.objz.commandbridge.backends.platform.cmd.ClientCommands;
1415
import dev.objz.commandbridge.backends.platform.cmd.CommandExecutor;
1516
import dev.objz.commandbridge.config.ConfigManager;
@@ -135,19 +136,12 @@ public CommandExecutor getCommandExecutor() {
135136
}
136137

137138
@Override
138-
public Object runSchedule(Runnable task, Duration timeout, Duration interval) {
139+
public ScheduleHandle runSchedule(Runnable task, Duration timeout, Duration interval) {
139140
long intervalTicks = interval.toMillis() / 50;
140141
long timeoutMillis = timeout.toMillis();
141142
return new TimeoutTask(task, timeoutMillis, intervalTicks).start();
142143
}
143144

144-
@Override
145-
public void cancelSchedule(Object task) {
146-
if (task instanceof TimeoutTask t) {
147-
t.cancel();
148-
}
149-
}
150-
151145
@Override
152146
public Set<UUID> getOnlinePlayerIds() {
153147
return Bukkit.getOnlinePlayers().stream()
@@ -199,7 +193,7 @@ public void onQuit(PlayerQuitEvent event) {
199193
}
200194
}
201195

202-
private class TimeoutTask implements Runnable {
196+
private class TimeoutTask implements Runnable, ScheduleHandle {
203197
private final Runnable delegate;
204198
private final long timeoutMillis;
205199
private final long intervalTicks;

backends/folia/src/main/java/dev/objz/commandbridge/folia/Adapter.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import dev.objz.commandbridge.backends.net.out.ctx.PlayerUpdateContext;
1111
import dev.objz.commandbridge.backends.platform.PathsUtil;
1212
import dev.objz.commandbridge.backends.platform.PlatformAdapter;
13+
import dev.objz.commandbridge.backends.platform.ScheduleHandle;
1314
import dev.objz.commandbridge.backends.platform.cmd.ClientCommands;
1415
import dev.objz.commandbridge.backends.platform.cmd.CommandExecutor;
1516
import dev.objz.commandbridge.config.ConfigManager;
@@ -132,15 +133,10 @@ public CommandExecutor getCommandExecutor() {
132133
}
133134

134135
@Override
135-
public Object runSchedule(Runnable task, Duration timeout, Duration interval) {
136-
return new TimeoutTask(task, timeout.toMillis(), interval.toMillis()).start();
137-
}
138-
139-
@Override
140-
public void cancelSchedule(Object task) {
141-
if (task instanceof TimeoutTask t) {
142-
t.cancel();
143-
}
136+
public ScheduleHandle runSchedule(Runnable task, Duration timeout, Duration interval) {
137+
long timeoutMillis = timeout.toMillis();
138+
long intervalMillis = interval.toMillis();
139+
return new TimeoutTask(task, timeoutMillis, intervalMillis).start();
144140
}
145141

146142
@Override
@@ -194,7 +190,7 @@ public void onQuit(PlayerQuitEvent event) {
194190
}
195191
}
196192

197-
private class TimeoutTask {
193+
private class TimeoutTask implements ScheduleHandle {
198194
private final Runnable delegate;
199195
private final long timeoutMillis;
200196
private final long intervalMillis;

backends/paper/src/main/java/dev/objz/commandbridge/paper/Adapter.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import dev.objz.commandbridge.backends.net.out.ctx.PlayerUpdateContext;
1111
import dev.objz.commandbridge.backends.platform.PathsUtil;
1212
import dev.objz.commandbridge.backends.platform.PlatformAdapter;
13+
import dev.objz.commandbridge.backends.platform.ScheduleHandle;
1314
import dev.objz.commandbridge.backends.platform.cmd.ClientCommands;
1415
import dev.objz.commandbridge.backends.platform.cmd.CommandExecutor;
1516
import dev.objz.commandbridge.config.ConfigManager;
@@ -135,19 +136,12 @@ public CommandExecutor getCommandExecutor() {
135136
}
136137

137138
@Override
138-
public Object runSchedule(Runnable task, Duration timeout, Duration interval) {
139+
public ScheduleHandle runSchedule(Runnable task, Duration timeout, Duration interval) {
139140
long intervalTicks = interval.toMillis() / 50;
140141
long timeoutMillis = timeout.toMillis();
141142
return new TimeoutTask(task, timeoutMillis, intervalTicks).start();
142143
}
143144

144-
@Override
145-
public void cancelSchedule(Object task) {
146-
if (task instanceof TimeoutTask t) {
147-
t.cancel();
148-
}
149-
}
150-
151145
@Override
152146
public Set<UUID> getOnlinePlayerIds() {
153147
return Bukkit.getOnlinePlayers().stream()
@@ -198,7 +192,7 @@ public void onQuit(PlayerQuitEvent event) {
198192
}
199193
}
200194

201-
private class TimeoutTask implements Runnable {
195+
private class TimeoutTask implements Runnable, ScheduleHandle {
202196
private final Runnable delegate;
203197
private final long timeoutMillis;
204198
private final long intervalTicks;

backends/src/main/java/dev/objz/commandbridge/backends/net/client/RedisClient.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,16 +298,14 @@ private void stopInternal() {
298298
if (p != null) {
299299
try {
300300
p.close();
301-
} catch (Exception ignore) {
301+
} catch (Exception e) {
302+
Log.warn("Failed to close Redis pool: {}", e.getMessage());
302303
}
303304
}
304305
}
305306

306307
private String resolveSecret() {
307-
String s = cfg.security() != null ? cfg.security().secret() : null;
308-
if (s != null && !s.isBlank()) {
309-
return s;
310-
}
311-
return new SecretLoader(dataDir).loadOrCreate();
308+
String configSecret = cfg.security() != null ? cfg.security().secret() : null;
309+
return SecretLoader.resolve(configSecret, dataDir);
312310
}
313311
}

backends/src/main/java/dev/objz/commandbridge/backends/net/client/WsClient.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,7 @@ private void attemptReconnect() {
223223
}
224224

225225
private String resolveSecret() {
226-
String s = cfg.security() != null ? cfg.security().secret() : null;
227-
if (s != null && !s.isBlank()) {
228-
return s;
229-
}
230-
return new SecretLoader(dataDir).loadOrCreate();
226+
String configSecret = cfg.security() != null ? cfg.security().secret() : null;
227+
return SecretLoader.resolve(configSecret, dataDir);
231228
}
232229
}

backends/src/main/java/dev/objz/commandbridge/backends/net/connection/ReconnectHandler.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.objz.commandbridge.backends.net.connection;
22

33
import dev.objz.commandbridge.backends.platform.PlatformAdapter;
4+
import dev.objz.commandbridge.backends.platform.ScheduleHandle;
45
import dev.objz.commandbridge.config.model.BackendsConfig;
56
import dev.objz.commandbridge.logging.Log;
67

@@ -11,7 +12,7 @@ public final class ReconnectHandler {
1112
private final BackendsConfig cfg;
1213
private final PlatformAdapter adapter;
1314
private final AtomicBoolean isReconnecting = new AtomicBoolean(false);
14-
private volatile Object reconnectionTask;
15+
private volatile ScheduleHandle reconnectionTask;
1516
private final Runnable reconnectCallback;
1617

1718
public ReconnectHandler(BackendsConfig cfg, PlatformAdapter adapter, Runnable reconnectCallback) {
@@ -22,10 +23,12 @@ public ReconnectHandler(BackendsConfig cfg, PlatformAdapter adapter, Runnable re
2223

2324
public synchronized void scheduleReconnect() {
2425
if (isReconnecting.get()) {
26+
Log.debug("Reconnect already in progress, skipping");
2527
return;
2628
}
2729

2830
if (reconnectionTask != null) {
31+
Log.debug("Reconnect task already scheduled, skipping");
2932
return;
3033
}
3134

@@ -79,7 +82,7 @@ public synchronized void onReconnectSuccess() {
7982

8083
public synchronized void stopReconnect() {
8184
if (reconnectionTask != null) {
82-
adapter.cancelSchedule(reconnectionTask);
85+
reconnectionTask.cancel();
8386
reconnectionTask = null;
8487
}
8588
isReconnecting.set(false);

backends/src/main/java/dev/objz/commandbridge/backends/platform/PlatformAdapter.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,7 @@ default void load(PlatformEnv env, Object plugin) throws Exception {
4141
* @param task The task to run.
4242
* @param timeout The total duration after which the task should stop running.
4343
* @param interval The delay between executions (frequency).
44-
* @return An object representing the scheduled task (for early cancellation).
44+
* @return A handle for early cancellation.
4545
*/
46-
Object runSchedule(Runnable task, Duration timeout, Duration interval);
47-
48-
/**
49-
* @param task The task object returned by runSchedule.
50-
*/
51-
void cancelSchedule(Object task);
46+
ScheduleHandle runSchedule(Runnable task, Duration timeout, Duration interval);
5247
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package dev.objz.commandbridge.backends.platform;
2+
3+
/**
4+
* A handle to a scheduled repeating task, allowing early cancellation.
5+
*/
6+
@FunctionalInterface
7+
public interface ScheduleHandle {
8+
9+
/**
10+
* Cancels the scheduled task. Safe to call multiple times.
11+
*/
12+
void cancel();
13+
}

backends/velocity/src/main/java/dev/objz/commandbridge/velocity/Adapter.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import dev.objz.commandbridge.backends.net.out.ctx.PlayerListContext;
1717
import dev.objz.commandbridge.backends.net.out.ctx.PlayerUpdateContext;
1818
import dev.objz.commandbridge.backends.platform.PathsUtil;
19+
import dev.objz.commandbridge.backends.platform.ScheduleHandle;
1920
import dev.objz.commandbridge.backends.platform.PlatformAdapter;
2021
import dev.objz.commandbridge.backends.platform.bootstrap.VelocityMain;
2122
import dev.objz.commandbridge.backends.platform.cmd.CommandExecutor;
@@ -142,17 +143,10 @@ public CommandExecutor getCommandExecutor() {
142143
}
143144

144145
@Override
145-
public Object runSchedule(Runnable task, Duration timeout, Duration interval) {
146+
public ScheduleHandle runSchedule(Runnable task, Duration timeout, Duration interval) {
146147
return new TimeoutTask(task, timeout.toMillis(), interval).start();
147148
}
148149

149-
@Override
150-
public void cancelSchedule(Object task) {
151-
if (task instanceof TimeoutTask t) {
152-
t.cancel();
153-
}
154-
}
155-
156150
@Override
157151
public Set<UUID> getOnlinePlayerIds() {
158152
return proxy.getAllPlayers().stream()
@@ -205,7 +199,7 @@ public void onDisconnect(DisconnectEvent event) {
205199
}
206200
}
207201

208-
private class TimeoutTask implements Runnable {
202+
private class TimeoutTask implements Runnable, ScheduleHandle {
209203
private final Runnable delegate;
210204
private final long timeoutMillis;
211205
private final Duration interval;

core/src/main/java/dev/objz/commandbridge/config/ConfigManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public <T> boolean load(Class<T> modelClass) {
8686

8787
var result = profile.normalize(loaded);
8888
this.current = result.config();
89+
Log.debug("Config loaded from '{}' for model {} (valid={})", filePath, modelClass.getSimpleName(), result.ok());
8990

9091
if (!result.ok()) {
9192
Log.error("Invalid config.yml");

0 commit comments

Comments
 (0)