Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
143 commits
Select commit Hold shift + click to select a range
567531e
Add secure single-port HTTP proxy transport
BenCodez Aug 31, 2026
1fd3be9
Validate HTTP client certificates at TLS boundary
BenCodez Aug 31, 2026
d27636b
Harden HTTP transport lifecycle
BenCodez Aug 31, 2026
1d30c94
Address HTTP transport review findings
BenCodez Aug 31, 2026
e9bbe03
Harden HTTP shutdown and protocol parsing
BenCodez Aug 31, 2026
38a37dd
fix(http): retain votes rejected by transport queue
BenCodez Aug 31, 2026
5722685
fix(http): persist outbound deliveries until ack
BenCodez Aug 31, 2026
aa0f8d8
fix(http): persist poll-created backend queues
BenCodez Aug 31, 2026
63e8f9d
fix(http): validate enrollment codes in Control
BenCodez Aug 31, 2026
5b666dc
fix(http): serialize callbacks and renew transport CA
BenCodez Sep 1, 2026
dbf416f
fix(http): verify backend presence against proxy route
BenCodez Sep 1, 2026
ac6a947
fix(http): preserve proxy callback order
BenCodez Sep 1, 2026
f104e61
fix(http): preserve callback order and crash dedup
BenCodez Sep 1, 2026
13fd2b7
fix(http): normalize corrupt fence errors
BenCodez Sep 1, 2026
71f5ca4
fix(http): revoke pending enrollment codes
BenCodez Sep 1, 2026
6216a04
fix(http): distinguish incomplete inbound deliveries
BenCodez Sep 1, 2026
2a9fcc6
test(http): import filesystem helper
BenCodez Sep 1, 2026
9eae8b5
fix(http): bound responses and persist queue roots
BenCodez Sep 1, 2026
b13ce28
test(http): await resumed delivery acknowledgement
BenCodez Sep 1, 2026
0a938cf
fix(http): persist transport directory entries
BenCodez Sep 1, 2026
5949e11
fix(http): coordinate transport lifecycle handoffs
BenCodez Sep 1, 2026
dd1ef83
fix(ci): restore complete proxy source
BenCodez Sep 1, 2026
0e9cf5a
fix(test): disambiguate transport validation assertion
BenCodez Sep 1, 2026
f81aa90
fix(http): validate readiness off the server thread
BenCodez Sep 1, 2026
b7503b9
fix(control): cancel stale transport publication
BenCodez Sep 1, 2026
67e9d12
fix(http): open proxy listener after runtime setup
BenCodez Sep 1, 2026
425664b
Restore HTTP transport after failed control reload
BenCodez Sep 1, 2026
c8b0116
Merge master into codex/http-transport
BenCodez Sep 1, 2026
57517d7
fix(http): restore credentials after failed reload
BenCodez Sep 1, 2026
9b9232b
fix(http): preserve independent delivery retries
BenCodez Sep 2, 2026
59b0805
fix(http): retain rejected vote-party rewards
BenCodez Sep 2, 2026
c10236a
fix(http): import vote-party collection helpers
BenCodez Sep 2, 2026
7fec797
test(http): normalize legacy code expiry precision
BenCodez Sep 2, 2026
01dea25
fix(http): bound streamed response reads
BenCodez Sep 2, 2026
f811389
fix(http): cancel stalled body reads at deadline
BenCodez Sep 2, 2026
7495519
fix(http): recover incomplete TLS provisioning
BenCodez Sep 2, 2026
e23a969
fix(http): defer replacement presence publication
BenCodez Sep 2, 2026
fa1296e
fix(http): flush presence on backend shutdown
BenCodez Sep 4, 2026
bfea6f1
fix(control): defer plugin-message relay publication
BenCodez Sep 4, 2026
b6d0f77
fix(control): harden transport rollback lifecycle
BenCodez Sep 5, 2026
48841b8
Fix durable vote-party effect recovery
BenCodez Sep 5, 2026
a88e705
Use SimpleAPI HTTP transport
BenCodez Sep 7, 2026
63277bc
Declare SimpleAPI HTTP dependency
BenCodez Sep 7, 2026
e6ba72c
Resume vote parties after effect retry
BenCodez Sep 7, 2026
3e17e38
Preserve HTTP messages during replacement
BenCodez Sep 8, 2026
c984404
Merge remote-tracking branch 'origin/master' into codex/http-transport
BenCodez Sep 8, 2026
804271e
Keep HTTP transport retries active
BenCodez Sep 8, 2026
f08dd1c
fix: retry HTTP enrollment failures
BenCodez Sep 8, 2026
7c715cf
Fix HTTP transport replacement during enrollment
BenCodez Sep 8, 2026
bc36371
Defer HTTP callbacks until handler publication
BenCodez Sep 8, 2026
d3fc00e
Make backend transport replacement failure-atomic
BenCodez Sep 8, 2026
59e05f1
Preserve HTTP delivery across publication and shutdown
BenCodez Sep 8, 2026
e3e5774
Preserve proxy delivery across handoff and restart
BenCodez Sep 8, 2026
17a5bd5
Restore Redis transport cleanly on failed handoff
BenCodez Sep 8, 2026
a0ee827
Recover auxiliary HTTP vote deliveries
BenCodez Sep 8, 2026
f772730
Merge remote-tracking branch 'origin/master' into codex/http-transport
BenCodez Sep 8, 2026
158d403
Preserve HTTP delivery state across retries
BenCodez Sep 8, 2026
ce74439
Fence vote-party work during transport changes
BenCodez Sep 9, 2026
874d62f
Harden HTTP handoff and broadcast recovery
BenCodez Sep 9, 2026
c45f3ea
Preserve proxy deliveries across transport changes
BenCodez Sep 10, 2026
f1337fa
Preserve deliveries across transport replacement
BenCodez Sep 10, 2026
ba2c091
Replay Redis handoff after inbound activation
BenCodez Sep 10, 2026
f74a228
Avoid Redis handoff callback lock inversion
BenCodez Sep 10, 2026
38ae6f6
Complete bounded proxy transport handoffs
BenCodez Sep 10, 2026
bf8de86
Preserve proxy runtime during deferred handoffs
BenCodez Sep 10, 2026
058e8e7
Fix deferred transport retirement
BenCodez Sep 10, 2026
59b5e75
Preserve stopped presence during transport disable
BenCodez Sep 10, 2026
18ff986
Harden HTTP transition failure handling
BenCodez Sep 10, 2026
b117c36
Harden HTTP shutdown and cache durability
BenCodez Sep 10, 2026
3e5c168
Make proxy vote delivery crash durable
BenCodez Sep 11, 2026
cbe6046
Preserve live vote retries across reload
BenCodez Sep 11, 2026
d8fbbed
Keep vote completion retries idempotent
BenCodez Sep 11, 2026
a404248
Settle live vote retries before shutdown
BenCodez Sep 11, 2026
0da1c46
Make multi-proxy vote delivery durable
BenCodez Sep 11, 2026
8f75535
Fix proxy retry durability and reload safety
BenCodez Sep 12, 2026
ae66bc7
Fix multi-proxy completion races
BenCodez Sep 12, 2026
ecd70f3
Preserve durable multi-proxy retry fences
BenCodez Sep 12, 2026
f5e6b06
Migrate legacy timed votes before reliable forwarding
BenCodez Sep 12, 2026
4122d62
Retire completed multi-proxy fences safely
BenCodez Sep 12, 2026
dbcdad9
Preserve distinct legacy timed vote rows
BenCodez Sep 12, 2026
58df2c8
Preserve legacy cache row identities
BenCodez Sep 12, 2026
325eb3b
Keep distinct legacy cross-store rows
BenCodez Sep 12, 2026
dc0a0cc
Scope online cache keys by player
BenCodez Sep 12, 2026
b7ab91f
Preserve distinct legacy timed cache rows
BenCodez Sep 12, 2026
ff36658
Keep unpaired legacy JSON cache rows
BenCodez Sep 12, 2026
c3924c5
Reuse retained HTTP listener on method revert
BenCodez Sep 12, 2026
98e8c79
Retain HTTP listener settings for queue recovery
BenCodez Sep 12, 2026
fa9f1a5
Keep cache expiry and transport shutdown scoped
BenCodez Sep 12, 2026
8086691
Preserve HTTP handoff queue during rollback
BenCodez Sep 13, 2026
19ed58b
Keep staged Redis cleanup off the server thread
BenCodez Sep 13, 2026
48185a7
Harden transport retirement and durable proxy state
BenCodez Sep 13, 2026
de0d3f7
Keep vote cache twins consistent
BenCodez Sep 13, 2026
b5d0490
Prepare transport disable off the server thread
BenCodez Sep 13, 2026
17e16d0
Persist retained HTTP listener settings durably
BenCodez Sep 13, 2026
a29828b
Retry rejected live HTTP broadcasts
BenCodez Sep 13, 2026
12d328c
Keep pending proxy ACKs from blocking votes
BenCodez Sep 13, 2026
a4f44ea
Retain timed SQL rows when deletion fails
BenCodez Sep 13, 2026
91108dd
Harden mixed-version proxy delivery
BenCodez Sep 13, 2026
76a65de
Preserve mixed-proxy vote delivery
BenCodez Sep 13, 2026
20081a6
Preserve legacy multi-proxy delivery across restarts
BenCodez Sep 13, 2026
74ead43
Make exclusive transport replacement rollback safe
BenCodez Sep 13, 2026
32f7c1b
Harden presence and legacy multi-proxy retries
BenCodez Sep 13, 2026
a2ad2e4
Harden backend transport cleanup
BenCodez Sep 13, 2026
283c2b2
Harden proxy compatibility edge cases
BenCodez Sep 13, 2026
0ee7950
Harden Control operations and backend scheduling
BenCodez Sep 13, 2026
3acae78
Keep global sync tests snapshot-compatible
BenCodez Sep 13, 2026
60fb262
Harden mixed-version control deployment
BenCodez Sep 13, 2026
b1664b2
Harden artifact reads and legacy proxy delivery
BenCodez Sep 13, 2026
3adf47c
Bound deployments and same-port HTTP changes
BenCodez Sep 14, 2026
a1fafd4
Keep HTTP delivery on verified capable peers
BenCodez Sep 14, 2026
2e49dd6
Persist multi-proxy capability peers
BenCodez Sep 14, 2026
0f0ed27
Harden mixed-version proxy capability discovery
BenCodez Sep 14, 2026
713e07c
Harden durable proxy capability discovery
BenCodez Sep 14, 2026
15eea84
Cover durable proxy lease retry
BenCodez Sep 16, 2026
72d5183
Recover interrupted plugin activation
BenCodez Sep 16, 2026
b3cac6f
Add verified VotingPlugin staging service
BenCodez Sep 18, 2026
dec7cd1
Test verified VotingPlugin staging
BenCodez Sep 18, 2026
157ddde
Enable verified Control staging on Bukkit nodes
BenCodez Sep 18, 2026
c3be440
Cover deployment capability advertisement
BenCodez Sep 18, 2026
d89bdf5
Enable verified Control staging on proxy nodes
BenCodez Sep 18, 2026
f623288
Expose deterministic proxy capability advertisement
BenCodez Sep 18, 2026
607129f
Cover proxy deployment capability advertisement
BenCodez Sep 18, 2026
3369cb8
Harden verified deployment transport and idempotency
BenCodez Sep 18, 2026
187db97
Restrict backend deployment to active secure routes
BenCodez Sep 18, 2026
bca3ec4
Fence and secure proxy deployment polling
BenCodez Sep 18, 2026
ad2c992
Cover secure deployment and consumed Bukkit updates
BenCodez Sep 18, 2026
f938c9f
Document verified deployment protocol
BenCodez Sep 18, 2026
632058f
Document verified deployment protocol
BenCodez Sep 18, 2026
a2b1381
Fix verified deployment hardening build
BenCodez Sep 18, 2026
5e4a20e
Merge current master with deployment capability gates
BenCodez Sep 19, 2026
b12bf79
Complete queued proxy deployment on connector shutdown
BenCodez Sep 19, 2026
fa14482
Merge current master into verified update staging
BenCodez Sep 19, 2026
5766dbf
Recognize verified staged artifact across deployment retries
BenCodez Sep 19, 2026
ef2be52
Publish deployment marker before proxy activation
BenCodez Sep 19, 2026
9bd840f
Reject unsafe Bukkit update targets and unknown deployment fields
BenCodez Sep 20, 2026
0c5b725
Require atomic deployment publication
BenCodez Sep 20, 2026
1c592fc
Merge current master into secure HTTP transport
BenCodez Sep 20, 2026
d3d46fd
Integrate deployment hardening and package HTTP transport classes
BenCodez Sep 20, 2026
43fbf0b
Continue rollover queue after retryable auxiliary broadcast
BenCodez Sep 20, 2026
bc9dac6
Require proxy method v2 for HTTP quick apply
BenCodez Sep 20, 2026
4c99045
Preserve deferred proxy method and gate HTTP previews
BenCodez Sep 20, 2026
88e7858
Keep live vote timestamps stable across retries
BenCodez Sep 20, 2026
f95f2a3
Normalize HTTP proxy capability selection
BenCodez Sep 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion VotingPlugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@
<shadedPattern>
${project.groupId}.votingplugin.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>org.bouncycastle</pattern>
<shadedPattern>${project.groupId}.votingplugin.bouncycastle</shadedPattern>
</relocation>
<relocation>
<pattern>xyz.upperlevel.spigot</pattern>
<shadedPattern>
Expand Down Expand Up @@ -209,12 +213,17 @@
<artifact>com.bencodez:simpleapi</artifact>
<excludes>
<exclude>org/bouncycastle/**</exclude>
<exclude>com/bencodez/simpleapi/servercomm/http/**</exclude>
<exclude>redis/clients/**</exclude>
<exclude>org/eclipse/paho/**</exclude>
<exclude>META-INF/versions/**</exclude>
</excludes>
</filter>
<filter>
<artifact>org.bouncycastle:*</artifact>
<excludes>
<exclude>META-INF/versions/25/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
Expand Down Expand Up @@ -433,6 +442,12 @@
<version>2.14.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.bencodez</groupId>
<artifactId>simpleapi</artifactId>
<version>1.0.2-SNAPSHOT</version>
<scope>compile</scope>
Comment thread
BenCodez marked this conversation as resolved.
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.bencodez.votingplugin.backendproxy.transport.BackendProxyTransportManager;
import com.bencodez.votingplugin.backendproxy.voteparty.BackendVotePartySync;
import com.bencodez.votingplugin.proxy.BungeeMethod;
import com.bencodez.votingplugin.proxy.VotingPluginWire;

import lombok.Getter;

Expand All @@ -39,6 +40,11 @@ public class BackendProxyHandler implements Listener {
private final BackendGlobalDataSync globalDataSync;

private BackendPresenceManager presenceManager;
private boolean presenceReportingActivated;
private final Object inboundPublication = new Object();
private boolean inboundPublished;
private boolean inboundAborted;
private BackendProxyHandler inboundRollbackTarget;
private BackendVotePartySync votePartySync;
private BackendProxyMessageRouter messageRouter;

Expand All @@ -62,12 +68,26 @@ public BackendProxyHandler(VotingPluginMain plugin, ProcessedVoteCache processed
* Loads the configured backend/proxy communication components.
*/
public void load() {
load(true);
}

/** Loads a replacement without announcing a new presence generation before publication. */
public void loadForReplacement() {
load(false);
}

private void load(boolean activatePresenceReporting) {
plugin.debug("Loading backend proxy handler");
method = BungeeMethod.getByName(plugin.getBungeeSettings().getBungeeMethod());
plugin.getLogger().info("Using BungeeMethod: " + method.toString());

globalDataSync.load();
globalMessageHandler = new GlobalMessageHandler() {
@Override
public void onMessage(JsonEnvelope envelope) {
BackendProxyHandler.this.dispatchIncomingAfterPublication(envelope, () -> super.onMessage(envelope));
}

@Override
public void sendMessage(JsonEnvelope envelope) {
transportManager.send(envelope);
Expand All @@ -79,20 +99,40 @@ public void sendMessage(JsonEnvelope envelope) {
messageRouter = new BackendProxyMessageRouter(plugin, presenceManager, globalDataSync, votePartySync,
processedVoteCache);
messageRouter.register(globalMessageHandler, method);
transportManager.start(method, globalMessageHandler);
transportManager.start(method, globalMessageHandler, activatePresenceReporting);

if (plugin.getOptions().getServer().equalsIgnoreCase("pleaseset")) {
plugin.getLogger().warning("Server name for bungee voting is not set, please set it");
}
presenceManager.start();
if (activatePresenceReporting) {
activatePresenceReporting();
activateInboundMessages();
}
}

/** Starts presence only after a staged handler reaches the atomic publication boundary. */
public void activatePresenceReporting() {
if (presenceManager != null && !presenceReportingActivated) {
presenceManager.start();
presenceReportingActivated = true;
}
// Presence startup can throw while scheduling its heartbeat. Keep inbound
// HTTP callbacks behind the publication barrier until every fallible part of
// the replacement is active, so rollback cannot race a queued callback.
transportManager.activateAfterPublication();
}

/**
* Closes backend/proxy components and persists cached proxy state.
*/
public void close() {
if (presenceManager != null) {
synchronized (inboundPublication) {
if (!inboundPublished && !inboundAborted) inboundAborted = true;
inboundPublication.notifyAll();
}
if (presenceManager != null && presenceReportingActivated) {
presenceManager.stop();
presenceReportingActivated = false;
}
transportManager.close();
if (votePartySync != null) {
Expand All @@ -101,26 +141,207 @@ public void close() {
globalDataSync.close();
}

/** Releases a same-method subscriber/listener before its replacement starts. */
public void prepareForReplacement(BungeeMethod replacementMethod) {
if (method == replacementMethod && method != BungeeMethod.PLUGINMESSAGING && method != BungeeMethod.REDIS) {
/** Opens inbound dispatch only after the replacement and all handoffs are committed. */
public void activateInboundMessages() {
synchronized (inboundPublication) {
if (inboundAborted) return;
inboundPublished = true;
inboundPublication.notifyAll();
}
}

/** Routes an already accepted staged callback through the restored predecessor on rollback. */
public void abortStagedInboundTo(BackendProxyHandler previous) {
synchronized (inboundPublication) {
if (inboundPublished || inboundAborted) return;
inboundRollbackTarget = previous;
inboundAborted = true;
inboundPublication.notifyAll();
}
}

void dispatchIncomingAfterPublication(JsonEnvelope envelope, Runnable localDispatch) {
BackendProxyHandler rollbackTarget;
synchronized (inboundPublication) {
while (!inboundPublished && !inboundAborted) {
try {
inboundPublication.wait();
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
return;
}
}
rollbackTarget = inboundPublished ? null : inboundRollbackTarget;
if (!inboundPublished && rollbackTarget == null) return;
}
if (rollbackTarget != null) {
GlobalMessageHandler rollbackHandler = rollbackTarget.globalMessageHandler;
if (rollbackHandler != null) rollbackHandler.onMessage(envelope);
return;
}
// Global-data checks perform synchronous SQL and already run on their own
// timer worker. Explicitly dispatch an inbound wake-up asynchronously too:
// plugin messaging can invoke this method on Bukkit's primary thread.
if (VotingPluginWire.SUB_BUNGEE_TIME_CHANGE.equals(envelope.getSubChannel())) {
plugin.getBukkitScheduler().runTaskAsynchronously(plugin, localDispatch);
return;
Comment thread
BenCodez marked this conversation as resolved.
}
plugin.getBukkitScheduler().executeOrScheduleSync(plugin, localDispatch);
Comment thread
BenCodez marked this conversation as resolved.
}

/** Returns whether replacement preparation must preserve accepted deliveries. */
public boolean requiresPreparationForReplacement() {
return method == BungeeMethod.HTTP || method == BungeeMethod.PLUGINMESSAGING
|| transportManager.hasPendingAsyncHandoff() || transportManager.hasPendingRedisReplay();
}

/** Prepares HTTP state or waits off-thread for an earlier cross-transport handoff. */
public boolean prepareForReplacement(BungeeMethod replacementMethod) {
return prepareForReplacement(replacementMethod,
System.nanoTime() + java.util.concurrent.TimeUnit.SECONDS.toNanos(25));
}

public boolean prepareForReplacement(BungeeMethod replacementMethod, long deadlineNanos) {
// SocketHandler swallows a listener bind failure. A same-method replacement
// must therefore retire its listener before the staged handler is started;
// rollback recreates this prepared transport if validation later fails.
if (method == BungeeMethod.SOCKETS && replacementMethod == BungeeMethod.SOCKETS) {
transportManager.prepareForReplacement();
return true;
}
if (method == BungeeMethod.MQTT && replacementMethod == BungeeMethod.MQTT) {
// A duplicate MQTT ClientID disconnects the live broker session, so stage
// only after retiring the predecessor and restore it on validation rollback.
transportManager.prepareForReplacement();
return true;
}
if (method == BungeeMethod.HTTP) {
transportManager.prepareForReplacement();
return true;
}
if (method == BungeeMethod.PLUGINMESSAGING) {
transportManager.prepareAsyncHandoffForReplacement(deadlineNanos);
return true;
}
if (method == BungeeMethod.REDIS && replacementMethod != BungeeMethod.REDIS) {
if (transportManager.hasPendingAsyncHandoff())
transportManager.prepareAsyncHandoffForReplacement(deadlineNanos);
return transportManager.prepareRedisReplayTransition(replacementMethod, deadlineNanos);
}
if (method == BungeeMethod.REDIS) {
// Same-Redis retirement installs its send fence during the bounded
// off-thread handoff. Returning true here lets the staged replacement
// buffer its own sends until the predecessor FIFO is admitted at Bukkit
// publication.
return true;
}
if (!transportManager.hasPendingAsyncHandoff()) return false;
transportManager.prepareAsyncHandoffForReplacement(deadlineNanos);
return true;
}

/** Atomically fences new sends only when disabling cannot discard prepared HTTP messages. */
public boolean commitPreparedDisable() {
return transportManager.commitPreparedDisable();
}

/** Publishes the final presence update while fencing other sends before transport preparation. */
public void preparePresenceForDisable() {
preparePresenceForDisableInternal(null);
}

/** Publishes the final presence update before the caller's validation deadline. */
public void preparePresenceForDisable(long deadlineNanos) {
preparePresenceForDisableInternal(deadlineNanos);
}

private void preparePresenceForDisableInternal(Long deadlineNanos) {
transportManager.beginPreparedDisable();
if (presenceManager != null && presenceReportingActivated) {
// stopForDisable may reject when the transport cannot accept the final
// presence update. Mark this inactive first so rollback can start it again.
presenceReportingActivated = false;
if (deadlineNanos == null) presenceManager.stopForDisable();
else presenceManager.stopForDisable(deadlineNanos);
}
}

/** Restores delivery and presence when a prepared disable is abandoned. */
public void restorePresenceAfterFailedDisablePreparation() {
transportManager.cancelPreparedDisable();
activatePresenceReporting();
}

public void beginPreparedHttpHandoff() {
transportManager.beginPreparedHttpHandoff();
}

/** Reserves staged HTTP capacity before publication can admit replacement sends. */
public void reservePreparedHttpHandoff(BackendProxyHandler replacement) {
transportManager.reservePreparedTransportHandoff(replacement.transportManager);
}

/** Restores a prepared HTTP transport when its replacement fails validation. */
public void restoreAfterFailedReplacement() {
transportManager.restoreAfterFailedReplacement();
}

/** Restores a failed same-Redis predecessor without discarding its replacement's replay FIFO. */
public void restoreAfterFailedReplacement(BackendProxyHandler failedReplacement) {
transportManager.restoreAfterFailedReplacement(
failedReplacement == null ? null : failedReplacement.transportManager);
}

/** Reasserts the old handler with a fresh presence generation after rollback. */
public void refreshPresenceAfterFailedReplacement() {
if (presenceManager != null && presenceReportingActivated) {
presenceManager.stop();
presenceManager.start();
}
}

public void awaitRestoreAfterFailedReplacement(long deadlineNanos) {
transportManager.awaitPreparedTransportRestoration(deadlineNanos);
}

/** Fails a configuration apply when its selected transport did not initialize. */
public void validateTransport() {
validateTransport(System.nanoTime() + java.util.concurrent.TimeUnit.SECONDS.toNanos(25));
}

/** Validates transport startup without extending the caller's existing deadline. */
public void validateTransport(long deadlineNanos) {
if (method == null || globalMessageHandler == null || presenceManager == null) {
throw new IllegalStateException("Backend proxy handler initialization failed");
}
transportManager.validate();
transportManager.validate(deadlineNanos);
}

/** Completes the no-loss/no-duplicate same-Redis subscriber handoff after validation. */
public void completeRedisHandoff(BackendProxyHandler replacement) {
if (method != BungeeMethod.REDIS || replacement.method != BungeeMethod.REDIS) return;
transportManager.closeRedisForHandoff();
replacement.transportManager.activateRedisAfterHandoff();
if (!requiresRedisHandoff(replacement)) return;
transportManager.completeRedisHandoff(replacement.transportManager);
}

/** Returns whether this handler owns a Redis listener whose shutdown can block. */
public boolean requiresRedisRetirement() {
return method == BungeeMethod.REDIS;
}

/** Returns whether this replacement needs the bounded same-Redis retirement path. */
public boolean requiresRedisHandoff(BackendProxyHandler replacement) {
return replacement != null && method == BungeeMethod.REDIS && replacement.method == BungeeMethod.REDIS;
}

/** Replays Redis handoff deliveries only after inbound publication is open. */
public void replayRedisAfterHandoffPublication() {
transportManager.replayRedisAfterHandoffPublication();
}

/** Forwards messages buffered while the previous transport was fenced. */
public void completeHttpHandoff(BackendProxyHandler replacement) {
if (replacement == null) return;
transportManager.completePreparedTransportHandoff(replacement.transportManager);
}

public void playerOnline(String playerName, String uuid) {
Expand All @@ -136,14 +357,15 @@ public void playerOffline(String playerName) {
}

public void reloadPresenceReporting() {
if (presenceManager != null) {
if (presenceManager != null && presenceReportingActivated) {
presenceManager.reload();
}
}

public void disablePresenceReporting() {
if (presenceManager != null) {
if (presenceManager != null && presenceReportingActivated) {
presenceManager.stop();
presenceReportingActivated = false;
}
}

Expand Down
Loading
Loading