Skip to content

Commit a7c5209

Browse files
committed
wip plugin sync command
1 parent df11174 commit a7c5209

5 files changed

Lines changed: 204 additions & 16 deletions

File tree

bukkit/src/main/java/com/xinecraft/minetrax/bukkit/MinetraxBukkit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public void onEnable() {
241241

242242
// Setup Schedulers
243243
if (isRemindPlayerToLinkEnabled) {
244-
getServer().getScheduler().scheduleSyncRepeatingTask(this, new AccountLinkReminderTask(), 20 * 20, remindPlayerToLinkInterval * 20L);
244+
getServer().getScheduler().scheduleSyncRepeatingTask(this, new AccountLinkReminderTask(), 10 * 20, remindPlayerToLinkInterval * 20L);
245245
}
246246
if (isServerIntelEnabled) {
247247
getServer().getScheduler().runTaskTimerAsynchronously(this, new ServerIntelReportTask(), 60 * 20L, 60 * 20L); // every minute

bukkit/src/main/java/com/xinecraft/minetrax/bukkit/commands/MinetraxAdminCommand.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.xinecraft.minetrax.bukkit.commands;
22

3+
import com.xinecraft.minetrax.bukkit.MinetraxBukkit;
34
import com.xinecraft.minetrax.common.MinetraxCommon;
45
import com.xinecraft.minetrax.common.enums.BanWardenSyncType;
56
import org.bukkit.ChatColor;
67
import org.bukkit.command.Command;
78
import org.bukkit.command.CommandExecutor;
89
import org.bukkit.command.CommandSender;
10+
import org.bukkit.command.ConsoleCommandSender;
911
import org.jetbrains.annotations.NotNull;
1012

1113
public class MinetraxAdminCommand implements CommandExecutor {
@@ -23,6 +25,11 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
2325
}
2426

2527
if (firstArg.equalsIgnoreCase("banwarden:sync")) {
28+
if (!(commandSender instanceof ConsoleCommandSender)) {
29+
commandSender.sendMessage(ChatColor.RED + "This command can only be run from console.");
30+
return false;
31+
}
32+
2633
String secondArg = strings.length > 1 ? strings[1].toLowerCase() : "all";
2734
commandSender.sendMessage(ChatColor.GREEN + "[BanWarden] Syncing " + secondArg + " ban data to web, plz check server logs for progress...");
2835
banwardenSyncBans(secondArg);
@@ -41,12 +48,16 @@ private void usage(CommandSender sender) {
4148
}
4249

4350
private void banwardenSyncBans(String typeString) {
51+
if (!MinetraxBukkit.getPlugin().getIsBanWardenEnabled()) {
52+
MinetraxBukkit.getPlugin().getLogger().warning("BanWarden is not enabled, cannot sync bans.");
53+
return;
54+
}
55+
4456
BanWardenSyncType syncType = switch (typeString) {
4557
case "active" -> BanWardenSyncType.ACTIVE;
4658
case "inactive" -> BanWardenSyncType.INACTIVE;
4759
default -> BanWardenSyncType.ALL;
4860
};
4961
MinetraxCommon.getInstance().getBanWarden().sync(syncType);
50-
return;
5162
}
5263
}

common/src/main/java/com/xinecraft/minetrax/common/actions/ReportPlayerPunishment.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,14 @@ public static void syncSync(List<PunishmentData> data) throws HttpException, IOE
2525
}
2626
}
2727

28-
public static void upsertSync(PunishmentData data) throws HttpException, IOException {
29-
JsonObject payload = new JsonObject();
30-
payload.addProperty("type", data.getType());
31-
// todo
28+
public static void reportSync(PunishmentData data) throws HttpException, IOException {
29+
JsonObject payload = common.getGson().toJsonTree(data).getAsJsonObject();
3230
payload.addProperty("server_id", common.getPlugin().getApiServerId());
3331

3432
HttpResponse response = MinetraxHttpUtil.post(MinetraxHttpUtil.BANWARDEN_REPORT_PUNISHMENT_ROUTE, payload.toString(), null);
3533

3634
if (!response.isSuccessful()) {
37-
throw new HttpException(response, "ReportServerChat.reportAsync");
35+
throw new HttpException(response, "ReportServerChat.upsertSync");
3836
}
3937
}
4038
}

common/src/main/java/com/xinecraft/minetrax/common/banwarden/hooks/LibertybansHook.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class LibertybansHook implements BanWardenHook {
3030
public static final MinetraxCommon common = MinetraxCommon.getInstance();
3131
private final Omnibus omnibus;
3232
private final LibertyBans libertyBans;
33-
private static final int RATE_LIMIT_DELAY_SECONDS = 1; // TODO change to 1 seconds
33+
private static final int RATE_LIMIT_DELAY_SECONDS = 1;
3434
private static final int CHUNK_SIZE = 50;
3535

3636
public LibertybansHook() {
@@ -74,9 +74,7 @@ public void accept(PostPunishEvent event) {
7474
MinetraxCommon.getInstance().getScheduler().runAsync(() -> {
7575
try {
7676
PunishmentData data = convertPunishmentToData(punishment, true, null);
77-
List<PunishmentData> punishmentDataList = new ArrayList<>();
78-
punishmentDataList.add(data);
79-
ReportPlayerPunishment.syncSync(punishmentDataList);
77+
ReportPlayerPunishment.reportSync(data);
8078
} catch (Exception e) {
8179
LoggingUtil.error("[BanWarden] PunishEvent -> Error reporting event to Minetrax: " + e.getMessage());
8280
}
@@ -92,9 +90,7 @@ public void accept(PostPardonEvent event) {
9290
MinetraxCommon.getInstance().getScheduler().runAsync(() -> {
9391
try {
9492
PunishmentData data = convertPunishmentToData(punishment, false, operator);
95-
List<PunishmentData> punishmentDataList = new ArrayList<>();
96-
punishmentDataList.add(data);
97-
ReportPlayerPunishment.syncSync(punishmentDataList);
93+
ReportPlayerPunishment.reportSync(data);
9894
} catch (Exception e) {
9995
LoggingUtil.error("[BanWarden] PardonEvent -> Error reporting event to Minetrax: " + e.getMessage());
10096
}
@@ -192,7 +188,7 @@ private PunishmentData convertPunishmentToData(Punishment punishment, boolean is
192188
if (punishment.getScope().appliesTo("*")) {
193189
punishmentData.server_scope = "*";
194190
} else {
195-
punishmentData.server_scope = "local";
191+
punishmentData.server_scope = "local"; // TODO: how to get which server this ban apply to. (ie, server_origin)
196192
}
197193

198194
// victim
@@ -216,6 +212,8 @@ private PunishmentData convertPunishmentToData(Punishment punishment, boolean is
216212
PlayerOperator operator = (PlayerOperator) punishment.getOperator();
217213
punishmentData.creator_uuid = operator.getUUID().toString();
218214
punishmentData.creator_username = null;
215+
} else {
216+
punishmentData.creator_username = "CONSOLE";
219217
}
220218

221219
// pardon operator

common/src/main/java/com/xinecraft/minetrax/common/banwarden/hooks/LitebansHook.java

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,38 @@
11
package com.xinecraft.minetrax.common.banwarden.hooks;
22

3+
import com.xinecraft.minetrax.common.MinetraxCommon;
4+
import com.xinecraft.minetrax.common.actions.ReportPlayerPunishment;
35
import com.xinecraft.minetrax.common.data.PunishmentData;
6+
import com.xinecraft.minetrax.common.enums.BanWardenPluginType;
7+
import com.xinecraft.minetrax.common.enums.BanWardenPunishmentType;
48
import com.xinecraft.minetrax.common.enums.BanWardenSyncType;
59
import com.xinecraft.minetrax.common.interfaces.banwarden.BanWardenHook;
10+
import com.xinecraft.minetrax.common.utils.LoggingUtil;
11+
import litebans.api.Database;
12+
import litebans.api.Entry;
13+
import litebans.api.Events;
14+
import space.arim.omnibus.util.concurrent.ReactionStage;
15+
16+
import java.sql.PreparedStatement;
17+
import java.sql.ResultSet;
18+
import java.sql.SQLException;
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.concurrent.CompletableFuture;
22+
import java.util.concurrent.CompletionStage;
23+
import java.util.concurrent.TimeUnit;
24+
import java.util.concurrent.atomic.AtomicInteger;
25+
import java.util.function.Function;
626

727
public class LitebansHook implements BanWardenHook {
28+
public static final MinetraxCommon common = MinetraxCommon.getInstance();
29+
private static final int RATE_LIMIT_DELAY_SECONDS = 1;
30+
private static final int CHUNK_SIZE = 50;
31+
32+
public LitebansHook() {
33+
registerEventListeners();
34+
}
35+
836
@Override
937
public void upsert(PunishmentData punishmentData) {
1038

@@ -22,6 +50,159 @@ public PunishmentData getPunishment(String punishmentId) {
2250

2351
@Override
2452
public void sync(BanWardenSyncType type) {
25-
System.out.println("Syncing with Litebans from LitebansHook");
53+
syncAllPunishments().thenAccept(aVoid -> {
54+
LoggingUtil.debug("[BanWarden] Syncing of punishments from LiteBans completed.");
55+
});
56+
}
57+
58+
private void registerEventListeners() {
59+
Events.get().register(new Events.Listener() {
60+
@Override
61+
public void entryAdded(Entry entry) {
62+
try {
63+
PunishmentData data = convertEntryToData(entry);
64+
ReportPlayerPunishment.reportSync(data);
65+
} catch (Exception e) {
66+
LoggingUtil.error("[BanWarden] EntryAdded -> Error reporting event to Minetrax: " + e.getMessage());
67+
}
68+
}
69+
70+
@Override
71+
public void entryRemoved(Entry entry) {
72+
try {
73+
PunishmentData data = convertEntryToData(entry);
74+
ReportPlayerPunishment.reportSync(data);
75+
} catch (Exception e) {
76+
LoggingUtil.error("[BanWarden] EntryRemoved -> Error reporting event to Minetrax: " + e.getMessage());
77+
}
78+
}
79+
});
80+
}
81+
82+
private CompletableFuture<Void> syncAllPunishments() {
83+
AtomicInteger totalPunishments = new AtomicInteger(0);
84+
AtomicInteger offset = new AtomicInteger(0);
85+
86+
return CompletableFuture.<Void>completedFuture(null).thenCompose(new Function<Void, CompletionStage<Void>>() {
87+
@Override
88+
public CompletionStage<Void> apply(Void unused) {
89+
return fetchPunishmentChunk(CHUNK_SIZE, offset.get())
90+
.thenCompose(punishmentList -> {
91+
int fetchedCount = punishmentList.size();
92+
totalPunishments.addAndGet(fetchedCount);
93+
94+
// Process the current chunk
95+
List<PunishmentData> punishmentDataList = new ArrayList<>(punishmentList);
96+
97+
// Report to Minetrax with API
98+
try {
99+
if (!punishmentDataList.isEmpty()) {
100+
LoggingUtil.info("Syncing batch of " + punishmentDataList.size() + " punishments to Minetrax...");
101+
ReportPlayerPunishment.syncSync(punishmentDataList);
102+
}
103+
} catch (Exception e) {
104+
LoggingUtil.error("[BanWarden] Error syncing punishments to Minetrax: " + e.getMessage());
105+
}
106+
107+
if (fetchedCount == CHUNK_SIZE) {
108+
// If we fetched a full chunk, there might be more bans
109+
offset.addAndGet(CHUNK_SIZE);
110+
111+
// some delay to avoid rate limit.
112+
try {
113+
Thread.sleep(TimeUnit.SECONDS.toMillis(RATE_LIMIT_DELAY_SECONDS));
114+
} catch (InterruptedException e) {
115+
throw new RuntimeException(e);
116+
}
117+
118+
return apply(null); // Recurse to fetch the next chunk
119+
} else {
120+
// We've fetched all bans
121+
LoggingUtil.info("[BanWarden] Finished syncing total of " + totalPunishments.get() + " punishments from LiteBans.");
122+
return CompletableFuture.completedFuture(null);
123+
}
124+
});
125+
}
126+
});
127+
}
128+
129+
private CompletionStage<List<PunishmentData>> fetchPunishmentChunk(int limit, int offset) {
130+
return CompletableFuture.supplyAsync(() -> {
131+
List<PunishmentData> punishmentDataList = new ArrayList<>();
132+
String sql = "SELECT id, uuid, ip, reason, banned_by_uuid, banned_by_name, removed_by_uuid, removed_by_name, removed_by_reason, removed_by_date, time, until, template, server_scope, server_origin, silent, ipban, ipban_wildcard, active,'ban'as type FROM litebans_bans UNION ALL SELECT id, uuid, ip, reason, banned_by_uuid, banned_by_name, removed_by_uuid, removed_by_name, removed_by_reason, removed_by_date, time, until, template, server_scope, server_origin, silent, ipban, ipban_wildcard, active,'mute'as type FROM litebans_mutes UNION ALL SELECT id, uuid, ip, reason, banned_by_uuid, banned_by_name, removed_by_uuid, removed_by_name, removed_by_reason, removed_by_date, time, until, template, server_scope, server_origin, silent, ipban, ipban_wildcard, active,'warn'as type FROM litebans_warnings ORDER BY id ASC LIMIT ? OFFSET ?";
133+
134+
try (PreparedStatement stmt = Database.get().prepareStatement(sql)) {
135+
stmt.setInt(1, limit);
136+
stmt.setInt(2, offset);
137+
ResultSet rs = stmt.executeQuery();
138+
139+
while (rs.next()) {
140+
// Print fetched data.
141+
String s = rs.getString("id") + rs.getString("uuid") + ", " + rs.getString("reason") + ", " + rs.getString("server_origin");
142+
System.out.println(s);
143+
144+
PunishmentData data = convertResultSetToData(rs);
145+
punishmentDataList.add(data);
146+
}
147+
} catch (SQLException e) {
148+
LoggingUtil.error("[BanWarden] Error fetching punishments from LiteBans: " + e.getMessage());
149+
}
150+
151+
return punishmentDataList;
152+
});
153+
}
154+
155+
private PunishmentData convertEntryToData(Entry entry) {
156+
String type = getBanWardenPunishmentType(entry.getType()).name().toLowerCase();
157+
PunishmentData punishmentData = new PunishmentData();
158+
punishmentData.plugin_name = BanWardenPluginType.LITEBANS.name().toLowerCase();
159+
punishmentData.plugin_punishment_id = String.valueOf(entry.getId());
160+
punishmentData.type = type;
161+
punishmentData.start_at = entry.getDateStart();
162+
punishmentData.end_at = entry.getDateEnd();
163+
punishmentData.reason = entry.getReason();
164+
punishmentData.is_active = entry.isActive();
165+
punishmentData.server_scope = entry.getServerScope();
166+
punishmentData.origin_server_name = entry.getServerOrigin();
167+
punishmentData.uuid = entry.getUuid();
168+
punishmentData.ip_address = entry.getIp();
169+
punishmentData.is_ipban = entry.getType().equalsIgnoreCase("ipban");
170+
punishmentData.creator_uuid = entry.getExecutorUUID();
171+
punishmentData.creator_username = entry.getExecutorName();
172+
173+
punishmentData.removed_at = 0; // TODO
174+
punishmentData.remover_uuid = entry.getRemovedByUUID();
175+
punishmentData.remover_username = entry.getRemovedByName();
176+
177+
return punishmentData;
178+
}
179+
180+
private PunishmentData convertResultSetToData(ResultSet rs) throws SQLException {
181+
PunishmentData punishmentData = new PunishmentData();
182+
punishmentData.plugin_name = BanWardenPluginType.LITEBANS.name().toLowerCase();
183+
punishmentData.plugin_punishment_id = rs.getString("id");
184+
punishmentData.type = rs.getString("type").toLowerCase();
185+
punishmentData.start_at = rs.getLong("time");
186+
punishmentData.end_at = rs.getLong("until");
187+
punishmentData.reason = rs.getString("reason");
188+
punishmentData.is_active = true;
189+
punishmentData.server_scope = rs.getString("server_scope");
190+
punishmentData.uuid = rs.getString("uuid");
191+
punishmentData.ip_address = rs.getString("ip");
192+
punishmentData.is_ipban = punishmentData.type.equals("ban") && rs.getBoolean("ipban");
193+
punishmentData.creator_uuid = rs.getString("banned_by_uuid");
194+
punishmentData.creator_username = rs.getString("banned_by_name");
195+
196+
return punishmentData;
197+
}
198+
199+
private BanWardenPunishmentType getBanWardenPunishmentType(String type) {
200+
return switch (type.toLowerCase()) {
201+
case "ban" -> BanWardenPunishmentType.BAN;
202+
case "mute" -> BanWardenPunishmentType.MUTE;
203+
case "warning" -> BanWardenPunishmentType.WARN;
204+
case "kick" -> BanWardenPunishmentType.KICK;
205+
default -> BanWardenPunishmentType.UNKNOWN;
206+
};
26207
}
27208
}

0 commit comments

Comments
 (0)