Throttle client-link requests per player
This commit is contained in:
2 files changed
+22
-1
No files matched your search
@@ -22,6 +22,9 @@ public final class ClientLink {
|
|||||||
private final Map<UUID, String> lastState = new ConcurrentHashMap<>();
|
private final Map<UUID, String> lastState = new ConcurrentHashMap<>();
|
||||||
private final Map<UUID, String> lastClaimsKey = new ConcurrentHashMap<>();
|
private final Map<UUID, String> lastClaimsKey = new ConcurrentHashMap<>();
|
||||||
private final Set<UUID> clients = ConcurrentHashMap.newKeySet();
|
private final Set<UUID> clients = ConcurrentHashMap.newKeySet();
|
||||||
|
private final Map<UUID, Long> lastRequest = new ConcurrentHashMap<>();
|
||||||
|
/** One request per player at most this often; a modded client can't turn the link into a panel flood. */
|
||||||
|
static final long MIN_REQUEST_GAP_MS = 400;
|
||||||
|
|
||||||
public ClientLink(Env env, PlayerCache cache, String serverName, BiConsumer<CorePlayer, byte[]> out) {
|
public ClientLink(Env env, PlayerCache cache, String serverName, BiConsumer<CorePlayer, byte[]> out) {
|
||||||
this.env = env; this.cache = cache; this.serverName = serverName; this.out = out;
|
this.env = env; this.cache = cache; this.serverName = serverName; this.out = out;
|
||||||
@@ -30,7 +33,7 @@ public final class ClientLink {
|
|||||||
public boolean hasClient(UUID uuid) { return clients.contains(uuid); }
|
public boolean hasClient(UUID uuid) { return clients.contains(uuid); }
|
||||||
|
|
||||||
public void disconnected(UUID uuid) {
|
public void disconnected(UUID uuid) {
|
||||||
clients.remove(uuid); lastState.remove(uuid); lastClaimsKey.remove(uuid); cache.forget(uuid);
|
clients.remove(uuid); lastState.remove(uuid); lastClaimsKey.remove(uuid); lastRequest.remove(uuid); cache.forget(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send(CorePlayer p, JsonObject message) { out.accept(p, Wire.encode(message.toString())); }
|
private void send(CorePlayer p, JsonObject message) { out.accept(p, Wire.encode(message.toString())); }
|
||||||
@@ -42,6 +45,9 @@ public final class ClientLink {
|
|||||||
catch (RuntimeException e) { return; }
|
catch (RuntimeException e) { return; }
|
||||||
String type = PlayerCache.str(msg, "t", "");
|
String type = PlayerCache.str(msg, "t", "");
|
||||||
if (!env.features.clientLink()) return;
|
if (!env.features.clientLink()) return;
|
||||||
|
long now = env.clock.getAsLong();
|
||||||
|
Long previous = lastRequest.put(p.uuid(), now);
|
||||||
|
if (previous != null && now - previous < MIN_REQUEST_GAP_MS && !type.equals("hello")) return;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "hello" -> hello(p);
|
case "hello" -> hello(p);
|
||||||
case "refresh" -> { if (clients.contains(p.uuid())) { lastState.remove(p.uuid()); cache.refresh(p, info -> pushState(p)); } }
|
case "refresh" -> { if (clients.contains(p.uuid())) { lastState.remove(p.uuid()); cache.refresh(p, info -> pushState(p)); } }
|
||||||
|
|||||||
@@ -102,12 +102,27 @@ class LinkTest {
|
|||||||
assertEquals(99.0, last("state").get("balance").getAsDouble());
|
assertEquals(99.0, last("state").get("balance").getAsDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test void requestsAreThrottledPerPlayer() {
|
||||||
|
link.receive(alex, msg("{\"t\":\"hello\"}"));
|
||||||
|
kit.panel.on("economy/market", "[]");
|
||||||
|
kit.now.addAndGet(1000);
|
||||||
|
link.receive(alex, msg("{\"t\":\"market\"}"));
|
||||||
|
for (int i = 0; i < 20; i++) link.receive(alex, msg("{\"t\":\"market\"}"));
|
||||||
|
assertEquals(1, kit.panel.calls.stream().filter(c -> c.equals("economy/market")).count(), "a burst is one panel call");
|
||||||
|
kit.now.addAndGet(ClientLink.MIN_REQUEST_GAP_MS + 1);
|
||||||
|
link.receive(alex, msg("{\"t\":\"market\"}"));
|
||||||
|
assertEquals(2, kit.panel.calls.stream().filter(c -> c.equals("economy/market")).count());
|
||||||
|
}
|
||||||
|
|
||||||
@Test void marketAndShopRequests() {
|
@Test void marketAndShopRequests() {
|
||||||
link.receive(alex, msg("{\"t\":\"hello\"}"));
|
link.receive(alex, msg("{\"t\":\"hello\"}"));
|
||||||
|
kit.now.addAndGet(1000);
|
||||||
kit.panel.on("economy/market", "[{\"id\":7,\"seller_name\":\"Mia\",\"item_id\":\"DIAMOND\",\"item_name\":\"Diamond\",\"amount\":3,\"price\":99.5}]");
|
kit.panel.on("economy/market", "[{\"id\":7,\"seller_name\":\"Mia\",\"item_id\":\"DIAMOND\",\"item_name\":\"Diamond\",\"amount\":3,\"price\":99.5}]");
|
||||||
link.receive(alex, msg("{\"t\":\"market\"}"));
|
link.receive(alex, msg("{\"t\":\"market\"}"));
|
||||||
|
kit.now.addAndGet(1000);
|
||||||
assertEquals(7, last("market").getAsJsonArray("listings").get(0).getAsJsonObject().get("id").getAsInt());
|
assertEquals(7, last("market").getAsJsonArray("listings").get(0).getAsJsonObject().get("id").getAsInt());
|
||||||
alex.held = new Item("DIAMOND", "Diamond", 4, "");
|
alex.held = new Item("DIAMOND", "Diamond", 4, "");
|
||||||
|
kit.now.addAndGet(1000);
|
||||||
link.receive(alex, msg("{\"t\":\"shop\"}"));
|
link.receive(alex, msg("{\"t\":\"shop\"}"));
|
||||||
JsonObject shop = last("shop");
|
JsonObject shop = last("shop");
|
||||||
assertTrue(shop.getAsJsonArray("items").size() > 10);
|
assertTrue(shop.getAsJsonArray("items").size() > 10);
|
||||||
|
|||||||
Reference in new issue
Block a user