Skip to content
Open
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
334 changes: 174 additions & 160 deletions core/src/main/java/org/geysermc/geyser/GeyserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -505,167 +505,9 @@ private void startInstance() {
}
}

MetricsPlatform metricsPlatform = bootstrap.createMetricsPlatform();
if (metricsPlatform != null && metricsPlatform.enabled()) {
metrics = new MetricsBase(
"server-implementation",
metricsPlatform.serverUuid(),
Constants.BSTATS_ID,
true, // Already checked above.
builder -> {
// OS specific data
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();

builder.appendField("osName", osName);
builder.appendField("osArch", osArch);
builder.appendField("osVersion", osVersion);
builder.appendField("coreCount", coreCount);
},
builder -> {},
null,
() -> true,
logger::error,
logger::info,
metricsPlatform.logFailedRequests(),
metricsPlatform.logSentData(),
metricsPlatform.logResponseStatusText(),
metricsPlatform.disableRelocateCheck()
);
metrics.addCustomChart(new SingleLineChart("players", sessionManager::size));
// Prevent unwanted words best we can
metrics.addCustomChart(new SimplePie("authMode", () -> config.java().authType().toString().toLowerCase(Locale.ROOT)));

Map<String, Map<String, Integer>> platformTypeMap = new HashMap<>();
Map<String, Integer> serverPlatform = new HashMap<>();
serverPlatform.put(bootstrap.getServerPlatform(), 1);
platformTypeMap.put(platformType().platformName(), serverPlatform);

metrics.addCustomChart(new DrilldownPie("platform", () -> {
// By the end, we should return, for example:
// Geyser-Spigot => (Paper, 1)
return platformTypeMap;
}));

metrics.addCustomChart(new SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
metrics.addCustomChart(new SimplePie("version", () -> GeyserImpl.VERSION));
metrics.addCustomChart(new SimplePie("javaHaProxyProtocol", () -> String.valueOf(config.advanced().java().useHaproxyProtocol())));
metrics.addCustomChart(new SimplePie("bedrockHaProxyProtocol", () -> String.valueOf(config.advanced().bedrock().useHaproxyProtocol())));
metrics.addCustomChart(new AdvancedPie("playerPlatform", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (GeyserSession session : sessionManager.getAllSessions()) {
if (session == null) continue;
if (session.getClientData() == null) continue;
String os = session.getClientData().getDeviceOs().toString();
if (!valueMap.containsKey(os)) {
valueMap.put(os, 1);
} else {
valueMap.put(os, valueMap.get(os) + 1);
}
}
return valueMap;
}));
metrics.addCustomChart(new AdvancedPie("playerVersion", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (GeyserSession session : sessionManager.getAllSessions()) {
if (session == null) continue;
if (session.getClientData() == null) continue;
String version = session.getClientData().getGameVersion();
if (!valueMap.containsKey(version)) {
valueMap.put(version, 1);
} else {
valueMap.put(version, valueMap.get(version) + 1);
}
}
return valueMap;
}));

String minecraftVersion = bootstrap.getMinecraftServerVersion();
if (minecraftVersion != null) {
Map<String, Map<String, Integer>> versionMap = new HashMap<>();
Map<String, Integer> platformMap = new HashMap<>();
platformMap.put(bootstrap.getServerPlatform(), 1);
versionMap.put(minecraftVersion, platformMap);

metrics.addCustomChart(new DrilldownPie("minecraftServerVersion", () -> {
// By the end, we should return, for example:
// 1.16.5 => (Spigot, 1)
return versionMap;
}));
}

// The following code can be attributed to the PaperMC project
// https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0005-Paper-Metrics.patch#L614
metrics.addCustomChart(new DrilldownPie("javaVersion", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
String javaVersion = System.getProperty("java.version");
Map<String, Integer> entry = new HashMap<>();
entry.put(javaVersion, 1);

// http://openjdk.java.net/jeps/223
// Java decided to change their versioning scheme and in doing so modified the
// java.version system property to return $major[.$minor][.$security][-ea], as opposed to
// 1.$major.0_$identifier we can handle pre-9 by checking if the "major" is equal to "1",
// otherwise, 9+
String majorVersion = javaVersion.split("\\.")[0];
String release;

int indexOf = javaVersion.lastIndexOf('.');

if (majorVersion.equals("1")) {
release = "Java " + javaVersion.substring(0, indexOf);
} else {
// of course, it really wouldn't be all that simple if they didn't add a quirk, now
// would it valid strings for the major may potentially include values such as -ea to
// denote a pre release
Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion);
if (versionMatcher.find()) {
majorVersion = versionMatcher.group(0);
}
release = "Java " + majorVersion;
}
map.put(release, entry);
return map;
}));
} else {
metrics = null;
}
setupMetrics(config, logger);

if (config.java().authType() == AuthType.ONLINE) {
// May be written/read to on multiple threads from each GeyserSession as well as writing the config
savedAuthChains = new ConcurrentHashMap<>();
Type type = new TypeToken<Map<String, String>>() { }.getType();

File authChainsFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile();
if (authChainsFile.exists()) {
Map<String, String> authChainFile = null;
try (FileReader reader = new FileReader(authChainsFile)) {
authChainFile = GSON.fromJson(reader, type);
} catch (IOException e) {
logger.error("Cannot load saved user tokens!", e);
}
if (authChainFile != null) {
List<String> validUsers = config.savedUserLogins();
boolean doWrite = false;
for (Map.Entry<String, String> entry : authChainFile.entrySet()) {
String user = entry.getKey();
if (!validUsers.contains(user)) {
// Perform a write to this file to purge the now-unused name
doWrite = true;
continue;
}
savedAuthChains.put(user, entry.getValue());
}
if (doWrite) {
scheduleAuthChainsWrite();
}
}
}
} else {
savedAuthChains = null;
}
loadSavedAuthChains(config, logger);

newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED);

Expand Down Expand Up @@ -949,4 +791,176 @@ private void scheduleAuthChainsWrite() {
}
});
}

/**
* Initializes bStats metrics collection with platform, player, and version charts.
*/
private void setupMetrics(GeyserConfig config, GeyserLogger logger) {
MetricsPlatform metricsPlatform = bootstrap.createMetricsPlatform();
if (metricsPlatform != null && metricsPlatform.enabled()) {
metrics = new MetricsBase(
"server-implementation",
metricsPlatform.serverUuid(),
Constants.BSTATS_ID,
true, // Already checked above.
builder -> {
// OS specific data
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();

builder.appendField("osName", osName);
builder.appendField("osArch", osArch);
builder.appendField("osVersion", osVersion);
builder.appendField("coreCount", coreCount);
},
builder -> {},
null,
() -> true,
logger::error,
logger::info,
metricsPlatform.logFailedRequests(),
metricsPlatform.logSentData(),
metricsPlatform.logResponseStatusText(),
metricsPlatform.disableRelocateCheck()
);
metrics.addCustomChart(new SingleLineChart("players", sessionManager::size));
// Prevent unwanted words best we can
metrics.addCustomChart(new SimplePie("authMode", () -> config.java().authType().toString().toLowerCase(Locale.ROOT)));

Map<String, Map<String, Integer>> platformTypeMap = new HashMap<>();
Map<String, Integer> serverPlatform = new HashMap<>();
serverPlatform.put(bootstrap.getServerPlatform(), 1);
platformTypeMap.put(platformType().platformName(), serverPlatform);

metrics.addCustomChart(new DrilldownPie("platform", () -> {
// By the end, we should return, for example:
// Geyser-Spigot => (Paper, 1)
return platformTypeMap;
}));

metrics.addCustomChart(new SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
metrics.addCustomChart(new SimplePie("version", () -> GeyserImpl.VERSION));
metrics.addCustomChart(new SimplePie("javaHaProxyProtocol", () -> String.valueOf(config.advanced().java().useHaproxyProtocol())));
metrics.addCustomChart(new SimplePie("bedrockHaProxyProtocol", () -> String.valueOf(config.advanced().bedrock().useHaproxyProtocol())));
metrics.addCustomChart(new AdvancedPie("playerPlatform", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (GeyserSession session : sessionManager.getAllSessions()) {
if (session == null) continue;
if (session.getClientData() == null) continue;
String os = session.getClientData().getDeviceOs().toString();
if (!valueMap.containsKey(os)) {
valueMap.put(os, 1);
} else {
valueMap.put(os, valueMap.get(os) + 1);
}
}
return valueMap;
}));
metrics.addCustomChart(new AdvancedPie("playerVersion", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (GeyserSession session : sessionManager.getAllSessions()) {
if (session == null) continue;
if (session.getClientData() == null) continue;
String version = session.getClientData().getGameVersion();
if (!valueMap.containsKey(version)) {
valueMap.put(version, 1);
} else {
valueMap.put(version, valueMap.get(version) + 1);
}
}
return valueMap;
}));

String minecraftVersion = bootstrap.getMinecraftServerVersion();
if (minecraftVersion != null) {
Map<String, Map<String, Integer>> versionMap = new HashMap<>();
Map<String, Integer> platformMap = new HashMap<>();
platformMap.put(bootstrap.getServerPlatform(), 1);
versionMap.put(minecraftVersion, platformMap);

metrics.addCustomChart(new DrilldownPie("minecraftServerVersion", () -> {
// By the end, we should return, for example:
// 1.16.5 => (Spigot, 1)
return versionMap;
}));
}

// The following code can be attributed to the PaperMC project
// https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0005-Paper-Metrics.patch#L614
metrics.addCustomChart(new DrilldownPie("javaVersion", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
String javaVersion = System.getProperty("java.version");
Map<String, Integer> entry = new HashMap<>();
entry.put(javaVersion, 1);

// http://openjdk.java.net/jeps/223
// Java decided to change their versioning scheme and in doing so modified the
// java.version system property to return $major[.$minor][.$security][-ea], as opposed to
// 1.$major.0_$identifier we can handle pre-9 by checking if the "major" is equal to "1",
// otherwise, 9+
String majorVersion = javaVersion.split("\\.")[0];
String release;

int indexOf = javaVersion.lastIndexOf('.');

if (majorVersion.equals("1")) {
release = "Java " + javaVersion.substring(0, indexOf);
} else {
// of course, it really wouldn't be all that simple if they didn't add a quirk, now
// would it valid strings for the major may potentially include values such as -ea to
// denote a pre release
Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion);
if (versionMatcher.find()) {
majorVersion = versionMatcher.group(0);
}
release = "Java " + majorVersion;
}
map.put(release, entry);
return map;
}));
} else {
metrics = null;
}
}

/**
* Loads saved authentication chains from disk for online-mode session resumption.
*/
private void loadSavedAuthChains(GeyserConfig config, GeyserLogger logger) {
if (config.java().authType() == AuthType.ONLINE) {
// May be written/read to on multiple threads from each GeyserSession as well as writing the config
savedAuthChains = new ConcurrentHashMap<>();
Type type = new TypeToken<Map<String, String>>() { }.getType();

File authChainsFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile();
if (authChainsFile.exists()) {
Map<String, String> authChainFile = null;
try (FileReader reader = new FileReader(authChainsFile)) {
authChainFile = GSON.fromJson(reader, type);
} catch (IOException e) {
logger.error("Cannot load saved user tokens!", e);
}
if (authChainFile != null) {
List<String> validUsers = config.savedUserLogins();
boolean doWrite = false;
for (Map.Entry<String, String> entry : authChainFile.entrySet()) {
String user = entry.getKey();
if (!validUsers.contains(user)) {
// Perform a write to this file to purge the now-unused name
doWrite = true;
continue;
}
savedAuthChains.put(user, entry.getValue());
}
if (doWrite) {
scheduleAuthChainsWrite();
}
}
}
} else {
savedAuthChains = null;
}
}
}
Loading
Loading