Delete src/main/java/net/viper/status/modules/chat/AccountLinkManager.java via Git Manager GUI
This commit is contained in:
@@ -1,318 +0,0 @@
|
||||
package net.viper.status.modules.chat;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Verwaltet die Verknüpfung von Minecraft-Accounts mit Discord/Telegram.
|
||||
*
|
||||
* Ablauf:
|
||||
* 1. Spieler tippt /linkdiscord oder /linktelegram → Token wird generiert
|
||||
* 2. Spieler schickt Token an den Bot
|
||||
* 3. Bot-Polling erkennt Token → Verknüpfung wird gespeichert
|
||||
*
|
||||
* Speicherformat (chat_links.dat):
|
||||
* minecraft:<uuid>|name:<spielername>|discord:<discord-user-id>|telegram:<telegram-user-id>
|
||||
*/
|
||||
public class AccountLinkManager {
|
||||
|
||||
private final File file;
|
||||
private final Logger logger;
|
||||
|
||||
// UUID → verknüpfte Accounts
|
||||
private final ConcurrentHashMap<UUID, LinkedAccount> links = new ConcurrentHashMap<>();
|
||||
|
||||
// Ausstehende Token: token → UUID (läuft nach 10 Min ab)
|
||||
private final ConcurrentHashMap<String, PendingToken> pendingTokens = new ConcurrentHashMap<>();
|
||||
|
||||
public AccountLinkManager(File dataFolder, Logger logger) {
|
||||
this.file = new File(dataFolder, "chat_links.dat");
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
// ===== Datenklassen =====
|
||||
|
||||
public static class LinkedAccount {
|
||||
public UUID minecraftUUID;
|
||||
public String minecraftName;
|
||||
public String discordUserId = ""; // leer = nicht verknüpft
|
||||
public String telegramUserId = ""; // leer = nicht verknüpft
|
||||
public String telegramUsername = ""; // @username für Anzeige
|
||||
public String discordUsername = ""; // für Anzeige
|
||||
}
|
||||
|
||||
private static class PendingToken {
|
||||
UUID uuid;
|
||||
String playerName;
|
||||
String type; // "discord" oder "telegram"
|
||||
long expiresAt; // Unix-Millis
|
||||
|
||||
PendingToken(UUID uuid, String playerName, String type) {
|
||||
this.uuid = uuid;
|
||||
this.playerName = playerName;
|
||||
this.type = type;
|
||||
this.expiresAt = System.currentTimeMillis() + (10 * 60 * 1000L); // 10 Min
|
||||
}
|
||||
|
||||
boolean isExpired() {
|
||||
return System.currentTimeMillis() > expiresAt;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Token-Generierung =====
|
||||
|
||||
/**
|
||||
* Generiert einen neuen Verknüpfungs-Token für einen Spieler.
|
||||
* Bestehende Token für denselben Spieler+Typ werden überschrieben.
|
||||
*
|
||||
* @param uuid UUID des Spielers
|
||||
* @param playerName Anzeigename
|
||||
* @param type "discord" oder "telegram"
|
||||
* @return 6-stelliger alphanumerischer Token (z.B. "A3F9K2")
|
||||
*/
|
||||
public String generateToken(UUID uuid, String playerName, String type) {
|
||||
// Alte Token für diesen Spieler+Typ entfernen
|
||||
pendingTokens.entrySet().removeIf(e ->
|
||||
e.getValue().uuid.equals(uuid) && e.getValue().type.equals(type));
|
||||
|
||||
// Abgelaufene Token bereinigen
|
||||
pendingTokens.entrySet().removeIf(e -> e.getValue().isExpired());
|
||||
|
||||
String token;
|
||||
do {
|
||||
token = generateRandomToken();
|
||||
} while (pendingTokens.containsKey(token));
|
||||
|
||||
pendingTokens.put(token, new PendingToken(uuid, playerName, type));
|
||||
return token;
|
||||
}
|
||||
|
||||
private String generateRandomToken() {
|
||||
String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // ohne I,O,0,1 (Verwechslungsgefahr)
|
||||
Random rnd = new Random();
|
||||
StringBuilder sb = new StringBuilder(6);
|
||||
for (int i = 0; i < 6; i++) sb.append(chars.charAt(rnd.nextInt(chars.length())));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// ===== Token einlösen =====
|
||||
|
||||
/**
|
||||
* Versucht einen Token einzulösen (aufgerufen wenn Bot eine Nachricht empfängt).
|
||||
*
|
||||
* @param token Der eingesendete Token
|
||||
* @param externalId Discord User-ID oder Telegram User-ID (als String)
|
||||
* @param externalName Discord-Username oder Telegram-@username
|
||||
* @return LinkedAccount wenn erfolgreich, null wenn Token ungültig/abgelaufen
|
||||
*/
|
||||
public LinkedAccount redeemToken(String token, String externalId, String externalName, String type) {
|
||||
token = token.trim().toUpperCase();
|
||||
PendingToken pending = pendingTokens.get(token);
|
||||
|
||||
if (pending == null || pending.isExpired()) {
|
||||
pendingTokens.remove(token);
|
||||
return null;
|
||||
}
|
||||
// Typ muss übereinstimmen
|
||||
if (!pending.type.equals(type)) return null;
|
||||
|
||||
pendingTokens.remove(token);
|
||||
|
||||
// Bestehenden Account holen oder neu anlegen
|
||||
LinkedAccount account = links.computeIfAbsent(pending.uuid, k -> {
|
||||
LinkedAccount a = new LinkedAccount();
|
||||
a.minecraftUUID = pending.uuid;
|
||||
a.minecraftName = pending.playerName;
|
||||
return a;
|
||||
});
|
||||
account.minecraftName = pending.playerName; // aktuell halten
|
||||
|
||||
if ("discord".equals(pending.type)) {
|
||||
account.discordUserId = externalId;
|
||||
account.discordUsername = externalName;
|
||||
} else if ("telegram".equals(pending.type)) {
|
||||
account.telegramUserId = externalId;
|
||||
account.telegramUsername = externalName;
|
||||
}
|
||||
|
||||
save();
|
||||
return account;
|
||||
}
|
||||
|
||||
// ===== Lookup =====
|
||||
|
||||
public LinkedAccount getByUUID(UUID uuid) {
|
||||
return links.get(uuid);
|
||||
}
|
||||
|
||||
public LinkedAccount getByDiscordId(String discordUserId) {
|
||||
for (LinkedAccount a : links.values()) {
|
||||
if (discordUserId.equals(a.discordUserId)) return a;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public LinkedAccount getByTelegramId(String telegramUserId) {
|
||||
for (LinkedAccount a : links.values()) {
|
||||
if (telegramUserId.equals(a.telegramUserId)) return a;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Gibt den Minecraft-Namen für eine Discord-User-ID zurück, oder null. */
|
||||
public String getMinecraftNameByDiscordId(String discordUserId) {
|
||||
LinkedAccount a = getByDiscordId(discordUserId);
|
||||
return a != null ? a.minecraftName : null;
|
||||
}
|
||||
|
||||
/** Gibt den Minecraft-Namen für eine Telegram-User-ID zurück, oder null. */
|
||||
public String getMinecraftNameByTelegramId(String telegramUserId) {
|
||||
LinkedAccount a = getByTelegramId(telegramUserId);
|
||||
return a != null ? a.minecraftName : null;
|
||||
}
|
||||
|
||||
/** Prüft ob ein Token gerade aussteht (für Tab-Complete etc.). */
|
||||
public boolean hasPendingToken(UUID uuid, String type) {
|
||||
for (PendingToken t : pendingTokens.values()) {
|
||||
if (t.uuid.equals(uuid) && t.type.equals(type) && !t.isExpired()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===== Verknüpfung aufheben =====
|
||||
|
||||
public boolean unlinkDiscord(UUID uuid) {
|
||||
LinkedAccount a = links.get(uuid);
|
||||
if (a == null || a.discordUserId.isEmpty()) return false;
|
||||
a.discordUserId = "";
|
||||
a.discordUsername = "";
|
||||
cleanupEmpty(uuid);
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean unlinkTelegram(UUID uuid) {
|
||||
LinkedAccount a = links.get(uuid);
|
||||
if (a == null || a.telegramUserId.isEmpty()) return false;
|
||||
a.telegramUserId = "";
|
||||
a.telegramUsername = "";
|
||||
cleanupEmpty(uuid);
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cleanupEmpty(UUID uuid) {
|
||||
LinkedAccount a = links.get(uuid);
|
||||
if (a != null && a.discordUserId.isEmpty() && a.telegramUserId.isEmpty()) {
|
||||
links.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Convenience-Methoden für Bridges =====
|
||||
|
||||
/**
|
||||
* Löst einen Telegram-Token ein.
|
||||
* Wrapper für redeemToken mit type="telegram".
|
||||
*/
|
||||
public LinkedAccount redeemTelegram(String token, String telegramUserId, String telegramUsername) {
|
||||
return redeemToken(token, telegramUserId, telegramUsername, "telegram");
|
||||
}
|
||||
|
||||
/**
|
||||
* Löst einen Discord-Token ein.
|
||||
* Wrapper für redeemToken mit type="discord".
|
||||
*/
|
||||
public LinkedAccount redeemDiscord(String token, String discordUserId, String discordUsername) {
|
||||
return redeemToken(token, discordUserId, discordUsername, "discord");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Anzeigenamen für einen Telegram-Nutzer zurück.
|
||||
* Wenn verknüpft: "MinecraftName (@telegram)", sonst: "@telegram"
|
||||
*/
|
||||
public String resolveTelegramName(String telegramUserId, String fallbackName) {
|
||||
String mc = getMinecraftNameByTelegramId(telegramUserId);
|
||||
return mc != null ? mc : fallbackName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Anzeigenamen für einen Discord-Nutzer zurück.
|
||||
* Wenn verknüpft: Minecraft-Name, sonst: Discord-Username
|
||||
*/
|
||||
public String resolveDiscordName(String discordUserId, String fallbackName) {
|
||||
String mc = getMinecraftNameByDiscordId(discordUserId);
|
||||
return mc != null ? mc : fallbackName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt das korrekte Format-String zurück abhängig ob Account verknüpft.
|
||||
* linked=true → linkedFormat (mit {player}), false → unlinkedFormat (mit {user})
|
||||
*/
|
||||
public boolean isLinkedTelegram(String telegramUserId) {
|
||||
return getByTelegramId(telegramUserId) != null;
|
||||
}
|
||||
|
||||
public boolean isLinkedDiscord(String discordUserId) {
|
||||
return getByDiscordId(discordUserId) != null;
|
||||
}
|
||||
|
||||
// ===== Persistenz =====
|
||||
|
||||
public void save() {
|
||||
try (BufferedWriter bw = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
|
||||
for (LinkedAccount a : links.values()) {
|
||||
bw.write(a.minecraftUUID
|
||||
+ "|" + esc(a.minecraftName)
|
||||
+ "|" + esc(a.discordUserId)
|
||||
+ "|" + esc(a.discordUsername)
|
||||
+ "|" + esc(a.telegramUserId)
|
||||
+ "|" + esc(a.telegramUsername));
|
||||
bw.newLine();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("[ChatModule] Fehler beim Speichern der Account-Links: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void load() {
|
||||
links.clear();
|
||||
if (!file.exists()) return;
|
||||
try (BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) continue;
|
||||
String[] p = line.split("\\|", -1);
|
||||
if (p.length < 6) continue;
|
||||
try {
|
||||
LinkedAccount a = new LinkedAccount();
|
||||
a.minecraftUUID = UUID.fromString(p[0]);
|
||||
a.minecraftName = unesc(p[1]);
|
||||
a.discordUserId = unesc(p[2]);
|
||||
a.discordUsername = unesc(p[3]);
|
||||
a.telegramUserId = unesc(p[4]);
|
||||
a.telegramUsername = unesc(p[5]);
|
||||
if (!a.discordUserId.isEmpty() || !a.telegramUserId.isEmpty()) {
|
||||
links.put(a.minecraftUUID, a);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("[ChatModule] Fehler beim Laden der Account-Links: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static String esc(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("\\", "\\\\").replace("|", "\\p");
|
||||
}
|
||||
|
||||
private static String unesc(String s) {
|
||||
if (s == null) return "";
|
||||
return s.replace("\\p", "|").replace("\\\\", "\\");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user