🌐 eeDomainInfo API

ΠœΠΎΡ‰Π½Ρ‹ΠΉ API для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠΌ eeDomainInfo

Автор: tyulpan
Π Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π°: Velocity, BungeeCord, NullCordX


πŸš€ Быстрый старт

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ API

βŽ—
βœ“
1
2
3
4
5
6
7
8
DomainInfoAPI api = DomainInfoAPI.getInstance();

if (api == null || !api.isAvailable()) {
    System.out.println("eeDomainInfo ΠΏΠ»Π°Π³ΠΈΠ½ Π½Π΅ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½!");
    return;
}

System.out.println("API Π³ΠΎΡ‚ΠΎΠ² ΠΊ использованию!");

Основная информация

βŽ—
βœ“
1
2
3
String apiVersion = api.getAPIVersion();        
String pluginVersion = api.getPluginVersion();  
boolean available = api.isAvailable();          // true/false

🌐 Π Π°Π±ΠΎΡ‚Π° с Π΄ΠΎΠΌΠ΅Π½Π°ΠΌΠΈ (api.domains())

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Ρ… Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²

βŽ—
βœ“
1
2
3
4
5
6
Map<String, Integer> domains = api.domains().getActiveDomains();
// Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚: {"example.com": 5, "test.net": 2, "demo.org": 1}

domains.forEach((domain, online) -> {
    System.out.println(domain + ": " + online + " ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²");
});

Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ Π΄ΠΎΠΌΠ΅Π½Π΅

βŽ—
βœ“
Optional<DomainInfo> info = api.domains().getDomainInfo("example.com");

if (info.isPresent()) {
    DomainInfo domain = info.get();

    System.out.println("Π”ΠΎΠΌΠ΅Π½: " + domain.getDomain());              // "example.com"
    System.out.println("Онлайн: " + domain.getCurrentOnline());      // 5
    System.out.println("Π˜Π³Ρ€ΠΎΠΊΠΈ: " + domain.getOnlinePlayers());      // ["Player1", "Player2"]
    System.out.println("АктивСн: " + domain.isActive());             // true
    System.out.println("ΠΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ: " + domain.getLastActivity());   // 2025-01-01T12:00:00
}

Бтатистика Π΄ΠΎΠΌΠ΅Π½Π°

βŽ—
βœ“
// ВСкущая статистика
api.domains().getDomainStats("example.com").thenAccept(stats -> {
    System.out.println("Онлайн (сСрвис): " + stats.getCurrentOnline());    // 5
    System.out.println("Онлайн (Π‘Π”): " + stats.getDatabaseOnline());        // 5
    System.out.println("Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ: " + stats.isSynced());            // true
});

// Бтатистика Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ (7 Π΄Π½Π΅ΠΉ)
api.domains().getDomainStats("example.com", 7).thenAccept(stats -> {
    System.out.println("ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ Π·Π° нСдСлю: " + stats.getTotalConnections()); // 150
    System.out.println("Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²: " + stats.getUniquePlayers());       // 45
});

πŸ“‘ Бтатистика ΠΏΠΈΠ½Π³ΠΎΠ² Π΄ΠΎΠΌΠ΅Π½Π°

βŽ—
βœ“
// ΠžΠ±Ρ‰Π°Ρ статистика ΠΏΠΈΠ½Π³ΠΎΠ²
api.domains().getDomainPingStats("example.com").thenAccept(pingStats -> {
    System.out.println("ВсСго ΠΏΠΈΠ½Π³ΠΎΠ²: " + pingStats.getTotalPings());       // 1250
    System.out.println("Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… IP: " + pingStats.getUniqueIPs());       // 89
    System.out.println("ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠΈΠ½Π³: " + pingStats.getFirstPing());         // 2025-01-01T10:00:00
    System.out.println("ПослСдний пинг: " + pingStats.getLastPing());       // 2025-01-15T14:30:00
});

// Бтатистика ΠΏΠΈΠ½Π³ΠΎΠ² Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ (7 Π΄Π½Π΅ΠΉ)
api.domains().getDomainPingStats("example.com", 7).thenAccept(pingStats -> {
    System.out.println("Пингов за нСдСлю: " + pingStats.getTotalPings());   // 320
    System.out.println("Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… IP: " + pingStats.getUniqueIPs());       // 45
});

// ПослСдниС пинги
api.domains().getRecentPings("example.com", 10).thenAccept(recentPings -> {
    System.out.println("ПослСдниС 10 пингов:");
    recentPings.forEach(ping -> {
        System.out.println("IP: " + ping.getPlayerIP() + 
                          " | ВрСмя: " + ping.getTimestamp());
    });
});

Π£Ρ‚ΠΈΠ»ΠΈΡ‚Ρ‹ для Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²

βŽ—
βœ“
// Бписок ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² Π½Π° Π΄ΠΎΠΌΠ΅Π½Π΅
List<String> players = api.domains().getPlayersOnDomain("example.com");

// ΠžΠ±Ρ‰ΠΈΠΉ ΠΎΠ½Π»Π°ΠΉΠ½
int totalOnline = api.domains().getTotalOnline();

// Онлайн ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ Π΄ΠΎΠΌΠ΅Π½Π°
int domainOnline = api.domains().getDomainOnline("example.com");

// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° сущСствования
boolean exists = api.domains().domainExists("example.com");

// Валидация Π΄ΠΎΠΌΠ΅Π½Π°
boolean valid = api.domains().isValidDomain("example.com");

πŸ‘€ Π Π°Π±ΠΎΡ‚Π° с ΠΈΠ³Ρ€ΠΎΠΊΠ°ΠΌΠΈ (api.players())

Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎΠ± ΠΈΠ³Ρ€ΠΎΠΊΠ΅

βŽ—
βœ“
// Поиск ΠΏΠΎ Π½ΠΈΠΊΡƒ
api.players().getPlayerInfo("Player1").thenAccept(playerOpt -> {
    if (playerOpt.isPresent()) {
        PlayerInfo player = playerOpt.get();

        System.out.println("Ник: " + player.getPlayerName());         // "Player1"
        System.out.println("UUID: " + player.getPlayerUuid());        // UUID
        System.out.println("Π”ΠΎΠΌΠ΅Π½: " + player.getCurrentDomain());    // "example.com"
        System.out.println("IP: " + player.getLastKnownIP());         // "192.168.1.1"
        System.out.println("ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ Π²Ρ…ΠΎΠ΄: " + player.getFirstJoin());  // LocalDateTime
        System.out.println("ПослСдний Π²Ρ…ΠΎΠ΄: " + player.getLastJoin()); // LocalDateTime
        System.out.println("ВсСго Π²Ρ…ΠΎΠ΄ΠΎΠ²: " + player.getTotalJoins()); // 25
        System.out.println("Онлайн: " + player.isOnline());           // true
    }
});

// Поиск по UUID
UUID playerUUID = UUID.fromString("...");
api.players().getPlayerInfo(playerUUID).thenAccept(playerOpt -> {
    // Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ
});

Π˜ΡΡ‚ΠΎΡ€ΠΈΡ ΠΈΠ³Ρ€ΠΎΠΊΠ°

βŽ—
βœ“
// Π˜ΡΡ‚ΠΎΡ€ΠΈΡ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ ΠΈΠ³Ρ€ΠΎΠΊΠ°
api.players().getPlayerHistory("Player1").thenAccept(history -> {
    System.out.println("Π˜ΡΡ‚ΠΎΡ€ΠΈΡ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ Player1:");
    history.forEach(entry -> {
        System.out.println("Π”ΠΎΠΌΠ΅Π½: " + entry.getDomain() + 
                          " | IP: " + entry.getPlayerIP() + 
                          " | ВрСмя: " + entry.getJoinTime() + 
                          " | Π—Π°Ρ…ΠΎΠ΄ΠΎΠ² Π½Π° Π΄ΠΎΠΌΠ΅Π½: " + entry.getTotalJoinsOnDomain());
    });
});

Π£Ρ‚ΠΈΠ»ΠΈΡ‚Ρ‹ для ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²

βŽ—
βœ“
// Π”ΠΎΠΌΠ΅Π½ ΠΈΠ³Ρ€ΠΎΠΊΠ°
Optional<String> domain = api.players().getPlayerDomain("Player1");
if (domain.isPresent()) {
    System.out.println("Player1 ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π½Π°: " + domain.get());
}

// ВсС ΠΎΠ½Π»Π°ΠΉΠ½ ΠΈΠ³Ρ€ΠΎΠΊΠΈ
List<String> allPlayers = api.players().getOnlinePlayers();

// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΎΠ½Π»Π°ΠΉΠ½Π°
boolean online = api.players().isPlayerOnline("Player1");

πŸ“Š Бтатистика (api.stats())

Π“Π»ΠΎΠ±Π°Π»ΡŒΠ½Π°Ρ статистика

βŽ—
βœ“
api.stats().getGlobalStats().thenAccept(stats -> {
    System.out.println("ΠžΠ±Ρ‰ΠΈΠΉ ΠΎΠ½Π»Π°ΠΉΠ½: " + stats.getTotalOnline());           // 15
    System.out.println("ВсСго Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²: " + stats.getTotalDomains());         // 3
    System.out.println("Π˜Π³Ρ€ΠΎΠΊΠΎΠ² Π² Π‘Π”: " + stats.getTotalPlayersInDatabase()); // 1250
    System.out.println("ΠŸΠΎΠΏΡƒΠ»ΡΡ€Π½Ρ‹ΠΉ Π΄ΠΎΠΌΠ΅Π½: " + stats.getMostPopularDomain()); // "example.com"

    // РаспрСдСлСниС ΠΏΠΎ Π΄ΠΎΠΌΠ΅Π½Π°ΠΌ
    Map<String, Integer> distribution = stats.getDomainDistribution();
    distribution.forEach((domain, count) -> {
        System.out.println(domain + ": " + count + " ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²");
    });
});

Бтатистика всСх Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²

βŽ—
βœ“
api.stats().getAllDomainStats().thenAccept(allStats -> {
    System.out.println("Бтатистика всСх Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²:");
    allStats.forEach((domain, stats) -> {
        System.out.println("Π”ΠΎΠΌΠ΅Π½: " + domain);
        System.out.println("  Онлайн: " + stats.getCurrentOnline());
        System.out.println("  ВсСго ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ: " + stats.getTotalConnections());
        System.out.println("  Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²: " + stats.getUniqueePlayers());
        System.out.println("  Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ: " + stats.isSynced());
    });
});

Π’ΠΎΠΏ Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²

βŽ—
βœ“
// Π’ΠΎΠΏ ΠΏΠΎ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌΡƒ ΠΎΠ½Π»Π°ΠΉΠ½Ρƒ
api.stats().getTopDomainsByOnline(5).thenAccept(top -> {
    System.out.println("Π’ΠΎΠΏ 5 Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΏΠΎ ΠΎΠ½Π»Π°ΠΉΠ½Ρƒ:");
    top.forEach((domain, online) -> {
        System.out.println(domain + ": " + online + " ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²");
    });
    // Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚: {"example.com": 10, "test.net": 5, "demo.org": 2}
});

// Π’ΠΎΠΏ ΠΏΠΎ ΠΎΠ±Ρ‰Π΅ΠΌΡƒ количСству ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ
api.stats().getTopDomainsByConnections(5).thenAccept(top -> {
    System.out.println("Π’ΠΎΠΏ 5 Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΏΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΠΌ:");
    top.forEach((domain, connections) -> {
        System.out.println(domain + ": " + connections + " ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ");
    });
});

Бинхронизация Π΄Π°Π½Π½Ρ‹Ρ…

βŽ—
βœ“
1
2
3
api.stats().syncData().thenRun(() -> {
    System.out.println("Π”Π°Π½Π½Ρ‹Π΅ сСрвиса ΠΈ Π‘Π” синхронизированы!");
});

🎯 Бобытия (api.events())

Бобытия Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²

βŽ—
βœ“
api.events().registerDomainListener(new DomainEventListener() {
    @Override
    public void onPlayerJoinDomain(DomainPlayerJoinEvent event) {
        String player = event.getPlayerName();        // "Player1"
        String domain = event.getDomain();            // "example.com"
        String ip = event.getPlayerIP();              // "192.168.1.1"
        LocalDateTime time = event.getTimestamp();    // 2025-01-01T12:00:00
        int newCount = event.getNewOnlineCount();     // 6

        System.out.println("🟒 " + player + " ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ ΠΊ " + domain);

        // ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° Π² Discord
        sendDiscordWebhook("🟒 **" + player + "** ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ ΠΊ `" + domain + "`");
    }

    @Override
    public void onPlayerLeaveDomain(DomainPlayerLeaveEvent event) {
        System.out.println("πŸ”΄ " + event.getPlayerName() + " ΠΏΠΎΠΊΠΈΠ½ΡƒΠ» " + event.getDomain());

        // ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° Π² Discord
        sendDiscordWebhook("πŸ”΄ **" + event.getPlayerName() + "** ΠΏΠΎΠΊΠΈΠ½ΡƒΠ» `" + event.getDomain() + "`");
    }

    @Override
    public void onDomainPing(DomainPingEvent event) {
        String domain = event.getDomain();            // "example.com"
        String ip = event.getPlayerIP();              // "192.168.1.1"
        LocalDateTime time = event.getTimestamp();    // 2025-01-01T12:00:00

        System.out.println("πŸ“‘ Пинг Π΄ΠΎΠΌΠ΅Π½Π° " + domain + " ΠΎΡ‚ " + ip);

        // Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΈΠ½Π³ΠΎΠ² для Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ
        logPingForAnalytics(domain, ip, time);
    }
});

Бобытия ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²

βŽ—
βœ“
api.events().registerPlayerListener(new PlayerEventListener() {
    @Override
    public void onPlayerConnect(PlayerConnectEvent event) {
        String player = event.getPlayerName();        // "Player1"
        UUID uuid = event.getPlayerUuid();           // UUID
        String domain = event.getDomain();            // "example.com"
        String ip = event.getPlayerIP();              // "192.168.1.1"
        LocalDateTime time = event.getTimestamp();    // 2025-01-01T12:00:00
        boolean firstJoin = event.isFirstJoin();      // false

        System.out.println("πŸ‘€ НовоС ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅: " + player + " (" + uuid + ")");

        // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π° VPN
        if (isVPN(ip)) {
            System.out.println("⚠️ Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ VPN: " + ip);
        }

        // Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅
        logToFile("CONNECT", player, domain, ip);
    }

    @Override
    public void onPlayerDisconnect(PlayerDisconnectEvent event) {
        long sessionMs = event.getSessionDuration();  // врСмя сСссии Π² миллисСкундах
        long sessionMin = sessionMs / 1000 / 60;      // Π² ΠΌΠΈΠ½ΡƒΡ‚Π°Ρ…

        System.out.println("πŸ‘€ ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅: " + event.getPlayerName() + 
                          " (сСссия: " + sessionMin + " мин)");

        // ОбновлСниС вСб-панСли
        updateWebStats();
    }

    @Override
    public void onPlayerSwitchDomain(PlayerSwitchDomainEvent event) {
        String from = event.getFromDomain();          // "old.com"
        String to = event.getToDomain();              // "new.com"

        System.out.println("πŸ”„ " + event.getPlayerName() + 
                          " ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ: " + from + " β†’ " + to);
    }
});

ΠžΡ‚ΠΌΠ΅Π½Π° рСгистрации

βŽ—
βœ“
DomainEventListener domainListener = new DomainEventListener() { /* ... */ };
PlayerEventListener playerListener = new PlayerEventListener() { /* ... */ };

// РСгистрация
api.events().registerDomainListener(domainListener);
api.events().registerPlayerListener(playerListener);

// ΠžΡ‚ΠΌΠ΅Π½Π° рСгистрации
api.events().unregisterDomainListener(domainListener);
api.events().unregisterPlayerListener(playerListener);

πŸ’‘ ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования

πŸ“‘ ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ ΠΏΠΈΠ½Π³ΠΎΠ² ΠΈ DDoS Π·Π°Ρ‰ΠΈΡ‚Π°

βŽ—
βœ“
public class PingMonitoring {
    private final Map<String, Integer> pingCounts = new ConcurrentHashMap<>();
    private final Set<String> blockedIPs = ConcurrentHashMap.newKeySet();

    public void setupPingMonitoring() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        api.events().registerDomainListener(new DomainEventListener() {
            @Override
            public void onDomainPing(DomainPingEvent event) {
                String ip = event.getPlayerIP();
                String domain = event.getDomain();

                ```java
                // ΠŸΠΎΠ΄ΡΡ‡Π΅Ρ‚ ΠΏΠΈΠ½Π³ΠΎΠ² с IP Π·Π° послСднюю ΠΌΠΈΠ½ΡƒΡ‚Ρƒ
                String key = ip + ":" + (System.currentTimeMillis() / 60000);
                int pings = pingCounts.merge(key, 1, Integer::sum);

                // Π—Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS - Π±ΠΎΠ»Π΅Π΅ 10 ΠΏΠΈΠ½Π³ΠΎΠ² Π² ΠΌΠΈΠ½ΡƒΡ‚Ρƒ
                if (pings > 10 && !blockedIPs.contains(ip)) {
                    blockedIPs.add(ip);
                    System.out.println("🚫 Π—Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½ IP Π·Π° спам ΠΏΠΈΠ½Π³ΠΎΠ²: " + maskIP(ip));
                    notifyAdmins("DDoS Π°Ρ‚Π°ΠΊΠ° ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½Π° с IP: " + maskIP(ip) + 
                               " (Π΄ΠΎΠΌΠ΅Π½: " + domain + ", ΠΏΠΈΠ½Π³ΠΎΠ²: " + pings + ")");

                    // АвтоматичСская Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠ° Ρ‡Π΅Ρ€Π΅Π· час
                    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
                    scheduler.schedule(() -> {
                        blockedIPs.remove(ip);
                        System.out.println("πŸ”“ IP Ρ€Π°Π·Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π½: " + maskIP(ip));
                    }, 1, TimeUnit.HOURS);
                }

                // Аналитика популярности Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²
                updateDomainPopularity(domain);

                // ГСолокация ΠΏΠΈΠ½Π³ΡƒΡŽΡ‰ΠΈΡ… IP
                analyzeIPGeolocation(ip, domain);
            }
        });

        // ΠžΡ‡ΠΈΡΡ‚ΠΊΠ° старых записСй ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ 5 ΠΌΠΈΠ½ΡƒΡ‚
        ScheduledExecutorService cleaner = Executors.newScheduledThreadPool(1);
        cleaner.scheduleAtFixedRate(() -> {
            long currentMinute = System.currentTimeMillis() / 60000;
            pingCounts.entrySet().removeIf(entry -> {
                String[] parts = entry.getKey().split(":");
                long entryMinute = Long.parseLong(parts[1]);
                return currentMinute - entryMinute > 5; // УдаляСм записи ΡΡ‚Π°Ρ€ΡˆΠ΅ 5 ΠΌΠΈΠ½ΡƒΡ‚
            });
        }, 5, 5, TimeUnit.MINUTES);
    }

    private void updateDomainPopularity(String domain) {
        // ОбновляСм Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³ популярности Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²
        api.domains().getDomainPingStats(domain).thenAccept(stats -> {
            if (stats.getTotalPings() > 1000) {
                System.out.println("🌟 ΠŸΠΎΠΏΡƒΠ»ΡΡ€Π½Ρ‹ΠΉ Π΄ΠΎΠΌΠ΅Π½: " + domain + 
                                 " (" + stats.getTotalPings() + " ΠΏΠΈΠ½Π³ΠΎΠ²)");
            }
        });
    }
}

πŸ€– Discord Π±ΠΎΡ‚ с увСдомлСниями

βŽ—
βœ“
public class DiscordIntegration {
    private final String webhookUrl = "https://discord.com/api/webhooks/...";

    public void setupBot() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        api.events().registerDomainListener(new DomainEventListener() {
            @Override
            public void onPlayerJoinDomain(DomainPlayerJoinEvent event) {
                // ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ статистику
                api.domains().getDomainInfo(event.getDomain()).ifPresent(info -> {
                    String embed = createDiscordEmbed(
                        "НовоС ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅",
                        "**Π˜Π³Ρ€ΠΎΠΊ:** " + event.getPlayerName() + "\n" +
                        "**Π”ΠΎΠΌΠ΅Π½:** " + event.getDomain() + "\n" +
                        "**Онлайн на домСнС:** " + info.getCurrentOnline(),
                        0x00FF00 // Π·Π΅Π»Π΅Π½Ρ‹ΠΉ
                    );
                    sendWebhook(embed);
                });
            }

            @Override
            public void onDomainPing(DomainPingEvent event) {
                // УвСдомлСния ΠΎ ΠΏΠΎΠ΄ΠΎΠ·Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΈΠ½Π³Π°Ρ…
                String ip = event.getPlayerIP();
                if (isSuspiciousIP(ip)) {
                    String embed = createDiscordEmbed(
                        "⚠️ ΠŸΠΎΠ΄ΠΎΠ·Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΈΠ½Π³",
                        "**Π”ΠΎΠΌΠ΅Π½:** " + event.getDomain() + "\n" +
                        "**IP:** " + maskIP(ip) + "\n" +
                        "**ВрСмя:** " + event.getTimestamp(),
                        0xFF0000 // красный
                    );
                    sendWebhook(embed);
                }
            }
        });

        // Бтатистика ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ 5 ΠΌΠΈΠ½ΡƒΡ‚
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            api.stats().getGlobalStats().thenAccept(stats -> {
                String embed = createDiscordEmbed(
                    "πŸ“Š Бтатистика сСрвСра",
                    "**ΠžΠ±Ρ‰ΠΈΠΉ ΠΎΠ½Π»Π°ΠΉΠ½:** " + stats.getTotalOnline() + "\n" +
                    "**Активных Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²:** " + stats.getTotalDomains() + "\n" +
                    "**ΠŸΠΎΠΏΡƒΠ»ΡΡ€Π½Ρ‹ΠΉ Π΄ΠΎΠΌΠ΅Π½:** " + stats.getMostPopularDomain(),
                    0xFFAA00 // ΠΎΡ€Π°Π½ΠΆΠ΅Π²Ρ‹ΠΉ
                );
                sendWebhook(embed);
            });
        }, 5, 5, TimeUnit.MINUTES);
    }
}

🌐 Π’Π΅Π±-панСль с live обновлСниями

βŽ—
βœ“
public class WebPanelIntegration {
    private final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();

    public void setupWebPanel() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        // ΠžΡ‚ΠΏΡ€Π°Π²Π»ΡΠ΅ΠΌ события Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
        api.events().registerDomainListener(new DomainEventListener() {
            @Override
            public void onPlayerJoinDomain(DomainPlayerJoinEvent event) {
                Map<String, Object> data = Map.of(
                    "type", "player_join",
                    "player", event.getPlayerName(),
                    "domain", event.getDomain(),
                    "timestamp", event.getTimestamp().toString()
                );
                broadcastToWeb(data);
            }

            @Override
            public void onDomainPing(DomainPingEvent event) {
                Map<String, Object> data = Map.of(
                    "type", "domain_ping",
                    "domain", event.getDomain(),
                    "ip", maskIP(event.getPlayerIP()),
                    "timestamp", event.getTimestamp().toString()
                );
                broadcastToWeb(data);
            }
        });

        // Бтатистика ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ 10 сСкунд
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            api.stats().getGlobalStats().thenAccept(stats -> {
                Map<String, Object> data = Map.of(
                    "type", "stats_update",
                    "totalOnline", stats.getTotalOnline(),
                    "domains", stats.getDomainDistribution(),
                    "timestamp", Instant.now().toString()
                );
                broadcastToWeb(data);
            });
        }, 0, 10, TimeUnit.SECONDS);
    }

    private void broadcastToWeb(Map<String, Object> data) {
        String json = convertToJSON(data);
        sessions.forEach(session -> {
            try {
                session.sendMessage(new TextMessage(json));
            } catch (Exception e) {
                sessions.remove(session);
            }
        });
    }
}

πŸ›‘οΈ БистСма бСзопасности

βŽ—
βœ“
public class SecuritySystem {
    private final Set<String> suspiciousIPs = ConcurrentHashMap.newKeySet();
    private final Map<String, Integer> connectionCounts = new ConcurrentHashMap<>();

    public void setupSecurity() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        api.events().registerPlayerListener(new PlayerEventListener() {
            @Override
            public void onPlayerConnect(PlayerConnectEvent event) {
                String ip = event.getPlayerIP();
                String player = event.getPlayerName();

                // ΠŸΠΎΠ΄ΡΡ‡Π΅Ρ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ с IP
                int connections = connectionCounts.merge(ip, 1, Integer::sum);

                // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π° мноТСствСнныС ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
                if (connections > 3) {
                    System.out.println("⚠️ ΠŸΠΎΠ΄ΠΎΠ·Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ с IP: " + maskIP(ip) + 
                                     " (" + connections + " ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ)");
                    suspiciousIPs.add(ip);
                    notifyAdmins("ΠŸΠΎΠ΄ΠΎΠ·Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ IP: " + maskIP(ip) + " (ΠΈΠ³Ρ€ΠΎΠΊ: " + player + ")");
                }

                // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π° VPN (асинхронно)
                CompletableFuture.runAsync(() -> checkVPN(ip, player));

                // Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ всСх ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ
                logConnection(player, event.getDomain(), ip, event.getTimestamp());
            }

            @Override
            public void onPlayerDisconnect(PlayerDisconnectEvent event) {
                // ΠžΡ‡ΠΈΡΡ‚ΠΊΠ° счСтчика Ρ‡Π΅Ρ€Π΅Π· 5 ΠΌΠΈΠ½ΡƒΡ‚
                ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
                scheduler.schedule(() -> {
                    connectionCounts.remove(event.getPlayerIP());
                }, 5, TimeUnit.MINUTES);
            }
        });

        // ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ ΠΏΠΎΠ΄ΠΎΠ·Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΈΠ½Π³ΠΎΠ²
        api.events().registerDomainListener(new DomainEventListener() {
            @Override
            public void onDomainPing(DomainPingEvent event) {
                String ip = event.getPlayerIP();

                // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ, Π½Π΅ Π² Ρ‡Π΅Ρ€Π½ΠΎΠΌ Π»ΠΈ спискС IP
                if (suspiciousIPs.contains(ip)) {
                    System.out.println("🚫 Пинг ΠΎΡ‚ ΠΏΠΎΠ΄ΠΎΠ·Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ IP: " + maskIP(ip));
                    // МоТно Π·Π°Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΠ»ΠΈ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΡŒ
                }
            }
        });
    }

    private void checkVPN(String ip, String player) {
        // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ‡Π΅Ρ€Π΅Π· VPN API (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, IPQualityScore)
        boolean isVPN = callVPNAPI(ip);
        if (isVPN) {
            System.out.println("🚫 VPN ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½: " + player + " (" + maskIP(ip) + ")");
            notifyAdmins("VPN ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅: " + player + " с IP " + maskIP(ip));
        }
    }
}

πŸ“ˆ БистСма Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ

βŽ—
βœ“
public class AnalyticsSystem {
    private final Map<String, DomainAnalytics> domainStats = new ConcurrentHashMap<>();

    public void setupAnalytics() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        api.events().registerDomainListener(new DomainEventListener() {
            @Override
            public void onPlayerJoinDomain(DomainPlayerJoinEvent event) {
                String domain = event.getDomain();

                domainStats.computeIfAbsent(domain, k -> new DomainAnalytics())
                          .recordJoin(event.getTimestamp());

                // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΈΠΊΠΎΠ²Ρ‹Π΅ значСния
                api.domains().getDomainInfo(domain).ifPresent(info -> {
                    int currentOnline = info.getCurrentOnline();
                    DomainAnalytics analytics = domainStats.get(domain);

                    if (currentOnline > analytics.getPeakOnline()) {
                        analytics.setPeakOnline(currentOnline);
                        System.out.println("πŸŽ‰ Новый Ρ€Π΅ΠΊΠΎΡ€Π΄ для " + domain + ": " + currentOnline + " ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²!");

                        // Π£Π²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ Π² Discord
                        sendDiscordMessage("πŸŽ‰ **Новый Ρ€Π΅ΠΊΠΎΡ€Π΄!**\n" +
                                         "Π”ΠΎΠΌΠ΅Π½ `" + domain + "` достиг **" + currentOnline + "** ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΎΠ½Π»Π°ΠΉΠ½!");
                    }
                });
            }

            @Override
            public void onDomainPing(DomainPingEvent event) {
                String domain = event.getDomain();

                // Аналитика ΠΏΠΈΠ½Π³ΠΎΠ²
                domainStats.computeIfAbsent(domain, k -> new DomainAnalytics())
                          .recordPing(event.getTimestamp());

                // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΎΠΏΡƒΠ»ΡΡ€Π½ΠΎΡΡ‚ΡŒ ΠΏΠΎ ΠΏΠΈΠ½Π³Π°ΠΌ
                api.domains().getDomainPingStats(domain).thenAccept(pingStats -> {
                    if (pingStats.getTotalPings() % 100 == 0) { // ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ 100 ΠΏΠΈΠ½Π³ΠΎΠ²
                        System.out.println("πŸ“Š Π”ΠΎΠΌΠ΅Π½ " + domain + " достиг " + 
                                         pingStats.getTotalPings() + " ΠΏΠΈΠ½Π³ΠΎΠ²!");
                    }
                });
            }
        });

        // Π•ΠΆΠ΅Π΄Π½Π΅Π²Π½Ρ‹ΠΉ ΠΎΡ‚Ρ‡Π΅Ρ‚
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(this::generateDailyReport, 0, 24, TimeUnit.HOURS);
    }

    private void generateDailyReport() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        api.stats().getGlobalStats().thenAccept(stats -> {
            StringBuilder report = new StringBuilder();
            report.append("πŸ“Š **Π•ΠΆΠ΅Π΄Π½Π΅Π²Π½Ρ‹ΠΉ ΠΎΡ‚Ρ‡Π΅Ρ‚**\n\n");
            report.append("**ΠžΠ±Ρ‰Π°Ρ статистика:**\n");
            report.append("β€’ ΠŸΠΈΠΊΠΎΠ²Ρ‹ΠΉ ΠΎΠ½Π»Π°ΠΉΠ½: ").append(stats.getTotalOnline()).append("\n");
            report.append("β€’ Активных Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²: ").append(stats.getTotalDomains()).append("\n");
            report.append("β€’ ΠŸΠΎΠΏΡƒΠ»ΡΡ€Π½Ρ‹ΠΉ Π΄ΠΎΠΌΠ΅Π½: ").append(stats.getMostPopularDomain()).append("\n\n");

            report.append("**Π’ΠΎΠΏ Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΏΠΎ ΠΎΠ½Π»Π°ΠΉΠ½Ρƒ:**\n");
            api.stats().getTopDomainsByOnline(5).thenAccept(top -> {
                top.forEach((domain, online) -> {
                    report.append("β€’ `").append(domain).append("`: ").append(online).append(" ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²\n");
                });

                // ДобавляСм статистику ΠΏΠΈΠ½Π³ΠΎΠ²
                report.append("\n**Π’ΠΎΠΏ Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΏΠΎ ΠΏΠΈΠ½Π³Π°ΠΌ:**\n");
                CompletableFuture.allOf(
                    top.keySet().stream()
                        .map(domain -> api.domains().getDomainPingStats(domain, 1)
                            .thenAccept(pingStats -> {
                                report.append("β€’ `").append(domain).append("`: ")
                                      .append(pingStats.getTotalPings()).append(" пингов за дСнь\n");
                            }))
                        .toArray(CompletableFuture[]::new)
                ).thenRun(() -> {
                    sendDiscordMessage(report.toString());
                    saveReportToFile(report.toString());
                });
            });
        });
    }
}

πŸ“‹ Π‘ΠΏΡ€Π°Π²ΠΎΡ‡Π½ΠΈΠΊ Data классов

DomainInfo

βŽ—
βœ“
1
2
3
4
5
6
7
8
public class DomainInfo {
    String getDomain()                    // НазваниС домСна
    int getCurrentOnline()                // Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΎΠ½Π»Π°ΠΉΠ½
    List<String> getOnlinePlayers()       // Бписок ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΎΠ½Π»Π°ΠΉΠ½
    boolean isActive()                    // АктивСн Π»ΠΈ Π΄ΠΎΠΌΠ΅Π½
```java
    LocalDateTime getLastActivity()       // ВрСмя послСднСй активности
}

DomainStats

βŽ—
βœ“
1
2
3
4
5
6
7
8
public class DomainStats {
    String getDomain()                    // НазваниС домСна
    int getTotalConnections()             // ВсСго ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄
    int getUniqueePlayers()               // Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄
    int getCurrentOnline()                // Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΎΠ½Π»Π°ΠΉΠ½ (сСрвис)
    int getDatabaseOnline()               // Онлайн Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…
    boolean isSynced()                    // Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹ Π»ΠΈ Π΄Π°Π½Π½Ρ‹Π΅
}

DomainPingInfo

βŽ—
βœ“
1
2
3
4
5
public class DomainPingInfo {
    String getDomain()                    // НазваниС домСна
    String getPlayerIP()                  // IP адрСс ΠΏΠΈΠ½Π³ΡƒΡŽΡ‰Π΅Π³ΠΎ
    LocalDateTime getTimestamp()          // ВрСмя ΠΏΠΈΠ½Π³Π°
}

DomainPingStats

βŽ—
βœ“
1
2
3
4
5
6
7
public class DomainPingStats {
    String getDomain()                    // НазваниС домСна
    int getTotalPings()                   // ΠžΠ±Ρ‰Π΅Π΅ количСство ΠΏΠΈΠ½Π³ΠΎΠ²
    int getUniqueIPs()                    // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… IP
    LocalDateTime getFirstPing()          // ВрСмя ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΏΠΈΠ½Π³Π°
    LocalDateTime getLastPing()           // ВрСмя послСднСго ΠΏΠΈΠ½Π³Π°
}

PlayerInfo

βŽ—
βœ“
public class PlayerInfo {
    String getPlayerName()                // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
    UUID getPlayerUuid()                  // UUID ΠΈΠ³Ρ€ΠΎΠΊΠ°
    String getCurrentDomain()             // Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ Π΄ΠΎΠΌΠ΅Π½ (null Ссли ΠΎΡ„Ρ„Π»Π°ΠΉΠ½)
    String getLastKnownIP()               // ПослСдний извСстный IP
    LocalDateTime getFirstJoin()          // ВрСмя ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
    LocalDateTime getLastJoin()           // ВрСмя послСднСго ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
    int getTotalJoins()                   // ΠžΠ±Ρ‰Π΅Π΅ количСство ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ
    boolean isOnline()                    // Онлайн Π»ΠΈ ΠΈΠ³Ρ€ΠΎΠΊ сСйчас
}

PlayerHistory

βŽ—
βœ“
1
2
3
4
5
6
public class PlayerHistory {
    String getDomain()                    // Π”ΠΎΠΌΠ΅Π½ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
    String getPlayerIP()                  // IP адрСс
    LocalDateTime getJoinTime()           // ВрСмя ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
    int getTotalJoinsOnDomain()           // ВсСго ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ ΠΊ этому Π΄ΠΎΠΌΠ΅Π½Ρƒ
}

LocationHistory

βŽ—
βœ“
public class LocationHistory {
    String getPlayerName()                // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
    String getPlayerUuid()                // UUID ΠΈΠ³Ρ€ΠΎΠΊΠ°
    String getDomain()                    // Π”ΠΎΠΌΠ΅Π½
    String getPlayerIP()                  // IP адрСс
    String getLocation()                  // ΠœΠ΅ΡΡ‚ΠΎΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ (Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅)
    String getCountryCode()               // Код страны (RU, US, etc.)
    String getCity()                      // Π“ΠΎΡ€ΠΎΠ΄
    LocalDateTime getTimestamp()          // ВрСмя записи
    boolean isCurrentLocation()           // Π’Π΅ΠΊΡƒΡ‰Π΅Π΅ Π»ΠΈ это мСстополоТСниС
}

GlobalStats

βŽ—
βœ“
1
2
3
4
5
6
7
public class GlobalStats {
    int getTotalOnline()                  // ΠžΠ±Ρ‰ΠΈΠΉ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° всСх Π΄ΠΎΠΌΠ΅Π½Π°Ρ…
    int getTotalDomains()                 // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Ρ… Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²
    int getTotalPlayersInDatabase()       // ВсСго ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…
    Map<String, Integer> getDomainDistribution()  // РаспрСдСлСниС ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΏΠΎ Π΄ΠΎΠΌΠ΅Π½Π°ΠΌ
    String getMostPopularDomain()         // Π‘Π°ΠΌΡ‹ΠΉ популярный Π΄ΠΎΠΌΠ΅Π½
}

🎯 Бобытия - ΠΏΠΎΠ»Π½Ρ‹ΠΉ список

DomainPlayerJoinEvent

βŽ—
βœ“
1
2
3
4
5
String getPlayerName()                   // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
String getDomain()                       // Π”ΠΎΠΌΠ΅Π½
String getPlayerIP()                     // IP адрСс
LocalDateTime getTimestamp()             // ВрСмя события
int getNewOnlineCount()                  // НовоС количСство ΠΎΠ½Π»Π°ΠΉΠ½

DomainPlayerLeaveEvent

βŽ—
βœ“
1
2
3
4
5
String getPlayerName()                   // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
String getDomain()                       // Π”ΠΎΠΌΠ΅Π½
String getPlayerIP()                     // IP адрСс
LocalDateTime getTimestamp()             // ВрСмя события
int getNewOnlineCount()                  // НовоС количСство ΠΎΠ½Π»Π°ΠΉΠ½

DomainPingEvent

βŽ—
βœ“
1
2
3
String getDomain()                       // Π”ΠΎΠΌΠ΅Π½
String getPlayerIP()                     // IP адрСс ΠΏΠΈΠ½Π³ΡƒΡŽΡ‰Π΅Π³ΠΎ
LocalDateTime getTimestamp()             // ВрСмя ΠΏΠΈΠ½Π³Π°

PlayerConnectEvent

βŽ—
βœ“
1
2
3
4
5
6
String getPlayerName()                   // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
UUID getPlayerUuid()                     // UUID ΠΈΠ³Ρ€ΠΎΠΊΠ°
String getPlayerIP()                     // IP адрСс
String getDomain()                       // Π”ΠΎΠΌΠ΅Π½ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
LocalDateTime getTimestamp()             // ВрСмя ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
boolean isFirstJoin()                    // ΠŸΠ΅Ρ€Π²ΠΎΠ΅ Π»ΠΈ это ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

PlayerDisconnectEvent

βŽ—
βœ“
1
2
3
4
5
6
String getPlayerName()                   // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
UUID getPlayerUuid()                     // UUID ΠΈΠ³Ρ€ΠΎΠΊΠ°
String getPlayerIP()                     // IP адрСс
String getDomain()                       // Π”ΠΎΠΌΠ΅Π½ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
LocalDateTime getTimestamp()             // ВрСмя ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ
long getSessionDuration()                // Π”Π»ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ сСссии (мс)

PlayerSwitchDomainEvent

βŽ—
βœ“
1
2
3
4
5
6
String getPlayerName()                   // Ник ΠΈΠ³Ρ€ΠΎΠΊΠ°
UUID getPlayerUuid()                     // UUID ΠΈΠ³Ρ€ΠΎΠΊΠ°
String getPlayerIP()                     // IP адрСс
String getFromDomain()                   // Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ Π΄ΠΎΠΌΠ΅Π½
String getToDomain()                     // Π¦Π΅Π»Π΅Π²ΠΎΠΉ Π΄ΠΎΠΌΠ΅Π½
LocalDateTime getTimestamp()             // ВрСмя ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ

πŸ”§ Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ возмоТности API

ГСолокация ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ²

βŽ—
βœ“
// Если Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π° гСолокация Π² ΠΏΠ»Π°Π³ΠΈΠ½Π΅
api.players().getPlayerInfo("Player1").thenAccept(playerOpt -> {
    if (playerOpt.isPresent()) {
        PlayerInfo player = playerOpt.get();

        // ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΈΡΡ‚ΠΎΡ€ΠΈΡŽ мСстополоТСний
        getLocationHistory(player.getPlayerUuid()).thenAccept(history -> {
            System.out.println("Π˜ΡΡ‚ΠΎΡ€ΠΈΡ мСстополоТСний " + player.getPlayerName() + ":");
            history.forEach(location -> {
                System.out.println("Π”ΠΎΠΌΠ΅Π½: " + location.getDomain() + 
                                 " | Локация: " + location.getLocation() + 
                                 " | ВрСмя: " + location.getTimestamp());
            });
        });
    }
});

ΠŸΠ°ΠΊΠ΅Ρ‚Π½Π°Ρ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ…

βŽ—
βœ“
// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ статистики всСх Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ
api.stats().getAllDomainStats().thenAccept(allStats -> {
    // Анализ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π΄ΠΎΠΌΠ΅Π½ΠΎΠ²
    allStats.entrySet().stream()
        .sorted((e1, e2) -> Integer.compare(e2.getValue().getCurrentOnline(), 
                                          e1.getValue().getCurrentOnline()))
        .limit(10)
        .forEach(entry -> {
            String domain = entry.getKey();
            DomainStats stats = entry.getValue();

            System.out.println("Π’ΠΎΠΏ Π΄ΠΎΠΌΠ΅Π½: " + domain + 
                             " (ΠΎΠ½Π»Π°ΠΉΠ½: " + stats.getCurrentOnline() + 
                             ", ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ: " + stats.getTotalConnections() + ")");
        });
});

// МассовоС ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ статистики ΠΏΠΈΠ½Π³ΠΎΠ²
List<String> domains = List.of("example.com", "test.net", "demo.org");
CompletableFuture.allOf(
    domains.stream()
        .map(domain -> api.domains().getDomainPingStats(domain)
            .thenAccept(pingStats -> {
                System.out.println(domain + " - ΠΏΠΈΠ½Π³ΠΎΠ²: " + pingStats.getTotalPings());
            }))
        .toArray(CompletableFuture[]::new)
).thenRun(() -> {
    System.out.println("Анализ ΠΏΠΈΠ½Π³ΠΎΠ² Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½!");
});

ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹Π΅ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΈ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠ°

βŽ—
βœ“
// Π€ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡ ΠΈΠ³Ρ€ΠΎΠΊΠΎΠ² ΠΏΠΎ критСриям
api.players().getOnlinePlayers().stream()
    .map(playerName -> api.players().getPlayerInfo(playerName))
    .map(CompletableFuture::join)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .filter(player -> player.getTotalJoins() > 100) // АктивныС ΠΈΠ³Ρ€ΠΎΠΊΠΈ
    .forEach(player -> {
        System.out.println("Активный ΠΈΠ³Ρ€ΠΎΠΊ: " + player.getPlayerName() + 
                         " (Π·Π°Ρ…ΠΎΠ΄ΠΎΠ²: " + player.getTotalJoins() + ")");
    });

// Анализ популярности Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΏΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
Map<String, List<LocalDateTime>> domainActivity = new HashMap<>();
api.events().registerDomainListener(new DomainEventListener() {
    @Override
    public void onPlayerJoinDomain(DomainPlayerJoinEvent event) {
        domainActivity.computeIfAbsent(event.getDomain(), k -> new ArrayList<>())
                     .add(event.getTimestamp());

        // Анализ ΠΏΠΈΠΊΠΎΠ²Ρ‹Ρ… часов ΠΊΠ°ΠΆΠ΄Ρ‹Π΅ 100 ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ
        List<LocalDateTime> activity = domainActivity.get(event.getDomain());
        if (activity.size() % 100 == 0) {
            analyzePeakHours(event.getDomain(), activity);
        }
    }
});

⚠️ Π’Π°ΠΆΠ½Ρ‹Π΅ Π·Π°ΠΌΠ΅Ρ‚ΠΊΠΈ

ΠΡΠΈΠ½Ρ…Ρ€ΠΎΠ½Π½ΠΎΡΡ‚ΡŒ

  • ВсС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΠ΅ CompletableFuture, Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ асинхронно
  • НС Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠΉΡ‚Π΅ основной ΠΏΠΎΡ‚ΠΎΠΊ сСрвСра
  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ .thenAccept(), .thenApply() для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° доступности

βŽ—
βœ“
1
2
3
4
5
6
// ВсСгда провСряйтС Π΄ΠΎΡΡ‚ΡƒΠΏΠ½ΠΎΡΡ‚ΡŒ API
DomainInfoAPI api = DomainInfoAPI.getInstance();
if (api == null || !api.isAvailable()) {
    // API нСдоступно
    return;
}

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок

βŽ—
βœ“
1
2
3
4
api.domains().getDomainStats("example.com").exceptionally(throwable -> {
    System.err.println("Ошибка получСния статистики: " + throwable.getMessage());
    return null; // ΠΈΠ»ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
});

Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ рСсурсами

βŽ—
βœ“
// ΠŸΡ€Π°Π²ΠΈΠ»ΡŒΠ½Π°Ρ ΠΎΡ‚ΠΌΠ΅Π½Π° рСгистрации ΡΠ»ΡƒΡˆΠ°Ρ‚Π΅Π»Π΅ΠΉ
public class MyPlugin {
    private DomainEventListener domainListener;
    private PlayerEventListener playerListener;

    public void onEnable() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();

        domainListener = new DomainEventListener() { /* ... */ };
        playerListener = new PlayerEventListener() { /* ... */ };

        api.events().registerDomainListener(domainListener);
        api.events().registerPlayerListener(playerListener);
    }

    public void onDisable() {
        DomainInfoAPI api = DomainInfoAPI.getInstance();
        if (api != null && api.isAvailable()) {
            api.events().unregisterDomainListener(domainListener);
            api.events().unregisterPlayerListener(playerListener);
        }
    }
}

πŸ“¦ Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ API ΠΊΠ°ΠΊ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒ

Maven

βŽ—
βœ“
1
2
3
4
5
6
7
<dependency>
    <groupId>ua.tyulpan</groupId>
    <artifactId>eeDomainInfo</artifactId>
    <version>VERSION</version>
    <scope>system</scope>
    <systemPath>path/to/eeDomainInfo-VERSION.jar</systemPath>
</dependency>

Gradle

βŽ—
βœ“
1
2
3
dependencies {
    compileOnly files('path/to/eeDomainInfo-VERSION.jar')
}

Базовая структура ΠΏΠ»Π°Π³ΠΈΠ½Π°

βŽ—
βœ“
@Plugin(id = "mydomainplugin", name = "MyDomainPlugin", version = "1.0.0")
public class MyDomainPlugin {

    @Subscribe
    public void onProxyInitialization(ProxyInitializeEvent event) {
        // Π–Π΄Π΅ΠΌ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ eeDomainInfo
        ProxyServer.getInstance().getScheduler().buildTask(this, () -> {
            DomainInfoAPI api = DomainInfoAPI.getInstance();
            if (api != null && api.isAvailable()) {
                setupAPI(api);
            } else {
                getLogger().warn("eeDomainInfo API нСдоступно!");
            }
        }).delay(1, TimeUnit.SECONDS).schedule();
    }

    private void setupAPI(DomainInfoAPI api) {
        getLogger().info("eeDomainInfo API ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ! ВСрсия: " + api.getAPIVersion());

        // Π’Π°Ρˆ ΠΊΠΎΠ΄ здСсь
        api.events().registerDomainListener(new DomainEventListener() {
            @Override
            public void onPlayerJoinDomain(DomainPlayerJoinEvent event) {
                getLogger().info("Π˜Π³Ρ€ΠΎΠΊ " + event.getPlayerName() + 
                               " ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΠ»ΡΡ ΠΊ " + event.getDomain());
            }
        });
    }
}

πŸš€ ΠŸΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΈ оптимизация

ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ…

βŽ—
βœ“
// ΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ часто Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌΡ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…
private final Map<String, DomainStats> statsCache = new ConcurrentHashMap<>();
private final long CACHE_TTL = 30000; // 30 сСкунд

public CompletableFuture<DomainStats> getCachedDomainStats(String domain) {
    DomainStats cached = statsCache.get(domain);
    if (cached != null && System.currentTimeMillis() - cached.getTimestamp() < CACHE_TTL) {
        return CompletableFuture.completedFuture(cached);
    }

    return api.domains().getDomainStats(domain).thenApply(stats -> {
        statsCache.put(domain, stats);
        return stats;
    });
}

Π‘Π°Ρ‚Ρ‡ΠΈΠ½Π³ запросов

βŽ—
βœ“
// Π“Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ° запросов для сниТСния Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ
private final Map<String, CompletableFuture<DomainStats>> pendingRequests = new ConcurrentHashMap<>();

public CompletableFuture<DomainStats> getBatchedDomainStats(String domain) {
    return pendingRequests.computeIfAbsent(domain, d -> {
        return api.domains().getDomainStats(d).whenComplete((result, throwable) -> {
            // УдаляСм ΠΈΠ· pending послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ
            pendingRequests.remove(d);
        });
    });
}

Π‘Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ

  • ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, маскируйтС IP адрСса ΠΏΡ€ΠΈ Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ: 192.168.1.1 β†’ 192.168.*.*
  • НС Π»ΠΎΠ³ΠΈΡ€ΡƒΠΉΡ‚Π΅ UUID Π² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΎΠΌ Π²ΠΈΠ΄Π΅ (ΠΏΠΎ возмоТности)
  • НС Π΄ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ людям Π² ΠΈΠ½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Π΅ (ΠΆΠ΅Π»Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ)
  • Π’Π°Π»ΠΈΠ΄ΠΈΡ€ΡƒΠΉΡ‚Π΅ Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅Π΄ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ Π² API

Β© 2025 tyulpan | eeDomainInfo API v1.3.0

ДокумСнтация ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π° для вСрсии с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ ΠΏΠΈΠ½Π³ΠΎΠ² Π΄ΠΎΠΌΠ΅Π½ΠΎΠ² ΠΈ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½Π½ΠΎΠΉ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ

Edit

Pub: 05 Aug 2025 22:13 UTC

Edit: 08 Sep 2025 20:29 UTC

Views: 52