/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to
*/
package com.imaginarycode.minecraft.redisbungee;
import com.google.common.base.Functions;
import com.google.common.collect.*;
import com.google.common.io.ByteStreams;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.util.LuaManager;
import com.imaginarycode.minecraft.redisbungee.util.NameFetcher;
import com.imaginarycode.minecraft.redisbungee.util.UUIDFetcher;
import com.imaginarycode.minecraft.redisbungee.util.UUIDTranslator;
import com.squareup.okhttp.Dispatcher;
import com.squareup.okhttp.OkHttpClient;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import static com.google.common.base.Preconditions.checkArgument;
/**
* The RedisBungee plugin.
*
* The only function of interest is {@link #getApi()}, which exposes some functions in this class.
*/
public final class RedisBungee extends Plugin {
@Getter
private static Gson gson = new Gson();
private static RedisBungeeAPI api;
@Getter(AccessLevel.PACKAGE)
private static PubSubListener psl = null;
@Getter
private JedisPool pool;
@Getter
private UUIDTranslator uuidTranslator;
@Getter(AccessLevel.PACKAGE)
private static RedisBungeeConfiguration configuration;
@Getter
private DataManager dataManager;
@Getter
private ExecutorService service;
@Getter
private static OkHttpClient httpClient;
private List serverIds;
private AtomicInteger nagAboutServers = new AtomicInteger();
private ScheduledTask integrityCheck;
private ScheduledTask heartbeatTask;
private boolean usingLua;
private LuaManager.Script serverToPlayersScript;
/**
* Fetch the {@link RedisBungeeAPI} object created on plugin start.
*
* @return the {@link RedisBungeeAPI} object
*/
public static RedisBungeeAPI getApi() {
return api;
}
static PubSubListener getPubSubListener() {
return psl;
}
final List getServerIds() {
return serverIds;
}
final List getCurrentServerIds() {
try (Jedis jedis = pool.getResource()) {
int nag = nagAboutServers.decrementAndGet();
if (nag <= 0) {
nagAboutServers.set(10);
}
ImmutableList.Builder servers = ImmutableList.builder();
Map heartbeats = jedis.hgetAll("heartbeats");
for (Map.Entry entry : heartbeats.entrySet()) {
try {
long stamp = Long.parseLong(entry.getValue());
if (System.currentTimeMillis() < stamp + 30000)
servers.add(entry.getKey());
else if (nag <= 0) {
getLogger().severe(entry.getKey() + " is " + (System.currentTimeMillis() - stamp) + "ms behind! (Time not synchronized or server down?)");
}
} catch (NumberFormatException ignored) {
}
}
return servers.build();
} catch (JedisConnectionException e) {
getLogger().log(Level.SEVERE, "Unable to fetch all server IDs", e);
return Collections.singletonList(configuration.getServerId());
}
}
final Multimap serversToPlayers() {
if (usingLua) {
String string = (String) serverToPlayersScript.eval(ImmutableList.of(), getServerIds());
Map> deserialized = gson.fromJson(string, new TypeToken