feat(dashboard): refine activity telemetry and maps
This commit is contained in:
@@ -59,6 +59,43 @@ final class AccountManagerClient {
|
||||
}
|
||||
}
|
||||
|
||||
boolean reportConnected(UUID minecraftUuid, String username) {
|
||||
String compactUuid = minecraftUuid.toString().replace("-", "").toLowerCase();
|
||||
ConnectionRequest payload = new ConnectionRequest(
|
||||
UUID.randomUUID().toString(),
|
||||
config.serverId(),
|
||||
compactUuid,
|
||||
username,
|
||||
Instant.now().toString()
|
||||
);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(config.apiUrl() + "/api/velocity/connection"))
|
||||
.timeout(config.timeout())
|
||||
.header("Authorization", "Bearer " + config.apiToken())
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(gson.toJson(payload)))
|
||||
.build();
|
||||
|
||||
try {
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
return response.statusCode() == 204;
|
||||
} catch (InterruptedException exception) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
} catch (IOException | RuntimeException exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private record ConnectionRequest(
|
||||
String requestId,
|
||||
String serverId,
|
||||
String minecraftUuid,
|
||||
String username,
|
||||
String occurredAt
|
||||
) {}
|
||||
|
||||
private record AccessRequest(
|
||||
String requestId,
|
||||
String serverId,
|
||||
|
||||
+20
-1
@@ -5,9 +5,11 @@ import com.velocitypowered.api.event.EventTask;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.ResultedEvent;
|
||||
import com.velocitypowered.api.event.connection.LoginEvent;
|
||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@@ -22,13 +24,15 @@ import org.slf4j.Logger;
|
||||
public final class MinecraftAccountManagerPlugin {
|
||||
private final Logger logger;
|
||||
private final Path dataDirectory;
|
||||
private final ProxyServer proxyServer;
|
||||
private volatile AccountManagerClient accountManagerClient;
|
||||
private volatile String fallbackMessage = "Please register your Minecraft account in Discord before joining.";
|
||||
|
||||
@Inject
|
||||
public MinecraftAccountManagerPlugin(Logger logger, @DataDirectory Path dataDirectory) {
|
||||
public MinecraftAccountManagerPlugin(Logger logger, @DataDirectory Path dataDirectory, ProxyServer proxyServer) {
|
||||
this.logger = logger;
|
||||
this.dataDirectory = dataDirectory;
|
||||
this.proxyServer = proxyServer;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -66,4 +70,19 @@ public final class MinecraftAccountManagerPlugin {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
proxyServer.getScheduler().buildTask(this, () -> {
|
||||
AccountManagerClient client = accountManagerClient;
|
||||
if (client == null) return;
|
||||
boolean recorded = client.reportConnected(
|
||||
event.getPlayer().getUniqueId(),
|
||||
event.getPlayer().getUsername()
|
||||
);
|
||||
if (!recorded) {
|
||||
logger.warn("Could not report confirmed Minecraft connection for {} ({})", event.getPlayer().getUsername(), event.getPlayer().getUniqueId());
|
||||
}
|
||||
}).schedule();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,15 @@ package games.dmg.accountmanager;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AccountManagerClientTest {
|
||||
@@ -27,4 +33,55 @@ class AccountManagerClientTest {
|
||||
assertFalse(decision.allowed());
|
||||
assertEquals("Register through Discord.", decision.message());
|
||||
}
|
||||
|
||||
@Test
|
||||
void reportsConfirmedConnectionsToTheAuthenticatedEndpoint() throws IOException {
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
||||
AtomicReference<String> body = new AtomicReference<>();
|
||||
AtomicReference<String> authorization = new AtomicReference<>();
|
||||
server.createContext("/api/velocity/connection", exchange -> {
|
||||
body.set(new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8));
|
||||
authorization.set(exchange.getRequestHeaders().getFirst("Authorization"));
|
||||
exchange.sendResponseHeaders(204, -1);
|
||||
exchange.close();
|
||||
});
|
||||
server.start();
|
||||
try {
|
||||
PluginConfig config = new PluginConfig(
|
||||
"http://127.0.0.1:" + server.getAddress().getPort(),
|
||||
"velocity-test",
|
||||
"test-token",
|
||||
Duration.ofSeconds(2),
|
||||
"Register through Discord."
|
||||
);
|
||||
|
||||
assertTrue(new AccountManagerClient(config).reportConnected(
|
||||
UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5"),
|
||||
"Notch"
|
||||
));
|
||||
assertEquals("Bearer test-token", authorization.get());
|
||||
assertTrue(body.get().contains("\"minecraftUuid\":\"069a79f444e94726a5befca90e38aaf5\""));
|
||||
assertTrue(body.get().contains("\"username\":\"Notch\""));
|
||||
} finally {
|
||||
server.stop(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void connectionReportingIsBestEffortWhenTheApiCannotBeReached() {
|
||||
PluginConfig config = new PluginConfig(
|
||||
"http://127.0.0.1:1",
|
||||
"velocity-test",
|
||||
"test-token",
|
||||
Duration.ofMillis(100),
|
||||
"Register through Discord."
|
||||
);
|
||||
|
||||
boolean recorded = new AccountManagerClient(config).reportConnected(
|
||||
UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5"),
|
||||
"Notch"
|
||||
);
|
||||
|
||||
assertFalse(recorded);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user