001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.bukkit.uuid;
020
021import com.google.common.util.concurrent.RateLimiter;
022import com.plotsquared.core.configuration.Settings;
023import com.plotsquared.core.uuid.UUIDMapping;
024import com.plotsquared.core.uuid.UUIDService;
025import org.apache.logging.log4j.LogManager;
026import org.apache.logging.log4j.Logger;
027import org.checkerframework.checker.nullness.qual.NonNull;
028import org.enginehub.squirrelid.Profile;
029import org.enginehub.squirrelid.resolver.HttpRepositoryService;
030import org.enginehub.squirrelid.resolver.ProfileService;
031
032import java.io.IOException;
033import java.util.ArrayList;
034import java.util.Collections;
035import java.util.List;
036import java.util.UUID;
037
038/**
039 * UUID service using SquirrelID
040 */
041@SuppressWarnings("UnstableApiUsage")
042public class SquirrelIdUUIDService implements UUIDService {
043
044    private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SquirrelIdUUIDService.class.getSimpleName());
045
046    private final ProfileService profileService;
047    private final RateLimiter rateLimiter;
048
049    /**
050     * Create a new SquirrelID UUID service
051     *
052     * @param rateLimit Mojangs rate limit is 600 requests per 10 minutes.
053     *                  This parameter specifies how many of those requests
054     *                  we can use before our internal rate limit kicks in.
055     */
056    public SquirrelIdUUIDService(final int rateLimit) {
057        this.profileService = HttpRepositoryService.forMinecraft();
058        // RateLimiter uses request per seconds. The constructor
059        // parameter rateLimit is requests per 600 seconds
060        this.rateLimiter = RateLimiter.create(rateLimit / 600.0D);
061    }
062
063    @Override
064    public @NonNull List<UUIDMapping> getNames(final @NonNull List<UUID> uuids) {
065        final List<UUIDMapping> results = new ArrayList<>(uuids.size());
066        this.rateLimiter.acquire(uuids.size());
067        try {
068            try {
069                for (final Profile profile : this.profileService.findAllByUuid(uuids)) {
070                    results.add(new UUIDMapping(profile.getUniqueId(), profile.getName()));
071                }
072            } catch (final IllegalArgumentException illegalArgumentException) {
073                //
074                // This means that the UUID was invalid for whatever reason, we'll try to
075                // go through them one by one
076                //
077                if (uuids.size() >= 2) {
078                    if (Settings.DEBUG) {
079                        LOGGER.info("(UUID) Found invalid UUID in batch. Will try each UUID individually.");
080                    }
081                    for (final UUID uuid : uuids) {
082                        final List<UUIDMapping> result = this.getNames(Collections.singletonList(uuid));
083                        if (result.isEmpty()) {
084                            continue;
085                        }
086                        results.add(result.get(0));
087                    }
088                } else if (uuids.size() == 1 && Settings.DEBUG) {
089                    LOGGER.info("(UUID) Found invalid UUID: {}", uuids.get(0));
090                }
091            }
092        } catch (IOException | InterruptedException e) {
093            e.printStackTrace();
094        }
095        return results;
096    }
097
098    @Override
099    public @NonNull List<UUIDMapping> getUUIDs(final @NonNull List<String> usernames) {
100        final List<UUIDMapping> results = new ArrayList<>(usernames.size());
101        this.rateLimiter.acquire(usernames.size());
102        try {
103            for (final Profile profile : this.profileService.findAllByName(usernames)) {
104                results.add(new UUIDMapping(profile.getUniqueId(), profile.getName()));
105            }
106        } catch (IOException | InterruptedException e) {
107            e.printStackTrace();
108        }
109        return results;
110    }
111
112}