Rewrote the way server information is loaded on enable

- The UUID of the server (and other info) is stored in a file
  on Proxy servers as well to speed up loading time.
- The information is stored in two places, with preference for the info in
  the file. The information is updated after the plugin has enabled.

This opens a possibility for a bug, where user changes UUID inside
Bungee file, leading to the Bungee storing a second BungeeCord entry to
the database. This can lead to issues. If this comes up the file
can be changed to different format (to deter users from modifying it manually)

Affects issues:
- Close #1247
  - Fixed #1478
  - Fixed #1496
  - Fixed #1637
This commit is contained in:
Risto Lahtela 2020-11-05 20:17:48 +02:00
parent 0e4529dcd6
commit e13516b43c
25 changed files with 386 additions and 315 deletions

View File

@ -17,22 +17,17 @@
package com.djrapitops.plan.identification;
import com.djrapitops.plan.delivery.webserver.Addresses;
import com.djrapitops.plan.delivery.webserver.WebServer;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.identification.properties.ServerProperties;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.Database;
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.identification.storage.ServerDBLoader;
import com.djrapitops.plan.identification.storage.ServerFileLoader;
import com.djrapitops.plan.identification.storage.ServerLoader;
import com.djrapitops.plan.processing.Processing;
import com.djrapitops.plugin.logging.console.PluginLogger;
import dagger.Lazy;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
/**
* Manages Server information on the Bungee instance.
@ -42,58 +37,52 @@ import java.util.concurrent.ExecutionException;
@Singleton
public class BungeeServerInfo extends ServerInfo {
private final DBSystem dbSystem;
private final ServerLoader fromFile;
private final ServerLoader fromDatabase;
private final Processing processing;
private final Addresses addresses;
private final Lazy<WebServer> webServer;
private final PluginLogger logger;
@Inject
public BungeeServerInfo(
ServerProperties serverProperties,
DBSystem dbSystem,
ServerFileLoader fromFile,
ServerDBLoader fromDatabase,
Processing processing,
Addresses addresses,
Lazy<WebServer> webServer,
PluginLogger logger
) {
super(serverProperties);
this.dbSystem = dbSystem;
this.fromFile = fromFile;
this.fromDatabase = fromDatabase;
this.processing = processing;
this.addresses = addresses;
this.webServer = webServer;
this.logger = logger;
}
@Override
public void loadServerInfo() throws EnableException {
public void loadServerInfo() {
checkIfDefaultIP();
try {
Database database = dbSystem.getDatabase();
Optional<Server> proxyInfo = database.query(ServerQueries.fetchProxyServerInformation());
if (proxyInfo.isPresent()) {
server = proxyInfo.get();
updateServerInfo();
} else {
server = registerBungeeInfo(database);
}
} catch (DBOpException | ExecutionException e) {
throw new EnableException("Failed to read Server information from Database.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
this.server = fromFile.load(null).orElseGet(() -> fromDatabase.load(null)
.orElseGet(this::registerServer));
processing.submitNonCritical(this::updateStorage);
}
private void updateServerInfo() {
addresses.getAccessAddress().ifPresent(this::saveAddress);
private void updateStorage() {
String address = addresses.getAccessAddress().orElseGet(addresses::getFallbackLocalhostAddress);
server.setWebAddress(address);
fromDatabase.save(server);
fromFile.save(server);
}
private void saveAddress(String accessAddress) {
if (!accessAddress.equals(server.getWebAddress())) {
server.setWebAddress(accessAddress);
dbSystem.getDatabase().executeTransaction(new StoreServerInformationTransaction(server));
}
}
private void checkIfDefaultIP() throws EnableException {
/**
* @throws EnableException
*/
private void checkIfDefaultIP() {
String ip = serverProperties.getIp();
if ("0.0.0.0".equals(ip)) {
logger.error("IP setting still 0.0.0.0 - Configure Alternative_IP/IP that connects to the Proxy server.");
@ -102,18 +91,26 @@ public class BungeeServerInfo extends ServerInfo {
}
}
private Server registerBungeeInfo(Database db) throws EnableException, ExecutionException, InterruptedException {
/**
* @throws EnableException
*/
private Server registerServer() {
Server proxy = createServerObject();
fromDatabase.save(proxy);
Server stored = fromDatabase.load(null)
.orElseThrow(() -> new EnableException("BungeeCord registration failed (DB)"));
fromFile.save(stored);
return stored;
}
/**
* @throws EnableException
*/
private Server createServerObject() {
UUID serverUUID = generateNewUUID();
String accessAddress = addresses.getAccessAddress().orElseThrow(() -> new EnableException("BungeeCord can not have '0.0.0.0' or '' as an address. Set up 'Server.IP' setting."));
Server proxy = new Server(-1, serverUUID, "BungeeCord", accessAddress, serverProperties.getMaxPlayers());
db.executeTransaction(new StoreServerInformationTransaction(proxy))
.get();
Optional<Server> proxyInfo = db.query(ServerQueries.fetchProxyServerInformation());
if (proxyInfo.isPresent()) {
return proxyInfo.get();
}
throw new EnableException("BungeeCord registration failed (Was not found in the database after saving)");
String accessAddress = addresses.getAccessAddress().orElseThrow(() -> new EnableException("Velocity can not have '0.0.0.0' or '' as an address. Set up 'Server.IP' setting."));
return new Server(-1, serverUUID, "BungeeCord", accessAddress);
}
}

View File

@ -77,7 +77,7 @@ public class TabCompleteCache implements SubSystem {
for (Map.Entry<UUID, Server> server : serverNames.entrySet()) {
serverIdentifiers.add(server.getKey().toString());
serverIdentifiers.add(server.getValue().getIdentifiableName());
serverIdentifiers.add(Integer.toString(server.getValue().getId()));
server.getValue().getId().ifPresent(id -> serverIdentifiers.add(Integer.toString(id)));
}
}

View File

@ -126,7 +126,7 @@ public class LinkCommands {
String serversListed = dbSystem.getDatabase()
.query(ServerQueries.fetchPlanServerInformationCollection())
.stream().sorted()
.map(server -> m + server.getId() + "::" + t + server.getName() + "::" + s + server.getUuid() + "\n")
.map(server -> m + server.getId().orElse(0) + "::" + t + server.getName() + "::" + s + server.getUuid() + "\n")
.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
.toString();
sender.buildMessage()

View File

@ -17,6 +17,7 @@
package com.djrapitops.plan.identification;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
@ -26,21 +27,23 @@ import java.util.UUID;
*/
public class Server implements Comparable<Server> {
private final UUID uuid;
private int id;
private Integer id;
private String name;
private String webAddress;
private int maxPlayers;
public Server(int id, UUID uuid, String name, String webAddress, int maxPlayers) {
public Server(UUID uuid, String name, String webAddress) {
this(null, uuid, name, webAddress);
}
public Server(Integer id, UUID uuid, String name, String webAddress) {
this.id = id;
this.uuid = uuid;
this.name = name;
this.webAddress = webAddress;
this.maxPlayers = maxPlayers;
}
public int getId() {
return id;
public Optional<Integer> getId() {
return Optional.ofNullable(id);
}
public void setId(int id) {
@ -71,10 +74,6 @@ public class Server implements Comparable<Server> {
this.webAddress = webAddress;
}
public int getMaxPlayers() {
return maxPlayers;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -97,7 +96,6 @@ public class Server implements Comparable<Server> {
", id=" + id +
", name='" + name + '\'' +
", webAddress='" + webAddress + '\'' +
", maxPlayers=" + maxPlayers +
'}';
}
@ -114,7 +112,4 @@ public class Server implements Comparable<Server> {
return !isProxy();
}
public void setMaxPlayers(int maxPlayers) {
this.maxPlayers = maxPlayers;
}
}

View File

@ -19,7 +19,6 @@ package com.djrapitops.plan.identification;
import com.djrapitops.plan.SubSystem;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.identification.properties.ServerProperties;
import com.djrapitops.plugin.utilities.Verify;
import java.util.Optional;
import java.util.UUID;
@ -57,12 +56,12 @@ public abstract class ServerInfo implements SubSystem {
}
@Override
public void enable() throws EnableException {
public void enable() {
loadServerInfo();
Verify.nullCheck(server, () -> new EnableException("Server information did not load!"));
if (server == null) throw new EnableException("Server information did not load!");
}
protected abstract void loadServerInfo() throws EnableException;
protected abstract void loadServerInfo();
@Override
public void disable() {

View File

@ -1,67 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.identification;
import com.djrapitops.plan.settings.config.Config;
import com.djrapitops.plan.settings.config.ConfigReader;
import com.djrapitops.plan.storage.file.PlanFiles;
import com.djrapitops.plugin.utilities.Verify;
import javax.inject.Inject;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
/**
* Manages local server info file.
* <p>
* Server.yml contains current server's ID, UUID and Bungee WebServer connection information.
* It
*
* @author Rsl1122
*/
public class ServerInfoFile extends Config {
private final PlanFiles files;
@Inject
public ServerInfoFile(PlanFiles files) {
super(files.getFileFromPluginFolder("ServerInfoFile.yml"));
this.files = files;
}
public void prepare() throws IOException {
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar("DefaultServerInfoFile.yml").asInputStream())) {
copyMissing(reader.read());
}
save();
}
public void saveServerUUID(UUID serverUUID) throws IOException {
set("Server.UUID", serverUUID.toString());
save();
}
public Optional<UUID> getUUID() {
String uuidString = getString("Server.UUID");
if (Verify.isEmpty(uuidString)) {
return Optional.empty();
}
return Optional.of(UUID.fromString(uuidString));
}
}

View File

@ -18,25 +18,18 @@ package com.djrapitops.plan.identification;
import com.djrapitops.plan.delivery.webserver.Addresses;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.identification.properties.ServerProperties;
import com.djrapitops.plan.identification.storage.ServerDBLoader;
import com.djrapitops.plan.identification.storage.ServerFileLoader;
import com.djrapitops.plan.identification.storage.ServerLoader;
import com.djrapitops.plan.processing.Processing;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.PluginSettings;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.Database;
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.utilities.logging.ErrorContext;
import com.djrapitops.plan.utilities.logging.ErrorLogger;
import com.djrapitops.plugin.logging.L;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
/**
* Manages the Server UUID for Bukkit servers.
@ -48,124 +41,70 @@ import java.util.concurrent.ExecutionException;
@Singleton
public class ServerServerInfo extends ServerInfo {
private final ServerInfoFile serverInfoFile;
private final ServerLoader fromFile;
private final ServerLoader fromDatabase;
private final PlanConfig config;
private final Processing processing;
private final DBSystem dbSystem;
private final Addresses addresses;
private final ErrorLogger errorLogger;
@Inject
public ServerServerInfo(
ServerProperties serverProperties,
ServerInfoFile serverInfoFile,
ServerFileLoader fromFile,
ServerDBLoader fromDatabase,
Processing processing,
PlanConfig config,
DBSystem dbSystem,
Addresses addresses,
ErrorLogger errorLogger
Addresses addresses
) {
super(serverProperties);
this.serverInfoFile = serverInfoFile;
this.fromFile = fromFile;
this.fromDatabase = fromDatabase;
this.processing = processing;
this.dbSystem = dbSystem;
this.addresses = addresses;
this.config = config;
this.errorLogger = errorLogger;
}
@Override
public void enable() throws EnableException {
try {
serverInfoFile.prepare();
} catch (IOException e) {
throw new EnableException("Failed to read ServerInfoFile.yml", e);
}
super.enable();
}
@Override
protected void loadServerInfo() throws EnableException {
Optional<UUID> serverUUID = serverInfoFile.getUUID();
try {
if (serverUUID.isPresent()) {
server = createServerObject(serverUUID.get());
processing.submitNonCritical(() -> updateDbInfo(serverUUID.get()));
} else {
server = registerServer();
}
} catch (DBOpException e) {
String causeMsg = e.getMessage();
throw new EnableException("Failed to read Server information from Database: " + causeMsg, e);
} catch (IOException e) {
throw new EnableException("Failed to read ServerInfoFile.yml", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
throw new EnableException("Failed to perform a database transaction to store the server information", e);
}
Optional<Server> loaded = fromFile.load(null);
server = loaded.orElseGet(this::registerNew);
processing.submitNonCritical(this::updateStorage);
}
private void updateDbInfo(UUID serverUUID) {
Database db = dbSystem.getDatabase();
Optional<Server> foundServer = db.query(ServerQueries.fetchServerMatchingIdentifier(serverUUID));
if (!foundServer.isPresent()) {
try {
server = registerServer(serverUUID);
} catch (IOException e) {
errorLogger.log(L.CRITICAL, e, ErrorContext.builder()
.whatToDo("Grant access permissions for writing to " + serverInfoFile.getConfigFilePath()).build());
} catch (ExecutionException e) {
errorLogger.log(L.CRITICAL, e, ErrorContext.builder().build());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return;
}
server = foundServer.get();
// Update information
private void updateStorage() {
String address = addresses.getAccessAddress().orElseGet(addresses::getFallbackLocalhostAddress);
String name = config.get(PluginSettings.SERVER_NAME);
server.setName("plan".equalsIgnoreCase(name) ? "Server " + server.getId() : name);
addresses.getAccessAddress().ifPresent(server::setWebAddress);
server.setName(name);
server.setWebAddress(address);
int maxPlayers = serverProperties.getMaxPlayers();
server.setMaxPlayers(maxPlayers);
// Save
db.executeTransaction(new StoreServerInformationTransaction(server));
fromDatabase.save(server);
fromFile.save(server);
}
private Server registerServer() throws ExecutionException, InterruptedException, IOException {
return registerServer(generateNewUUID());
private Server registerNew() {
return registerNew(generateNewUUID());
}
private Server registerServer(UUID serverUUID) throws ExecutionException, InterruptedException, IOException {
Database db = dbSystem.getDatabase();
private Server registerNew(UUID serverUUID) {
Server server = createServerObject(serverUUID);
fromDatabase.save(server);
// Save
db.executeTransaction(new StoreServerInformationTransaction(server))
.get(); // Wait until transaction has completed
// Load from database
server = db.query(ServerQueries.fetchServerMatchingIdentifier(serverUUID))
.orElseThrow(() -> new IllegalStateException("Failed to Register Server (ID not found)"));
// Store the UUID in ServerInfoFile
serverInfoFile.saveServerUUID(serverUUID);
return server;
Server stored = fromDatabase.load(serverUUID)
.orElseThrow(() -> new EnableException("Failed to register server (not found after saving to database)"));
fromFile.save(stored);
return stored;
}
private Server createServerObject(UUID serverUUID) {
String webAddress = addresses.getAccessAddress().orElse(addresses.getFallbackLocalhostAddress());
String webAddress = addresses.getAccessAddress().orElseGet(addresses::getFallbackLocalhostAddress);
String name = config.get(PluginSettings.SERVER_NAME);
int maxPlayers = serverProperties.getMaxPlayers();
return new Server(-1, serverUUID, name, webAddress, maxPlayers);
return new Server(serverUUID, name, webAddress);
}
}

View File

@ -24,7 +24,7 @@ import java.util.function.Supplier;
*
* @author Rsl1122
*/
public abstract class ServerProperties {
public class ServerProperties {
private final String name;
private final int port;
@ -33,7 +33,7 @@ public abstract class ServerProperties {
private final Supplier<String> ip;
private final int maxPlayers;
protected ServerProperties(
public ServerProperties(
String name,
int port,
String version,

View File

@ -0,0 +1,72 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.identification.storage;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.identification.Server;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
@Singleton
public class ServerDBLoader implements ServerLoader {
private final DBSystem dbSystem;
@Inject
public ServerDBLoader(
DBSystem dbSystem
) {
this.dbSystem = dbSystem;
}
@Override
public Optional<Server> load(UUID serverUUID) {
try {
if (serverUUID == null) {
// Assumes that we want the server that has single entry in the database, the proxy
return dbSystem.getDatabase().query(ServerQueries.fetchProxyServerInformation());
}
return dbSystem.getDatabase().query(
ServerQueries.fetchServerMatchingIdentifier(serverUUID)
);
} catch (DBOpException e) {
throw new EnableException("Failed to read Server information from Database: " + e.getMessage(), e);
}
}
@Override
public void save(Server server) {
try {
dbSystem.getDatabase().executeTransaction(
new StoreServerInformationTransaction(server)
).get(); // Wait until transaction has completed;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
throw new EnableException("Failed to save server information to database: " + e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,94 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.identification.storage;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.identification.Server;
import com.djrapitops.plan.settings.config.Config;
import com.djrapitops.plan.settings.config.ConfigReader;
import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.PluginSettings;
import com.djrapitops.plan.storage.file.PlanFiles;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
@Singleton
public class ServerFileLoader extends Config implements ServerLoader {
private final PlanFiles files;
private final PlanConfig config;
private boolean prepared;
@Inject
public ServerFileLoader(
PlanFiles files,
PlanConfig config
) {
super(files.getFileFromPluginFolder("ServerInfoFile.yml"));
this.files = files;
this.config = config;
prepared = false;
}
public void prepare() throws IOException {
try (ConfigReader reader = new ConfigReader(files.getResourceFromJar("DefaultServerInfoFile.yml").asInputStream())) {
copyMissing(reader.read());
}
save();
prepared = true;
}
@Override
public Optional<Server> load(UUID loaded) {
try {
if (!prepared) prepare();
String serverUUIDString = getString("Server.UUID");
if (serverUUIDString == null) return Optional.empty();
Integer id = getInteger("Server.ID");
UUID serverUUID = UUID.fromString(serverUUIDString);
String name = config.get(PluginSettings.SERVER_NAME);
String address = getString("Server.Web_address");
return Optional.of(new Server(id, serverUUID, name, address));
} catch (IOException e) {
throw new EnableException("Failed to read ServerInfoFile.yml: " + e.getMessage());
}
}
@Override
public void save(Server server) {
try {
if (!prepared) prepare();
server.getId().ifPresent(id -> set("Server.ID", id));
set("Server.UUID", server.getUuid());
set("Server.Web_address", server.getWebAddress());
save();
} catch (IOException e) {
throw new EnableException("Failed to write ServerInfoFile.yml: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,48 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.identification.storage;
import com.djrapitops.plan.identification.Server;
import java.util.Optional;
import java.util.UUID;
/**
* Interface for operating on server information.
*
* @author Rsl1122
*/
public interface ServerLoader {
/**
* Load the server information.
*
* @param serverUUID
* @return Optional of the saved information or empty if it has not been stored.
* @throws com.djrapitops.plan.exceptions.EnableException When the loading fails
*/
Optional<Server> load(UUID serverUUID);
/**
* Save the server information.
*
* @param information Information to save.
* @throws com.djrapitops.plan.exceptions.EnableException When the saving fails
*/
void save(Server information);
}

View File

@ -164,7 +164,6 @@ public class LargeStoreQueries {
statement.setString(2, name);
statement.setString(3, webAddress);
statement.setBoolean(4, true);
statement.setInt(5, info.getMaxPlayers());
statement.addBatch();
}
}

View File

@ -65,8 +65,7 @@ public class ServerQueries {
set.getInt(ServerTable.SERVER_ID),
serverUUID,
set.getString(ServerTable.NAME),
set.getString(ServerTable.WEB_ADDRESS),
set.getInt(ServerTable.MAX_PLAYERS)));
set.getString(ServerTable.WEB_ADDRESS)));
}
return servers;
}
@ -107,8 +106,7 @@ public class ServerQueries {
set.getInt(ServerTable.SERVER_ID),
UUID.fromString(set.getString(ServerTable.SERVER_UUID)),
set.getString(ServerTable.NAME),
set.getString(ServerTable.WEB_ADDRESS),
set.getInt(ServerTable.MAX_PLAYERS)
set.getString(ServerTable.WEB_ADDRESS)
));
}
return Optional.empty();
@ -167,8 +165,7 @@ public class ServerQueries {
set.getInt(ServerTable.SERVER_ID),
UUID.fromString(set.getString(ServerTable.SERVER_UUID)),
set.getString(ServerTable.NAME),
set.getString(ServerTable.WEB_ADDRESS),
set.getInt(ServerTable.MAX_PLAYERS)
set.getString(ServerTable.WEB_ADDRESS)
));
}
return matches;

View File

@ -40,18 +40,18 @@ public class ServerTable {
public static final String NAME = "name";
public static final String WEB_ADDRESS = "web_address";
public static final String INSTALLED = "is_installed";
@Deprecated
public static final String MAX_PLAYERS = "max_players";
public static final String INSERT_STATEMENT = Insert.values(TABLE_NAME,
SERVER_UUID, NAME,
WEB_ADDRESS, INSTALLED, MAX_PLAYERS);
WEB_ADDRESS, INSTALLED);
public static final String UPDATE_STATEMENT = Update.values(TABLE_NAME,
SERVER_UUID,
NAME,
WEB_ADDRESS,
INSTALLED,
MAX_PLAYERS)
INSTALLED)
.where(SERVER_UUID + "=?")
.toString();

View File

@ -53,8 +53,7 @@ public class StoreServerInformationTransaction extends Transaction {
statement.setString(2, server.getName());
statement.setString(3, server.getWebAddress());
statement.setBoolean(4, true);
statement.setInt(5, server.getMaxPlayers());
statement.setString(6, serverUUIDString);
statement.setString(5, serverUUIDString);
}
};
}
@ -67,7 +66,6 @@ public class StoreServerInformationTransaction extends Transaction {
statement.setString(2, server.getName());
statement.setString(3, server.getWebAddress());
statement.setBoolean(4, true);
statement.setInt(5, server.getMaxPlayers());
}
};
}

View File

@ -36,7 +36,7 @@ public class Version10Patch extends Patch {
@Override
protected void applyPatch() {
Optional<Server> server = query(ServerQueries.fetchServerMatchingIdentifier(getServerUUID()));
serverID = server.map(Server::getId)
serverID = server.flatMap(Server::getId)
.orElseThrow(() -> new IllegalStateException("Server UUID was not registered, try rebooting the plugin."));
alterTablesToV10();

View File

@ -1,4 +1,6 @@
# Changing the UUID in this file will make Plan regard your server as a completely new server
# Tread with caution.
Server:
ID:
UUID:
Web_address:

View File

@ -109,7 +109,7 @@ class ShutdownSaveTest {
UUID playerUUID = TestConstants.PLAYER_ONE_UUID;
String worldName = TestConstants.WORLD_ONE_NAME;
database.executeTransaction(new StoreServerInformationTransaction(new Server(-1, serverUUID, "-", "", 0)));
database.executeTransaction(new StoreServerInformationTransaction(new Server(serverUUID, "-", "")));
database.executeTransaction(new PlayerRegisterTransaction(playerUUID, () -> 0L, TestConstants.PLAYER_ONE_NAME));
database.executeTransaction(new WorldNameStoreTransaction(serverUUID, worldName))
.get();

View File

@ -91,7 +91,7 @@ public class H2Test implements DatabaseTest,
db().executeTransaction(new CreateTablesTransaction());
db().executeTransaction(new RemoveEverythingTransaction());
db().executeTransaction(new StoreServerInformationTransaction(new Server(-1, serverUUID(), "ServerName", "", 20)));
db().executeTransaction(new StoreServerInformationTransaction(new Server(serverUUID(), "ServerName", "")));
assertEquals(serverUUID(), ((SQLDB) db()).getServerUUIDSupplier().get());
}

View File

@ -98,7 +98,7 @@ class MySQLTest implements DatabaseTest,
db().executeTransaction(new CreateTablesTransaction());
db().executeTransaction(new RemoveEverythingTransaction());
db().executeTransaction(new StoreServerInformationTransaction(new Server(-1, serverUUID(), "ServerName", "", 20)));
db().executeTransaction(new StoreServerInformationTransaction(new Server(serverUUID(), "ServerName", "")));
assertEquals(serverUUID(), ((SQLDB) db()).getServerUUIDSupplier().get());
}
@AfterAll

View File

@ -91,7 +91,7 @@ public class SQLiteTest implements DatabaseTest,
db().executeTransaction(new CreateTablesTransaction());
db().executeTransaction(new RemoveEverythingTransaction());
db().executeTransaction(new StoreServerInformationTransaction(new Server(-1, serverUUID(), "ServerName", "", 20)));
db().executeTransaction(new StoreServerInformationTransaction(new Server(serverUUID(), "ServerName", "")));
assertEquals(serverUUID(), ((SQLDB) db()).getServerUUIDSupplier().get());
}

View File

@ -56,7 +56,7 @@ public interface ServerQueriesTest extends DatabaseTestPreparer {
assertFalse(bungeeInfo.isPresent());
UUID bungeeUUID = UUID.randomUUID();
Server bungeeCord = new Server(-1, bungeeUUID, "BungeeCord", "Random:1234", 20);
Server bungeeCord = new Server(bungeeUUID, "BungeeCord", "Random:1234");
db().executeTransaction(new StoreServerInformationTransaction(bungeeCord));
forcePersistenceCheck();

View File

@ -37,27 +37,27 @@ public class TestData {
/* Utility class */
}
private static UUID playerUUID = TestConstants.PLAYER_ONE_UUID;
private static UUID player2UUID = TestConstants.PLAYER_TWO_UUID;
private static UUID serverUUID = TestConstants.SERVER_UUID;
private static UUID server2UUID = TestConstants.SERVER_TWO_UUID;
private static String playerName = TestConstants.PLAYER_ONE_NAME;
private static String player2Name = TestConstants.PLAYER_TWO_NAME;
private static final UUID playerUUID = TestConstants.PLAYER_ONE_UUID;
private static final UUID player2UUID = TestConstants.PLAYER_TWO_UUID;
private static final UUID serverUUID = TestConstants.SERVER_UUID;
private static final UUID server2UUID = TestConstants.SERVER_TWO_UUID;
private static final String playerName = TestConstants.PLAYER_ONE_NAME;
private static final String player2Name = TestConstants.PLAYER_TWO_NAME;
private static String[] serverWorldNames = new String[]{
private static final String[] serverWorldNames = new String[]{
TestConstants.WORLD_ONE_NAME, "World Two", "world"
};
private static String[] server2WorldNames = new String[]{
private static final String[] server2WorldNames = new String[]{
"Foo", "Bar", "Z"
};
private static long playerFirstJoin = 1234500L;
private static long playerSecondJoin = 234000L;
private static final long playerFirstJoin = 1234500L;
private static final long playerSecondJoin = 234000L;
private static List<Session> playerSessions = createSessionsForPlayer(playerUUID);
private static List<Session> player2Sessions = createSessionsForPlayer(player2UUID);
private static final List<Session> playerSessions = createSessionsForPlayer(playerUUID);
private static final List<Session> player2Sessions = createSessionsForPlayer(player2UUID);
private static List<GeoInfo> playerGeoInfo = createGeoInfoForPlayer();
private static final List<GeoInfo> playerGeoInfo = createGeoInfoForPlayer();
private static List<GeoInfo> createGeoInfoForPlayer() {
List<GeoInfo> geoInfos = new ArrayList<>();
@ -96,8 +96,8 @@ public class TestData {
return new Transaction() {
@Override
protected void performOperations() {
executeOther(new StoreServerInformationTransaction(new Server(-1, serverUUID, "Server 1", "", 20)));
executeOther(new StoreServerInformationTransaction(new Server(-1, server2UUID, "Server 2", "", 50)));
executeOther(new StoreServerInformationTransaction(new Server(serverUUID, "Server 1", "")));
executeOther(new StoreServerInformationTransaction(new Server(server2UUID, "Server 2", "")));
for (String worldName : serverWorldNames) {
executeOther(new WorldNameStoreTransaction(serverUUID, worldName));

View File

@ -41,6 +41,6 @@ public class PluginServerPropertiesModule {
"1.13-git-mock",
() -> new InetSocketAddress(25565).getAddress().getHostAddress(),
20
) {};
);
}
}

View File

@ -18,77 +18,70 @@ package com.djrapitops.plan.identification;
import com.djrapitops.plan.delivery.webserver.Addresses;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.identification.properties.ServerProperties;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.Database;
import com.djrapitops.plan.storage.database.queries.objects.ServerQueries;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.identification.storage.ServerDBLoader;
import com.djrapitops.plan.identification.storage.ServerFileLoader;
import com.djrapitops.plan.identification.storage.ServerLoader;
import com.djrapitops.plan.processing.Processing;
import com.djrapitops.plugin.logging.console.PluginLogger;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
/**
* Manages Server information on the Bungee instance.
* Manages Server information on the Velocity instance.
*
* @author Rsl1122
*/
@Singleton
public class VelocityServerInfo extends ServerInfo {
private final DBSystem dbSystem;
private final ServerLoader fromFile;
private final ServerLoader fromDatabase;
private final Processing processing;
private final Addresses addresses;
private final PluginLogger logger;
@Inject
public VelocityServerInfo(
ServerProperties serverProperties,
DBSystem dbSystem,
Addresses addresses,
ServerFileLoader fromFile,
ServerDBLoader fromDatabase,
Processing processing, Addresses addresses,
PluginLogger logger
) {
super(serverProperties);
this.dbSystem = dbSystem;
this.fromFile = fromFile;
this.fromDatabase = fromDatabase;
this.processing = processing;
this.addresses = addresses;
this.logger = logger;
}
@Override
public void loadServerInfo() throws EnableException {
public void loadServerInfo() {
checkIfDefaultIP();
try {
Database database = dbSystem.getDatabase();
Optional<Server> proxyInfo = database.query(ServerQueries.fetchProxyServerInformation());
if (proxyInfo.isPresent()) {
server = proxyInfo.get();
updateServerInfo();
} else {
server = registerVelocityInfo(database);
}
} catch (DBOpException | ExecutionException e) {
throw new EnableException("Failed to read Server information from Database.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
this.server = fromFile.load(null).orElseGet(() -> fromDatabase.load(null)
.orElseGet(this::registerServer));
processing.submitNonCritical(this::updateStorage);
}
private void updateServerInfo() {
addresses.getAccessAddress().ifPresent(this::saveAddress);
private void updateStorage() {
String address = addresses.getAccessAddress().orElseGet(addresses::getFallbackLocalhostAddress);
server.setWebAddress(address);
fromDatabase.save(server);
fromFile.save(server);
}
private void saveAddress(String accessAddress) {
if (!accessAddress.equals(server.getWebAddress())) {
server.setWebAddress(accessAddress);
dbSystem.getDatabase().executeTransaction(new StoreServerInformationTransaction(server));
}
}
private void checkIfDefaultIP() throws EnableException {
/**
* @throws EnableException
*/
private void checkIfDefaultIP() {
String ip = serverProperties.getIp();
if ("0.0.0.0".equals(ip)) {
logger.error("IP setting still 0.0.0.0 - Configure Alternative_IP/IP that connects to the Proxy server.");
@ -97,19 +90,24 @@ public class VelocityServerInfo extends ServerInfo {
}
}
private Server registerVelocityInfo(Database db) throws EnableException, ExecutionException, InterruptedException {
private Server registerServer() {
Server proxy = createServerObject();
fromDatabase.save(proxy);
Server stored = fromDatabase.load(null)
.orElseThrow(() -> new EnableException("Velocity registration failed (DB)"));
fromFile.save(stored);
return stored;
}
/**
* @throws EnableException
*/
private Server createServerObject() {
UUID serverUUID = generateNewUUID();
String accessAddress = addresses.getAccessAddress().orElseThrow(() -> new EnableException("Velocity can not have '0.0.0.0' or '' as an address. Set up 'Server.IP' setting."));
// TODO Rework to allow Velocity as name.
Server proxy = new Server(-1, serverUUID, "BungeeCord", accessAddress, serverProperties.getMaxPlayers());
db.executeTransaction(new StoreServerInformationTransaction(proxy))
.get();
Optional<Server> proxyInfo = db.query(ServerQueries.fetchProxyServerInformation());
if (proxyInfo.isPresent()) {
return proxyInfo.get();
}
throw new EnableException("Velocity registration failed (DB)");
// TODO Rework to allow Velocity as a name
return new Server(-1, serverUUID, "BungeeCord", accessAddress);
}
}