Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,7 @@ private UUID parseUUIDFromString(String uuidAsString) {
public void processQueue() {
while (getVoteCacheHandler().getTimeChangeQueue().size() > 0) {
VoteTimeQueue vote = getVoteCacheHandler().getTimeChangeQueue().remove();
vote(vote.getName(), vote.getService(), true, false, vote.getTime(), null, null);
vote(vote.getName(), vote.getService(), true, false, vote.getTime(), null, null, vote.getVoteId());
}
}

Expand Down Expand Up @@ -1597,7 +1597,19 @@ public boolean checkVoteDelay(String uuid, String service, ArrayList<Column> dat

public synchronized void vote(String player, String service, boolean realVote, boolean timeQueue, long queueTime,
VoteTotalsSnapshot text, String uuid) {
vote(player, service, realVote, timeQueue, queueTime, text, uuid, null);
}

private synchronized void vote(String player, String service, boolean realVote, boolean timeQueue, long queueTime,
VoteTotalsSnapshot text, String uuid, UUID existingVoteId) {
try {
UUID voteId = existingVoteId;
if (voteId == null && text != null) {
voteId = text.getVoteUUID();
}
if (voteId == null) {
voteId = UUID.randomUUID();
}
if (player == null || player.isEmpty()) {
log("No name from vote on " + service);
return;
Expand All @@ -1608,7 +1620,7 @@ public synchronized void vote(String player, String service, boolean realVote, b
if (getGlobalDataHandler().isTimeChangedHappened()) {
getGlobalDataHandler().checkForFinishedTimeChanges();
if (timeQueue && getGlobalDataHandler().isTimeChangedHappened()) {
getVoteCacheHandler().getTimeChangeQueue().add(new VoteTimeQueue(player, service,
getVoteCacheHandler().getTimeChangeQueue().add(new VoteTimeQueue(voteId, player, service,
LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()));
log("Caching vote from " + player + "/" + service
+ " because time change is happening right now");
Expand Down Expand Up @@ -1684,8 +1696,6 @@ public synchronized void vote(String player, String service, boolean realVote, b
final boolean playerOnline = isPlayerOnline(player);
final String playerServer = playerOnline ? getCurrentPlayerServer(player) : null;

final UUID voteId = UUID.randomUUID();

addVoteParty();

// Totals processing (primary server OR no multiproxy)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public void addTimedVote(int num, VoteTimeQueue voteTimedQueue) {
setString(path + ".Name", voteTimedQueue.getName());
setString(path + ".Service", voteTimedQueue.getService());
setLong(path + ".Time", voteTimedQueue.getTime());
setString(path + ".VoteId", voteTimedQueue.getVoteId() == null ? null : voteTimedQueue.getVoteId().toString());
}

public void addVote(String server, int num, OfflineBungeeVote voteData) {
Expand All @@ -50,7 +51,7 @@ public void addVote(String server, int num, OfflineBungeeVote voteData) {
setLong(path + ".Time", voteData.getTime());
setBoolean(path + ".Real", voteData.isRealVote());
setString(path + ".Text", voteData.getText());
setString(path + ".VoteID", voteData.getVoteId() != null ? voteData.getVoteId().toString() : null);
setString(path + ".VoteId", voteData.getVoteId() != null ? voteData.getVoteId().toString() : null);
}

public void addVoteOnline(String player, int num, OfflineBungeeVote voteData) {
Expand All @@ -61,7 +62,7 @@ public void addVoteOnline(String player, int num, OfflineBungeeVote voteData) {
setLong(path + ".Time", voteData.getTime());
setBoolean(path + ".Real", voteData.isRealVote());
setString(path + ".Text", voteData.getText());
setString(path + ".VoteID", voteData.getVoteId() != null ? voteData.getVoteId().toString() : null);
setString(path + ".VoteId", voteData.getVoteId() != null ? voteData.getVoteId().toString() : null);
}

public void clearData() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.bencodez.simpleapi.sql.mysql.AbstractSqlTable;
import com.bencodez.simpleapi.sql.mysql.DbType;
Expand All @@ -30,7 +31,8 @@ public String buildCreateTableSql(DbType dbType) {
+ qi("id") + " BIGSERIAL PRIMARY KEY, "
+ qi("playerName") + " VARCHAR(100), "
+ qi("service") + " VARCHAR(100), "
+ qi("time") + " BIGINT"
+ qi("time") + " BIGINT, "
+ qi("voteId") + " VARCHAR(36)"
+ ");";
}

Expand All @@ -39,6 +41,7 @@ public String buildCreateTableSql(DbType dbType) {
+ qi("playerName") + " VARCHAR(100),"
+ qi("service") + " VARCHAR(100),"
+ qi("time") + " BIGINT,"
+ qi("voteId") + " VARCHAR(36),"
+ "INDEX idx_time (" + qi("time") + ")"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
}
Expand All @@ -62,6 +65,7 @@ public ProxyTimedVoteCacheTable(MySQL existingMysql, String tablePrefix, boolean
super((tablePrefix != null ? tablePrefix : "") + "votingplugin_timedvotecache",
existingMysql,
debug);
ensureVoteIdColumn();
ensureIndexes();
}

Expand All @@ -72,9 +76,28 @@ public ProxyTimedVoteCacheTable(MySQL existingMysql, String tablePrefix, boolean
*/
public ProxyTimedVoteCacheTable(MysqlConfig config, boolean debug) {
super("votingplugin_timedvotecache", config, debug);
ensureVoteIdColumn();
ensureIndexes();
}

private void ensureVoteIdColumn() {
String probeSql = "SELECT " + qi("voteId") + " FROM " + qi(getTableName()) + " WHERE 1 = 0;";
try (Connection conn = mysql.getConnectionManager().getConnection();
PreparedStatement ps = conn.prepareStatement(probeSql)) {
ps.executeQuery();
return;
} catch (SQLException ignored) {
// Column does not exist yet.
}

try {
new Query(mysql, "ALTER TABLE " + qi(getTableName()) + " ADD COLUMN " + qi("voteId")
+ " VARCHAR(36);").executeUpdate();
} catch (SQLException e) {
debug(e);
}
}

private void ensureIndexes() {
if (getDbType() == DbType.POSTGRESQL) {
try {
Expand All @@ -89,18 +112,20 @@ private void ensureIndexes() {
// --- INSERT ---
/**
* Inserts a timed vote.
* @param voteId unique vote identifier
* @param playerName the player name
* @param service the voting service
* @param time the vote time
*/
public void insertTimedVote(String playerName, String service, long time) {
public void insertTimedVote(UUID voteId, String playerName, String service, long time) {
String sql = "INSERT INTO " + qi(getTableName()) + " (" + qi("playerName") + ", " + qi("service") + ", "
+ qi("time") + ") VALUES (?, ?, ?);";
+ qi("time") + ", " + qi("voteId") + ") VALUES (?, ?, ?, ?);";
try (Connection conn = mysql.getConnectionManager().getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, playerName);
ps.setString(2, service);
ps.setLong(3, time);
ps.setString(4, voteId == null ? null : voteId.toString());
ps.executeUpdate();
} catch (SQLException e) {
debug(e);
Expand Down Expand Up @@ -189,7 +214,8 @@ private List<TimedVoteRow> selectVotes(String sql, Object[] params) {
rs.getInt("id"),
rs.getString("playerName"),
rs.getString("service"),
rs.getLong("time")
rs.getLong("time"),
parseUuid(rs.getString("voteId"))
));
}
}
Expand All @@ -199,6 +225,17 @@ private List<TimedVoteRow> selectVotes(String sql, Object[] params) {
return list;
}

private UUID parseUuid(String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
return UUID.fromString(value);
} catch (IllegalArgumentException ignored) {
return null;
}
}

/**
* Represents a row in the timed vote cache table.
*/
Expand All @@ -207,19 +244,22 @@ public static class TimedVoteRow {
private final String playerName;
private final String service;
private final long time;
private final UUID voteId;

/**
* Constructor for TimedVoteRow.
* @param id the row ID
* @param playerName the player name
* @param service the voting service
* @param time the vote time
* @param voteId unique vote identifier
*/
public TimedVoteRow(int id, String playerName, String service, long time) {
public TimedVoteRow(int id, String playerName, String service, long time, UUID voteId) {
this.id = id;
this.playerName = playerName;
this.service = service;
this.time = time;
this.voteId = voteId;
}

/**
Expand Down Expand Up @@ -253,5 +293,14 @@ public String getService() {
public long getTime() {
return time;
}

/**
* Gets the vote identifier.
*
* @return vote identifier or null
*/
public UUID getVoteId() {
return voteId;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

Expand Down Expand Up @@ -88,6 +89,11 @@ public int getProxyCachedTotal(String uuid) {
* @param vote the vote to add
*/
public void addServerVote(String server, OfflineBungeeVote vote) {
if (containsServerVote(server, vote.getVoteId())) {
debug1("Not caching duplicate vote " + vote.getVoteId() + " for server " + server);
return;
}

cachedVotes.putIfAbsent(server, new ArrayList<>());
cachedVotes.get(server).add(vote);

Expand Down Expand Up @@ -160,6 +166,11 @@ public ArrayList<OfflineBungeeVote> getOnlineVotes(String uuid) {
* @param vote the vote to add
*/
public void addOnlineVote(String uuid, OfflineBungeeVote vote) {
if (containsOnlineVote(uuid, vote.getVoteId())) {
debug1("Not caching duplicate online vote " + vote.getVoteId() + " for " + uuid);
return;
}

cachedOnlineVotes.putIfAbsent(uuid, new ArrayList<>());
cachedOnlineVotes.get(uuid).add(vote);

Expand Down Expand Up @@ -226,6 +237,82 @@ public void checkVoteCacheTime(int voteCacheTime) {
}
}

/**
* Checks whether a vote is already cached for a server.
*
* @param server target server
* @param voteId unique vote identifier
* @return true if the vote is already cached for the server
*/
private boolean containsServerVote(String server, UUID voteId) {
if (voteId == null) {
return false;
}
for (OfflineBungeeVote vote : getVotes(server)) {
if (voteId.equals(vote.getVoteId())) {
return true;
}
}
return false;
}

/**
* Checks whether a vote is already cached for an online player.
*
* @param uuid player UUID
* @param voteId unique vote identifier
* @return true if the vote is already cached for the player
*/
private boolean containsOnlineVote(String uuid, UUID voteId) {
if (voteId == null) {
return false;
}
for (OfflineBungeeVote vote : getOnlineVotes(uuid)) {
if (voteId.equals(vote.getVoteId())) {
return true;
}
}
return false;
}

/**
* Reads a vote identifier using the current key and the legacy key.
*
* @param data cached vote data
* @return stored vote identifier or an empty string
*/
private String readVoteId(DataNode data) {
if (data.has("VoteId")) {
return data.get("VoteId").asString();
}
if (data.has("VoteID")) {
return data.get("VoteID").asString();
}
return "";
}

/**
* Reads an optional UUID from cached data.
*
* @param data cached data
* @param key value key
* @return parsed UUID or null
*/
private UUID readUuid(DataNode data, String key) {
if (!data.has(key)) {
return null;
}
String value = data.get(key).asString();
if (value == null || value.isEmpty()) {
return null;
}
try {
return UUID.fromString(value);
} catch (IllegalArgumentException ignored) {
return null;
}
}

/**
* Saves the vote cache to storage.
*/
Expand All @@ -234,7 +321,7 @@ public void saveVoteCache() {

if (!getTimeChangeQueue().isEmpty()) {
for (VoteTimeQueue vote : getTimeChangeQueue()) {
timedVoteCacheTable.insertTimedVote(vote.getName(), vote.getService(), vote.getTime());
timedVoteCacheTable.insertTimedVote(vote.getVoteId(), vote.getName(), vote.getService(), vote.getTime());
}
}
} else {
Expand Down Expand Up @@ -286,8 +373,8 @@ public void load() {
// Load timed votes from MySQL
ArrayList<VoteTimeQueue> timedVotes = new ArrayList<>();
timedVoteCacheTable.getAllVotes().forEach(timedVoteRow -> {
VoteTimeQueue voteTimeQueue = new VoteTimeQueue(timedVoteRow.getPlayerName(), timedVoteRow.getService(),
timedVoteRow.getTime());
VoteTimeQueue voteTimeQueue = new VoteTimeQueue(timedVoteRow.getVoteId(), timedVoteRow.getPlayerName(),
timedVoteRow.getService(), timedVoteRow.getTime());
timedVotes.add(voteTimeQueue);
});
timeChangeQueue.addAll(timedVotes);
Expand All @@ -303,8 +390,9 @@ public void load() {
String name = data.has("Name") ? data.get("Name").asString() : "";
String service = data.has("Service") ? data.get("Service").asString() : "";
long time = data.has("Time") ? data.get("Time").asLong() : 0L;
UUID voteId = readUuid(data, "VoteId");

getTimeChangeQueue().add(new VoteTimeQueue(name, service, time));
getTimeChangeQueue().add(new VoteTimeQueue(voteId, name, service, time));
}
}

Expand All @@ -326,7 +414,7 @@ public void load() {
long time = data.has("Time") ? data.get("Time").asLong() : 0L;
boolean real = data.has("Real") && data.get("Real").asBoolean();
String text = data.has("Text") ? data.get("Text").asString() : "";
String voteId = data.has("VoteId") ? data.get("VoteId").asString() : "";
String voteId = readVoteId(data);

votes.add(new OfflineBungeeVote(voteId, name, uuid, service, time, real, text));
}
Expand All @@ -351,7 +439,7 @@ public void load() {
long time = data.has("Time") ? data.get("Time").asLong() : 0L;
boolean real = data.has("Real") && data.get("Real").asBoolean();
String text = data.has("Text") ? data.get("Text").asString() : "";
String voteId = data.has("VoteId") ? data.get("VoteId").asString() : "";
String voteId = readVoteId(data);

votes.add(new OfflineBungeeVote(voteId, name, uuid, service, time, real, text));
}
Expand Down
Loading
Loading