Added version tracking to client and server and updated registry.
This commit is contained in:
parent
c6d54d3f38
commit
ec86b8cf69
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>ace-of-shades</artifactId>
|
||||
<groupId>nl.andrewlalis</groupId>
|
||||
<version>5.0</version>
|
||||
<version>0.5.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.awt.*;
|
|||
public record PublicServerInfo(
|
||||
String name,
|
||||
String address,
|
||||
String version,
|
||||
String description,
|
||||
String location,
|
||||
Image icon,
|
||||
|
@ -14,35 +15,53 @@ public record PublicServerInfo(
|
|||
) {
|
||||
public static ListCellRenderer<PublicServerInfo> cellRenderer() {
|
||||
return (list, value, index, isSelected, cellHasFocus) -> {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createTitledBorder(value.name()));
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
var c = new GridBagConstraints();
|
||||
|
||||
panel.add(new JLabel("Address: " + value.address()), BorderLayout.NORTH);
|
||||
|
||||
JPanel content = new JPanel();
|
||||
c.anchor = GridBagConstraints.CENTER;
|
||||
c.insets = new Insets(1, 1, 1, 1);
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
c.gridheight = 4;
|
||||
c.weightx = 0.25;
|
||||
c.fill = GridBagConstraints.BOTH;
|
||||
if (value.icon() != null) {
|
||||
JLabel iconLabel = new JLabel(new ImageIcon(value.icon()));
|
||||
content.add(iconLabel);
|
||||
panel.add(iconLabel, c);
|
||||
}
|
||||
|
||||
c.anchor = GridBagConstraints.LINE_START;
|
||||
c.gridx = 1;
|
||||
c.gridy = 0;
|
||||
c.gridheight = 1;
|
||||
c.weightx = 0.75;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
var nameLabel = new JLabel(value.name() + " [" + value.version() + "]");
|
||||
nameLabel.setFont(nameLabel.getFont().deriveFont(Font.BOLD));
|
||||
panel.add(nameLabel, c);
|
||||
c.gridy++;
|
||||
var addressLabel = new JLabel(value.address());
|
||||
addressLabel.setFont(new Font("monospaced", Font.PLAIN, 12));
|
||||
panel.add(addressLabel, c);
|
||||
c.gridy++;
|
||||
JTextArea descriptionArea = new JTextArea(value.description());
|
||||
descriptionArea.setEditable(false);
|
||||
descriptionArea.setWrapStyleWord(true);
|
||||
descriptionArea.setLineWrap(true);
|
||||
content.add(descriptionArea);
|
||||
panel.add(content, BorderLayout.CENTER);
|
||||
|
||||
JPanel bottomPanel = new JPanel();
|
||||
bottomPanel.add(new JLabel(String.format("Current players: %d / %d", value.currentPlayers(), value.maxPlayers())));
|
||||
|
||||
panel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
panel.add(descriptionArea, c);
|
||||
c.gridy++;
|
||||
panel.add(new JLabel(String.format("%d / %d Players", value.currentPlayers(), value.maxPlayers())), c);
|
||||
|
||||
if (isSelected) {
|
||||
panel.setBackground(list.getSelectionBackground());
|
||||
panel.setForeground(list.getSelectionForeground());
|
||||
descriptionArea.setForeground(list.getSelectionForeground());
|
||||
descriptionArea.setBackground(list.getSelectionBackground());
|
||||
} else {
|
||||
panel.setBackground(list.getBackground());
|
||||
panel.setForeground(list.getForeground());
|
||||
descriptionArea.setForeground(list.getForeground());
|
||||
descriptionArea.setBackground(list.getBackground());
|
||||
}
|
||||
|
||||
return panel;
|
||||
|
|
|
@ -149,6 +149,7 @@ public class PublicServerListModel extends AbstractListModel<PublicServerInfo> {
|
|||
PublicServerInfo info = new PublicServerInfo(
|
||||
node.get("name").asText(),
|
||||
node.get("address").asText(),
|
||||
node.get("version").asText(),
|
||||
node.get("description").asText(),
|
||||
node.get("location").asText(),
|
||||
icon,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>ace-of-shades</artifactId>
|
||||
<groupId>nl.andrewlalis</groupId>
|
||||
<version>5.0</version>
|
||||
<version>0.5.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -7,7 +7,7 @@
|
|||
<groupId>nl.andrewlalis</groupId>
|
||||
<artifactId>ace-of-shades</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>5.0</version>
|
||||
<version>0.5.0</version>
|
||||
<modules>
|
||||
<module>server</module>
|
||||
<module>client</module>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>ace-of-shades</artifactId>
|
||||
<groupId>nl.andrewlalis</groupId>
|
||||
<version>5.0</version>
|
||||
<version>0.5.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package nl.andrewlalis.aos_server_registry.servlet;
|
||||
|
||||
public class ResponseStatusException extends Exception {
|
||||
private final int statusCode;
|
||||
private final String message;
|
||||
|
||||
public ResponseStatusException(int statusCode, String message) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public class ServerInfoServlet extends HttpServlet {
|
|||
));
|
||||
String orderDir = Requests.getStringParam(req, "dir", "ASC", s -> s.equalsIgnoreCase("ASC") || s.equalsIgnoreCase("DESC"));
|
||||
try {
|
||||
var results = this.getData(size, page, searchQuery, order, orderDir);
|
||||
var results = this.getData(size, page, searchQuery, null, order, orderDir);
|
||||
Responses.ok(resp, new Page<>(results, page, size, order, orderDir));
|
||||
} catch (SQLException t) {
|
||||
t.printStackTrace();
|
||||
|
@ -54,6 +54,8 @@ public class ServerInfoServlet extends HttpServlet {
|
|||
try {
|
||||
this.saveNewServer(info);
|
||||
Responses.ok(resp, Map.of("message", "Server icon saved."));
|
||||
} catch (ResponseStatusException e) {
|
||||
Responses.json(resp, e.getStatusCode(), Map.of("message", e.getMessage()));
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Responses.internalServerError(resp, "Database error.");
|
||||
|
@ -66,11 +68,11 @@ public class ServerInfoServlet extends HttpServlet {
|
|||
this.updateServerStatus(status, resp);
|
||||
}
|
||||
|
||||
private List<ServerInfoResponse> getData(int size, int page, String searchQuery, String order, String orderDir) throws SQLException, IOException {
|
||||
private List<ServerInfoResponse> getData(int size, int page, String searchQuery, String versionQuery, String order, String orderDir) throws SQLException, IOException {
|
||||
final List<ServerInfoResponse> results = new ArrayList<>(20);
|
||||
var con = DataManager.getInstance().getConnection();
|
||||
String selectQuery = """
|
||||
SELECT name, address, updated_at, description, location, icon, max_players, current_players
|
||||
SELECT name, address, version, updated_at, description, location, icon, max_players, current_players
|
||||
FROM servers
|
||||
//CONDITIONS
|
||||
ORDER BY name
|
||||
|
@ -78,20 +80,30 @@ public class ServerInfoServlet extends HttpServlet {
|
|||
OFFSET ?
|
||||
""";
|
||||
selectQuery = selectQuery.replace("ORDER BY name", "ORDER BY " + order + " " + orderDir);
|
||||
List<String> conditions = new ArrayList<>();
|
||||
List<Object> conditionParams = new ArrayList<>();
|
||||
if (searchQuery != null && !searchQuery.isBlank()) {
|
||||
selectQuery = selectQuery.replace("//CONDITIONS", "WHERE UPPER(name) LIKE ?");
|
||||
conditions.add("UPPER(name) LIKE ?");
|
||||
conditionParams.add("%" + searchQuery.toUpperCase() + "%");
|
||||
}
|
||||
if (versionQuery != null && !versionQuery.isBlank()) {
|
||||
conditions.add("version = ?");
|
||||
conditionParams.add(versionQuery);
|
||||
}
|
||||
if (!conditions.isEmpty()) {
|
||||
selectQuery = selectQuery.replace("//CONDITIONS", "WHERE " + String.join(" AND ", conditions));
|
||||
}
|
||||
PreparedStatement stmt = con.prepareStatement(selectQuery);
|
||||
int index = 1;
|
||||
if (searchQuery != null && !searchQuery.isBlank()) {
|
||||
stmt.setString(index++, "%" + searchQuery.toUpperCase() + "%");
|
||||
for (var param : conditionParams) {
|
||||
stmt.setObject(index++, param);
|
||||
}
|
||||
stmt.setInt(index++, size);
|
||||
stmt.setInt(index, page * size);
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
// Attempt to load the server's icon, if it is not null.
|
||||
InputStream iconInputStream = rs.getBinaryStream(6);
|
||||
InputStream iconInputStream = rs.getBinaryStream(7);
|
||||
String encodedIconImage = null;
|
||||
if (iconInputStream != null) {
|
||||
encodedIconImage = Base64.getUrlEncoder().encodeToString(iconInputStream.readAllBytes());
|
||||
|
@ -99,19 +111,20 @@ public class ServerInfoServlet extends HttpServlet {
|
|||
results.add(new ServerInfoResponse(
|
||||
rs.getString(1),
|
||||
rs.getString(2),
|
||||
rs.getTimestamp(3).toInstant().atOffset(ZoneOffset.UTC).toString(),
|
||||
rs.getString(4),
|
||||
rs.getString(3),
|
||||
rs.getTimestamp(4).toInstant().atOffset(ZoneOffset.UTC).toString(),
|
||||
rs.getString(5),
|
||||
rs.getString(6),
|
||||
encodedIconImage,
|
||||
rs.getInt(7),
|
||||
rs.getInt(8)
|
||||
rs.getInt(8),
|
||||
rs.getInt(9)
|
||||
));
|
||||
}
|
||||
stmt.close();
|
||||
return results;
|
||||
}
|
||||
|
||||
private void saveNewServer(ServerInfoUpdate info) throws SQLException {
|
||||
private void saveNewServer(ServerInfoUpdate info) throws SQLException, ResponseStatusException {
|
||||
var con = DataManager.getInstance().getConnection();
|
||||
PreparedStatement stmt = con.prepareStatement("SELECT name, address FROM servers WHERE name = ? AND address = ?");
|
||||
stmt.setString(1, info.name());
|
||||
|
@ -119,42 +132,45 @@ public class ServerInfoServlet extends HttpServlet {
|
|||
ResultSet rs = stmt.executeQuery();
|
||||
boolean exists = rs.next();
|
||||
stmt.close();
|
||||
String version = info.version() == null ? "Unknown" : info.version();
|
||||
if (!exists) {
|
||||
PreparedStatement createStmt = con.prepareStatement("""
|
||||
INSERT INTO servers (name, address, description, location, icon, max_players, current_players)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||
INSERT INTO servers (name, address, version, description, location, icon, max_players, current_players)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
||||
""");
|
||||
createStmt.setString(1, info.name());
|
||||
createStmt.setString(2, info.address());
|
||||
createStmt.setString(3, info.description());
|
||||
createStmt.setString(4, info.location());
|
||||
createStmt.setString(3, version);
|
||||
createStmt.setString(4, info.description());
|
||||
createStmt.setString(5, info.location());
|
||||
InputStream inputStream = null;
|
||||
if (info.icon() != null) {
|
||||
inputStream = new ByteArrayInputStream(Base64.getUrlDecoder().decode(info.icon()));
|
||||
}
|
||||
createStmt.setBinaryStream(5, inputStream);
|
||||
createStmt.setInt(6, info.maxPlayers());
|
||||
createStmt.setInt(7, info.currentPlayers());
|
||||
createStmt.setBinaryStream(6, inputStream);
|
||||
createStmt.setInt(7, info.maxPlayers());
|
||||
createStmt.setInt(8, info.currentPlayers());
|
||||
int rowCount = createStmt.executeUpdate();
|
||||
createStmt.close();
|
||||
if (rowCount != 1) throw new SQLException("Could not insert new server.");
|
||||
log.info("Registered new server " + info.name() + " @ " + info.address());
|
||||
log.info("Registered new server " + info.name() + " @ " + info.address() + " running version " + version + ".");
|
||||
} else {
|
||||
PreparedStatement updateStmt = con.prepareStatement("""
|
||||
UPDATE servers SET description = ?, location = ?, icon = ?, max_players = ?, current_players = ?
|
||||
UPDATE servers SET version = ?, description = ?, location = ?, icon = ?, max_players = ?, current_players = ?
|
||||
WHERE name = ? AND address = ?;
|
||||
""");
|
||||
updateStmt.setString(1, info.description());
|
||||
updateStmt.setString(2, info.location());
|
||||
updateStmt.setString(1, version);
|
||||
updateStmt.setString(2, info.description());
|
||||
updateStmt.setString(3, info.location());
|
||||
InputStream inputStream = null;
|
||||
if (info.icon() != null) {
|
||||
inputStream = new ByteArrayInputStream(Base64.getUrlDecoder().decode(info.icon()));
|
||||
}
|
||||
updateStmt.setBinaryStream(3, inputStream);
|
||||
updateStmt.setInt(4, info.maxPlayers());
|
||||
updateStmt.setInt(5, info.currentPlayers());
|
||||
updateStmt.setString(6, info.name());
|
||||
updateStmt.setString(7, info.address());
|
||||
updateStmt.setBinaryStream(4, inputStream);
|
||||
updateStmt.setInt(5, info.maxPlayers());
|
||||
updateStmt.setInt(6, info.currentPlayers());
|
||||
updateStmt.setString(7, info.name());
|
||||
updateStmt.setString(8, info.address());
|
||||
int rowCount = updateStmt.executeUpdate();
|
||||
updateStmt.close();
|
||||
if (rowCount != 1) throw new SQLException("Could not update server.");
|
||||
|
|
|
@ -3,6 +3,7 @@ package nl.andrewlalis.aos_server_registry.servlet.dto;
|
|||
public record ServerInfoResponse(
|
||||
String name,
|
||||
String address,
|
||||
String version,
|
||||
String updatedAt,
|
||||
String description,
|
||||
String location,
|
||||
|
|
|
@ -3,6 +3,7 @@ package nl.andrewlalis.aos_server_registry.servlet.dto;
|
|||
public record ServerInfoUpdate (
|
||||
String name,
|
||||
String address,
|
||||
String version,
|
||||
String description,
|
||||
String location,
|
||||
String icon,
|
||||
|
|
|
@ -21,6 +21,12 @@ public class Responses {
|
|||
mapper.writeValue(resp.getOutputStream(), body);
|
||||
}
|
||||
|
||||
public static void json(HttpServletResponse resp, int status, Object body) throws IOException {
|
||||
resp.setStatus(status);
|
||||
resp.setContentType("application/json");
|
||||
mapper.writeValue(resp.getOutputStream(), body);
|
||||
}
|
||||
|
||||
public static void badRequest(HttpServletResponse resp, String msg) throws IOException {
|
||||
respond(resp, HttpServletResponse.SC_BAD_REQUEST, msg);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ SET MODE MySQL;
|
|||
CREATE TABLE servers (
|
||||
name VARCHAR(64) NOT NULL,
|
||||
address VARCHAR(255) NOT NULL,
|
||||
version VARCHAR(64) NOT NULL DEFAULT 'Unknown Version',
|
||||
created_at TIMESTAMP(0) WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP(0),
|
||||
updated_at TIMESTAMP(0) WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP(0),
|
||||
description VARCHAR(1024),
|
||||
location VARCHAR(64),
|
||||
location VARCHAR(128),
|
||||
icon BLOB NULL DEFAULT NULL,
|
||||
|
||||
max_players INTEGER NOT NULL,
|
||||
|
@ -17,3 +18,4 @@ CREATE TABLE servers (
|
|||
);
|
||||
|
||||
CREATE INDEX server_name_idx ON servers(name);
|
||||
CREATE INDEX server_version_idx ON servers(version);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>ace-of-shades</artifactId>
|
||||
<groupId>nl.andrewlalis</groupId>
|
||||
<version>5.0</version>
|
||||
<version>0.5.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ public class RegistryManager {
|
|||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("name", this.server.getSettings().getRegistrySettings().getName());
|
||||
data.put("address", this.server.getSettings().getRegistrySettings().getAddress());
|
||||
data.put("version", Server.VERSION);
|
||||
data.put("description", this.server.getSettings().getRegistrySettings().getDescription());
|
||||
data.put("location", this.server.getSettings().getRegistrySettings().getLocation());
|
||||
data.put("icon", this.getIconData());
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class Server {
|
||||
public static final String VERSION = "0.5.0";
|
||||
private final ServerSettings settings;
|
||||
|
||||
private final List<ClientHandler> clientHandlers;
|
||||
|
@ -263,6 +264,7 @@ public class Server {
|
|||
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("Starting Ace of Shades Server version " + VERSION + ".");
|
||||
Server server = new Server(SettingsLoader.load());
|
||||
server.run();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public class ServerCli extends Thread {
|
|||
public void run() {
|
||||
this.running = true;
|
||||
String input;
|
||||
System.out.println("Server command-line-interface initialized. Type \"help\" for more information.");
|
||||
System.out.println("AOS-Server command-line-interface initialized. Type \"help\" for more information.");
|
||||
while (this.running) {
|
||||
try {
|
||||
input = reader.readLine();
|
||||
|
|
Loading…
Reference in New Issue