Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public static void clearCache(@NotNull UUID player) {
});
}

private record CacheKey(@NotNull UUID requester, @NotNull UUID formatFor) {
private record CacheKey(@NotNull UUID requester, @NotNull UUID formatFor, @NotNull String scope) {

private boolean contains(@NotNull UUID player) {
return requester.equals(player) || formatFor.equals(player);
Expand Down Expand Up @@ -168,7 +168,7 @@ private CompletableFuture<String> formatPlaceholders(@NotNull String text, @NotN
if (!requester.isConnected()) {
return CompletableFuture.completedFuture(text);
}
final CacheKey cacheKey = new CacheKey(requester.getUniqueId(), formatFor);
final CacheKey cacheKey = new CacheKey(requester.getUniqueId(), formatFor, requester.getPlaceholderCacheScope());
if (cacheExpiry > 0 && cache.containsKey(cacheKey) && cache.get(cacheKey).containsKey(text)) {
return CompletableFuture.completedFuture(cache.get(cacheKey).get(text));
}
Expand Down Expand Up @@ -273,7 +273,7 @@ private CompletableFuture<Component> formatComponentPlaceholders(@NotNull String
if (!requester.isConnected()) {
return CompletableFuture.completedFuture(Component.text(text));
}
final CacheKey cacheKey = new CacheKey(requester.getUniqueId(), formatFor);
final CacheKey cacheKey = new CacheKey(requester.getUniqueId(), formatFor, requester.getPlaceholderCacheScope());
if (cacheExpiry > 0 && componentCache.containsKey(cacheKey) && componentCache.get(cacheKey).containsKey(text)) {
return CompletableFuture.completedFuture(componentCache.get(cacheKey).get(text));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ public interface OnlineUser {
@NotNull
UUID getUniqueId();

/**
* Returns the runtime context in which placeholder results may be reused.
* Implementations should change this value when the same user can resolve
* placeholders against a different backend or data source.
*
* @return the placeholder cache scope
*/
@NotNull
default String getPlaceholderCacheScope() {
return "";
}

default void sendMessage(@NotNull PAPIProxyBridge plugin, @NotNull Request request, boolean wantsJson, boolean isRequest) {
final ByteArrayDataOutput messageWriter = ByteStreams.newDataOutput();
final UUID uuid = getUniqueId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;

Expand Down Expand Up @@ -89,6 +90,30 @@ void componentCacheUsesRequesterAndFormattingTarget() {
assertEquals(3, bridge.requests.get());
}

@Test
void cacheIsIsolatedByBackendServer() {
final TestProxyUser proxyUser = new TestProxyUser(UUID.randomUUID(), "lobby");
bridge.response = "lobby";
assertEquals("lobby", api.formatPlaceholders("%server_name%", proxyUser).join());

proxyUser.serverName = "survival";
bridge.response = "survival";
assertEquals("survival", api.formatPlaceholders("%server_name%", proxyUser).join());
assertEquals(2, bridge.requests.get());
}

@Test
void componentCacheIsIsolatedByBackendServer() {
final TestProxyUser proxyUser = new TestProxyUser(UUID.randomUUID(), "lobby");
bridge.response = "{\"text\":\"lobby\"}";
assertEquals(Component.text("lobby"), api.formatComponentPlaceholders("%server_name%", proxyUser).join());

proxyUser.serverName = "survival";
bridge.response = "{\"text\":\"survival\"}";
assertEquals(Component.text("survival"), api.formatComponentPlaceholders("%server_name%", proxyUser).join());
assertEquals(2, bridge.requests.get());
}

@Test
void retriesFailedRequests() {
api.setRetryTimes(1);
Expand All @@ -99,11 +124,23 @@ void retriesFailedRequests() {
assertEquals(2, bridge.requests.get());
}

@Test
void retriesTimedOutRequests() throws Exception {
api.setRequestTimeout(20);
api.setRetryTimes(1);
bridge.timeouts = 1;
bridge.response = "formatted";

assertEquals("formatted", api.formatPlaceholders("%name%", requester).get(1, TimeUnit.SECONDS));
assertEquals(2, bridge.requests.get());
}

private static final class TestBridge implements PAPIProxyBridge {
private final TestUser user;
private final AtomicInteger requests = new AtomicInteger();
private String response;
private int failures;
private int timeouts;

private TestBridge(TestUser user) {
this.user = user;
Expand All @@ -128,6 +165,9 @@ public Optional<? extends OnlineUser> findPlayer(@NotNull UUID uuid) {
public CompletableFuture<String> createRequest(@NotNull String text, @NotNull OnlineUser requester,
@NotNull UUID formatFor, boolean wantsJson, long requestTimeout) {
requests.incrementAndGet();
if (timeouts-- > 0) {
return new CompletableFuture<>();
}
if (failures-- > 0) {
return CompletableFuture.failedFuture(new IllegalStateException("failed"));
}
Expand Down Expand Up @@ -182,4 +222,33 @@ private record TestUser(UUID uuid) implements OnlineUser {
public void handleMessage(@NotNull PAPIProxyBridge plugin, @NotNull Request message, boolean wantsJson) {
}
}

private static final class TestProxyUser implements OnlineUser {
private final UUID uuid;
private String serverName;

private TestProxyUser(UUID uuid, String serverName) {
this.uuid = uuid;
this.serverName = serverName;
}

@Override
public @NotNull String getUsername() {
return "proxy-user";
}

@Override
public @NotNull UUID getUniqueId() {
return uuid;
}

@Override
public @NotNull String getPlaceholderCacheScope() {
return serverName;
}

@Override
public void handleMessage(@NotNull PAPIProxyBridge plugin, @NotNull Request message, boolean wantsJson) {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,10 @@ default void handleMessage(@NotNull PAPIProxyBridge plugin, @NotNull Request mes
@NotNull
String getServerName();

@Override
@NotNull
default String getPlaceholderCacheScope() {
return getServerName();
}

}
Loading