Skip to content

Commit eff9e8e

Browse files
committed
Add Floodgate variable to StoredProfile/Database
1 parent 08a9f7e commit eff9e8e

File tree

4 files changed

+156
-21
lines changed

4 files changed

+156
-21
lines changed

core/src/main/java/com/github/games647/fastlogin/core/StoredProfile.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.github.games647.fastlogin.core;
2727

2828
import com.github.games647.craftapi.model.Profile;
29+
import com.github.games647.fastlogin.core.shared.FloodgateState;
2930

3031
import java.time.Instant;
3132
import java.util.Objects;
@@ -39,20 +40,28 @@ public class StoredProfile extends Profile {
3940
private final ReentrantLock saveLock = new ReentrantLock();
4041

4142
private boolean premium;
43+
private FloodgateState floodgate;
4244
private String lastIp;
4345
private Instant lastLogin;
4446

45-
public StoredProfile(long rowId, UUID uuid, String playerName, boolean premium, String lastIp, Instant lastLogin) {
47+
public StoredProfile(long rowId, UUID uuid, String playerName, boolean premium, FloodgateState floodgate,
48+
String lastIp, Instant lastLogin) {
4649
super(uuid, playerName);
4750

4851
this.rowId = rowId;
4952
this.premium = premium;
53+
this.floodgate = floodgate;
5054
this.lastIp = lastIp;
5155
this.lastLogin = lastLogin;
5256
}
5357

58+
public StoredProfile(UUID uuid, String playerName, boolean premium, FloodgateState isFloodgate, String lastIp) {
59+
this(-1, uuid, playerName, premium, isFloodgate, lastIp, Instant.now());
60+
}
61+
62+
@Deprecated
5463
public StoredProfile(UUID uuid, String playerName, boolean premium, String lastIp) {
55-
this(-1, uuid, playerName, premium, lastIp, Instant.now());
64+
this(-1, uuid, playerName, premium, FloodgateState.FALSE, lastIp, Instant.now());
5665
}
5766

5867
public ReentrantLock getSaveLock() {
@@ -96,6 +105,18 @@ public synchronized void setPremium(boolean premium) {
96105
this.premium = premium;
97106
}
98107

108+
public synchronized FloodgateState getFloodgate() {
109+
return floodgate;
110+
}
111+
112+
public synchronized boolean isFloodgateMigrated() {
113+
return floodgate != FloodgateState.NOT_MIGRATED;
114+
}
115+
116+
public synchronized void setFloodgate(FloodgateState floodgate) {
117+
this.floodgate = floodgate;
118+
}
119+
99120
public synchronized String getLastIp() {
100121
return lastIp;
101122
}
@@ -128,7 +149,7 @@ public synchronized boolean equals(Object o) {
128149
}
129150

130151
return rowId == that.rowId && premium == that.premium
131-
&& Objects.equals(lastIp, that.lastIp) && lastLogin.equals(that.lastLogin);
152+
&& Objects.equals(lastIp, that.lastIp) && lastLogin.equals(that.lastLogin);
132153
}
133154

134155
@Override
@@ -141,6 +162,7 @@ public synchronized String toString() {
141162
return this.getClass().getSimpleName() + '{'
142163
+ "rowId=" + rowId
143164
+ ", premium=" + premium
165+
+ ", floodgate=" + floodgate
144166
+ ", lastIp='" + lastIp + '\''
145167
+ ", lastLogin=" + lastLogin
146168
+ "} " + super.toString();
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2015-2022 games647 and contributors
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in all
16+
* copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*/
26+
package com.github.games647.fastlogin.core.shared;
27+
28+
public enum FloodgateState {
29+
FALSE(0),
30+
TRUE(1),
31+
LINKED(2),
32+
NOT_MIGRATED(3);
33+
34+
private int value;
35+
36+
FloodgateState(int value) {
37+
this.value = value;
38+
}
39+
40+
public int getValue() {
41+
return value;
42+
}
43+
44+
/**
45+
* Convert a number to FloodgateState
46+
* <ol start="0">
47+
* <li>False</li>
48+
* <li>True</li>
49+
* <li>Linked</li>
50+
* <li>Not Migrated</li>
51+
* </ol>
52+
* @param num the number, most likely loaded from the database
53+
* @return FloodgateStatus on success, null otherwise
54+
*/
55+
public static FloodgateState fromInt(int num) {
56+
// using Enum.values()[i] is expensive as per https://stackoverflow.com/a/8762387/9767089
57+
switch (num) {
58+
case 0:
59+
return FloodgateState.FALSE;
60+
case 1:
61+
return FloodgateState.TRUE;
62+
case 2:
63+
return FloodgateState.LINKED;
64+
case 3:
65+
return FloodgateState.NOT_MIGRATED;
66+
default:
67+
return null;
68+
}
69+
}
70+
}

core/src/main/java/com/github/games647/fastlogin/core/storage/SQLStorage.java

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
import com.github.games647.craftapi.UUIDAdapter;
2929
import com.github.games647.fastlogin.core.StoredProfile;
3030
import com.github.games647.fastlogin.core.shared.FastLoginCore;
31+
import com.github.games647.fastlogin.core.shared.FloodgateState;
3132
import com.zaxxer.hikari.HikariConfig;
3233
import com.zaxxer.hikari.HikariDataSource;
3334

3435
import java.sql.Connection;
36+
import java.sql.DatabaseMetaData;
3537
import java.sql.PreparedStatement;
3638
import java.sql.ResultSet;
3739
import java.sql.SQLException;
@@ -51,13 +53,15 @@ public abstract class SQLStorage implements AuthStorage {
5153
+ "`UUID` CHAR(36), "
5254
+ "`Name` VARCHAR(16) NOT NULL, "
5355
+ "`Premium` BOOLEAN NOT NULL, "
54-
+ "`Floodgate` BOOLEAN NOT NULL, "
5556
+ "`LastIp` VARCHAR(255) NOT NULL, "
5657
+ "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
5758
//the premium shouldn't steal the cracked account by changing the name
5859
+ "UNIQUE (`Name`) "
5960
+ ')';
6061

62+
protected static final String ADD_FLOODGATE_COLUMN_STMT = "ALTER TABLE `" + PREMIUM_TABLE
63+
+ "` ADD COLUMN `Floodgate` INTEGER(3)";
64+
6165
protected static final String LOAD_BY_NAME = "SELECT * FROM `" + PREMIUM_TABLE
6266
+ "` WHERE `Name`=? LIMIT 1";
6367
protected static final String LOAD_BY_UUID = "SELECT * FROM `" + PREMIUM_TABLE
@@ -88,11 +92,23 @@ public void createTables() throws SQLException {
8892
// choose surrogate PK(ID), because UUID can be null for offline players
8993
// if UUID is always Premium UUID we would have to update offline player entries on insert
9094
// name cannot be PK, because it can be changed for premium players
91-
9295
//todo: add unique uuid index usage
9396
try (Connection con = dataSource.getConnection();
94-
Statement createStmt = con.createStatement()) {
95-
createStmt.executeUpdate(CREATE_TABLE_STMT);
97+
Statement stmt = con.createStatement()) {
98+
stmt.executeUpdate(getCreateTableStmt());
99+
100+
// add Floodgate column
101+
DatabaseMetaData md = con.getMetaData();
102+
if (isColumnMissing(md, "Floodgate")) {
103+
stmt.executeUpdate(ADD_FLOODGATE_COLUMN_STMT);
104+
}
105+
106+
}
107+
}
108+
109+
private boolean isColumnMissing(DatabaseMetaData metaData, String columnName) throws SQLException {
110+
try (ResultSet rs = metaData.getColumns(null, null, PREMIUM_TABLE, columnName)) {
111+
return !rs.next();
96112
}
97113
}
98114

@@ -104,7 +120,8 @@ public StoredProfile loadProfile(String name) {
104120
loadStmt.setString(1, name);
105121

106122
try (ResultSet resultSet = loadStmt.executeQuery()) {
107-
return parseResult(resultSet).orElseGet(() -> new StoredProfile(null, name, false, false, ""));
123+
return parseResult(resultSet).orElseGet(() -> new StoredProfile(null, name, false,
124+
FloodgateState.FALSE, ""));
108125
}
109126
} catch (SQLException sqlEx) {
110127
core.getPlugin().getLog().error("Failed to query profile: {}", name, sqlEx);
@@ -137,9 +154,19 @@ private Optional<StoredProfile> parseResult(ResultSet resultSet) throws SQLExcep
137154

138155
String name = resultSet.getString("Name");
139156
boolean premium = resultSet.getBoolean("Premium");
157+
int floodgateNum = resultSet.getInt("Floodgate");
158+
FloodgateState floodgate;
159+
160+
// if the player wasn't migrated to the new database format
161+
if (resultSet.wasNull()) {
162+
floodgate = FloodgateState.NOT_MIGRATED;
163+
} else {
164+
floodgate = FloodgateState.fromInt(floodgateNum);
165+
}
166+
140167
String lastIp = resultSet.getString("LastIp");
141168
Instant lastLogin = resultSet.getTimestamp("LastLogin").toInstant();
142-
return Optional.of(new StoredProfile(userId, uuid, name, premium, lastIp, lastLogin));
169+
return Optional.of(new StoredProfile(userId, uuid, name, premium, floodgate, lastIp, lastLogin));
143170
}
144171

145172
return Optional.empty();
@@ -157,9 +184,10 @@ public void save(StoredProfile playerProfile) {
157184
saveStmt.setString(1, uuid);
158185
saveStmt.setString(2, playerProfile.getName());
159186
saveStmt.setBoolean(3, playerProfile.isPremium());
160-
saveStmt.setString(4, playerProfile.getLastIp());
187+
saveStmt.setInt(4, playerProfile.getFloodgate().getValue());
188+
saveStmt.setString(5, playerProfile.getLastIp());
161189

162-
saveStmt.setLong(5, playerProfile.getRowId());
190+
saveStmt.setLong(6, playerProfile.getRowId());
163191
saveStmt.execute();
164192
}
165193
} else {
@@ -168,7 +196,9 @@ public void save(StoredProfile playerProfile) {
168196

169197
saveStmt.setString(2, playerProfile.getName());
170198
saveStmt.setBoolean(3, playerProfile.isPremium());
171-
saveStmt.setString(4, playerProfile.getLastIp());
199+
saveStmt.setBoolean(3, playerProfile.isPremium());
200+
saveStmt.setInt(4, playerProfile.getFloodgate().getValue());
201+
saveStmt.setString(5, playerProfile.getLastIp());
172202

173203
saveStmt.execute();
174204
try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) {
@@ -186,6 +216,14 @@ public void save(StoredProfile playerProfile) {
186216
}
187217
}
188218

219+
/**
220+
* SQLite has a slightly different syntax, so this will be overridden by SQLiteStorage
221+
* @return An SQL Statement to create the `premium` table
222+
*/
223+
protected String getCreateTableStmt() {
224+
return CREATE_TABLE_STMT;
225+
}
226+
189227
@Override
190228
public void close() {
191229
dataSource.close();

core/src/main/java/com/github/games647/fastlogin/core/storage/SQLiteStorage.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@
3030
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
3131
import com.zaxxer.hikari.HikariConfig;
3232

33-
import java.sql.Connection;
34-
import java.sql.SQLException;
35-
import java.sql.Statement;
3633
import java.util.UUID;
3734
import java.util.concurrent.locks.Lock;
3835
import java.util.concurrent.locks.ReentrantLock;
@@ -42,6 +39,17 @@
4239

4340
public class SQLiteStorage extends SQLStorage {
4441

42+
protected static final String CREATE_TABLE_STMT = "CREATE TABLE IF NOT EXISTS `" + PREMIUM_TABLE + "` ("
43+
+ "`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT, "
44+
+ "`UUID` CHAR(36), "
45+
+ "`Name` VARCHAR(16) NOT NULL, "
46+
+ "`Premium` BOOLEAN NOT NULL, "
47+
+ "`LastIp` VARCHAR(255) NOT NULL, "
48+
+ "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
49+
//the premium shouldn't steal the cracked account by changing the name
50+
+ "UNIQUE (`Name`) "
51+
+ ')';
52+
4553
private static final String SQLITE_DRIVER = "org.sqlite.SQLiteDataSource";
4654
private final Lock lock = new ReentrantLock();
4755

@@ -104,12 +112,9 @@ public void save(StoredProfile playerProfile) {
104112
}
105113

106114
@Override
107-
public void createTables() throws SQLException {
108-
try (Connection con = dataSource.getConnection();
109-
Statement createStmt = con.createStatement()) {
110-
// SQLite has a different syntax for auto increment
111-
createStmt.executeUpdate(CREATE_TABLE_STMT.replace("AUTO_INCREMENT", "AUTOINCREMENT"));
112-
}
115+
protected String getCreateTableStmt() {
116+
// SQLite has a different syntax for auto increment
117+
return CREATE_TABLE_STMT.replace("AUTO_INCREMENT", "AUTOINCREMENT");
113118
}
114119

115120
private static String replacePathVariables(PlatformPlugin<?> plugin, String input) {

0 commit comments

Comments
 (0)