2022-04-13 18:17:38 +00:00
package com.imaginarycode.minecraft.redisbungee ;
import com.google.common.cache.Cache ;
import com.google.common.cache.CacheBuilder ;
import com.google.common.collect.ImmutableList ;
import com.google.common.collect.ImmutableMultimap ;
import com.google.common.collect.ImmutableSet ;
import com.google.common.collect.Multimap ;
import com.google.common.io.ByteStreams ;
2022-04-13 21:56:17 +00:00
import com.imaginarycode.minecraft.redisbungee.commands.RedisBungeeCommands ;
2022-04-14 11:59:02 +00:00
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent ;
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent ;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent ;
2022-04-13 18:17:38 +00:00
import com.imaginarycode.minecraft.redisbungee.internal.* ;
2022-07-16 05:18:33 +00:00
import com.imaginarycode.minecraft.redisbungee.internal.summoners.Summoner ;
2022-07-06 19:04:09 +00:00
import com.imaginarycode.minecraft.redisbungee.internal.summoners.SinglePoolJedisSummoner ;
2022-04-13 18:17:38 +00:00
import com.imaginarycode.minecraft.redisbungee.internal.util.IOUtil ;
import com.imaginarycode.minecraft.redisbungee.internal.util.LuaManager ;
import com.imaginarycode.minecraft.redisbungee.internal.util.uuid.NameFetcher ;
import com.imaginarycode.minecraft.redisbungee.internal.util.uuid.UUIDFetcher ;
import com.imaginarycode.minecraft.redisbungee.internal.util.uuid.UUIDTranslator ;
import com.squareup.okhttp.Dispatcher ;
import com.squareup.okhttp.OkHttpClient ;
import net.md_5.bungee.api.ProxyServer ;
import net.md_5.bungee.api.connection.ProxiedPlayer ;
import net.md_5.bungee.api.plugin.Event ;
import net.md_5.bungee.api.plugin.Plugin ;
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.Pipeline ;
import redis.clients.jedis.exceptions.JedisConnectionException ;
import java.io.* ;
import java.lang.reflect.Field ;
import java.net.InetAddress ;
2022-07-08 02:47:50 +00:00
import java.nio.file.Files ;
2022-04-13 18:17:38 +00:00
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 ;
public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin < ProxiedPlayer > {
private RedisBungeeAPI api ;
private PubSubListener psl = null ;
2022-07-16 05:18:33 +00:00
private Summoner jedisSummoner ;
2022-04-13 18:17:38 +00:00
private UUIDTranslator uuidTranslator ;
private RedisBungeeConfiguration configuration ;
private BungeeDataManager dataManager ;
private OkHttpClient httpClient ;
private volatile List < String > serverIds ;
private final AtomicInteger nagAboutServers = new AtomicInteger ( ) ;
private final AtomicInteger globalPlayerCount = new AtomicInteger ( ) ;
private Future < ? > integrityCheck ;
private Future < ? > heartbeatTask ;
private LuaManager . Script serverToPlayersScript ;
private LuaManager . Script getPlayerCountScript ;
private static final Object SERVER_TO_PLAYERS_KEY = new Object ( ) ;
private final Cache < Object , Multimap < String , UUID > > serverToPlayersCache = CacheBuilder . newBuilder ( )
. expireAfterWrite ( 5 , TimeUnit . SECONDS )
. build ( ) ;
@Override
public RedisBungeeConfiguration getConfiguration ( ) {
return this . configuration ;
}
@Override
public int getCount ( ) {
return this . globalPlayerCount . get ( ) ;
}
@Override
public int getCurrentCount ( ) {
2022-07-08 02:47:50 +00:00
Long count = ( Long ) getPlayerCountScript . eval ( ImmutableList . of ( ) , ImmutableList . of ( ) ) ;
2022-04-13 18:17:38 +00:00
return count . intValue ( ) ;
}
@Override
public Set < String > getLocalPlayersAsUuidStrings ( ) {
ImmutableSet . Builder < String > builder = ImmutableSet . builder ( ) ;
for ( ProxiedPlayer player : getProxy ( ) . getPlayers ( ) ) {
builder . add ( player . getUniqueId ( ) . toString ( ) ) ;
}
return builder . build ( ) ;
}
@Override
2022-07-07 22:39:05 +00:00
public AbstractDataManager < ProxiedPlayer , ? , ? , ? > getDataManager ( ) {
2022-04-13 18:17:38 +00:00
return this . dataManager ;
}
@Override
public Set < UUID > getPlayers ( ) {
ImmutableSet . Builder < UUID > setBuilder = ImmutableSet . builder ( ) ;
if ( isJedisAvailable ( ) ) {
try ( Jedis rsc = requestJedis ( ) ) {
List < String > keys = new ArrayList < > ( ) ;
for ( String i : getServerIds ( ) ) {
keys . add ( " proxy: " + i + " :usersOnline " ) ;
}
if ( ! keys . isEmpty ( ) ) {
2022-07-08 02:47:50 +00:00
Set < String > users = rsc . sunion ( keys . toArray ( new String [ 0 ] ) ) ;
2022-04-13 18:17:38 +00:00
if ( users ! = null & & ! users . isEmpty ( ) ) {
for ( String user : users ) {
try {
setBuilder = setBuilder . add ( UUID . fromString ( user ) ) ;
} catch ( IllegalArgumentException ignored ) {
}
}
}
}
} catch ( JedisConnectionException e ) {
// Redis server has disappeared!
getLogger ( ) . log ( Level . SEVERE , " Unable to get connection from pool - did your Redis server go away? " , e ) ;
throw new RuntimeException ( " Unable to get all players online " , e ) ;
}
}
return setBuilder . build ( ) ;
}
@Override
public Jedis requestJedis ( ) {
2022-07-06 19:04:09 +00:00
return this . jedisSummoner . requestJedis ( ) ;
2022-04-13 18:17:38 +00:00
}
@Override
public boolean isJedisAvailable ( ) {
2022-07-06 19:04:09 +00:00
return this . jedisSummoner . isJedisAvailable ( ) ;
2022-04-14 10:34:56 +00:00
}
2022-04-13 18:17:38 +00:00
@Override
public RedisBungeeAPI getApi ( ) {
return this . api ;
}
@Override
public UUIDTranslator getUuidTranslator ( ) {
return this . uuidTranslator ;
}
@Override
2022-07-08 02:47:50 +00:00
@SuppressWarnings ( " unchecked " )
2022-04-13 18:17:38 +00:00
public Multimap < String , UUID > serversToPlayers ( ) {
try {
2022-07-08 02:47:50 +00:00
return serverToPlayersCache . get ( SERVER_TO_PLAYERS_KEY , ( ) - > {
Collection < String > data = ( Collection < String > ) serverToPlayersScript . eval ( ImmutableList . of ( ) , getServerIds ( ) ) ;
ImmutableMultimap . Builder < String , UUID > builder = ImmutableMultimap . builder ( ) ;
String key = null ;
for ( String s : data ) {
if ( key = = null ) {
key = s ;
continue ;
2022-04-13 18:17:38 +00:00
}
2022-07-08 02:47:50 +00:00
builder . put ( key , UUID . fromString ( s ) ) ;
key = null ;
2022-04-13 18:17:38 +00:00
}
2022-07-08 02:47:50 +00:00
return builder . build ( ) ;
2022-04-13 18:17:38 +00:00
} ) ;
} catch ( ExecutionException e ) {
throw new RuntimeException ( e ) ;
}
}
@Override
public Set < UUID > getPlayersOnProxy ( String proxyId ) {
2022-04-13 21:16:31 +00:00
checkArgument ( getServerIds ( ) . contains ( proxyId ) , proxyId + " is not a valid proxy ID " ) ;
try ( Jedis jedis = requestJedis ( ) ) {
Set < String > users = jedis . smembers ( " proxy: " + proxyId + " :usersOnline " ) ;
ImmutableSet . Builder < UUID > builder = ImmutableSet . builder ( ) ;
for ( String user : users ) {
builder . add ( UUID . fromString ( user ) ) ;
}
return builder . build ( ) ;
}
2022-04-13 18:17:38 +00:00
}
@Override
public void sendProxyCommand ( String serverId , String command ) {
2022-04-13 21:16:31 +00:00
checkArgument ( getServerIds ( ) . contains ( serverId ) | | serverId . equals ( " allservers " ) , " proxyId is invalid " ) ;
sendChannelMessage ( " redisbungee- " + serverId , command ) ;
2022-04-13 18:17:38 +00:00
}
@Override
public List < String > getServerIds ( ) {
2022-04-13 21:16:31 +00:00
return serverIds ;
2022-04-13 18:17:38 +00:00
}
@Override
public List < String > getCurrentServerIds ( boolean nag , boolean lagged ) {
2022-04-13 21:16:31 +00:00
try ( Jedis jedis = requestJedis ( ) ) {
long time = getRedisTime ( jedis . time ( ) ) ;
int nagTime = 0 ;
if ( nag ) {
nagTime = nagAboutServers . decrementAndGet ( ) ;
if ( nagTime < = 0 ) {
nagAboutServers . set ( 10 ) ;
}
}
ImmutableList . Builder < String > servers = ImmutableList . builder ( ) ;
Map < String , String > heartbeats = jedis . hgetAll ( " heartbeats " ) ;
for ( Map . Entry < String , String > entry : heartbeats . entrySet ( ) ) {
try {
long stamp = Long . parseLong ( entry . getValue ( ) ) ;
if ( lagged ? time > = stamp + 30 : time < = stamp + 30 )
servers . add ( entry . getKey ( ) ) ;
else if ( nag & & nagTime < = 0 ) {
getLogger ( ) . warning ( entry . getKey ( ) + " is " + ( time - stamp ) + " seconds behind! (Time not synchronized or server down?) and was removed from heartbeat. " ) ;
jedis . hdel ( " heartbeats " , entry . getKey ( ) ) ;
}
} catch ( NumberFormatException ignored ) {
}
}
return servers . build ( ) ;
} catch ( JedisConnectionException e ) {
getLogger ( ) . log ( Level . SEVERE , " Unable to fetch server IDs " , e ) ;
return Collections . singletonList ( configuration . getServerId ( ) ) ;
}
2022-04-13 18:17:38 +00:00
}
@Override
public PubSubListener getPubSubListener ( ) {
2022-04-13 21:16:31 +00:00
return this . psl ;
2022-04-13 18:17:38 +00:00
}
@Override
public void sendChannelMessage ( String channel , String message ) {
2022-04-13 21:16:31 +00:00
try ( Jedis jedis = requestJedis ( ) ) {
jedis . publish ( channel , message ) ;
} catch ( JedisConnectionException e ) {
// Redis server has disappeared!
getLogger ( ) . log ( Level . SEVERE , " Unable to get connection from pool - did your Redis server go away? " , e ) ;
throw new RuntimeException ( " Unable to publish channel message " , e ) ;
}
2022-04-13 18:17:38 +00:00
}
@Override
public void executeAsync ( Runnable runnable ) {
this . getProxy ( ) . getScheduler ( ) . runAsync ( this , runnable ) ;
}
@Override
public void executeAsyncAfter ( Runnable runnable , TimeUnit timeUnit , int time ) {
this . getProxy ( ) . getScheduler ( ) . schedule ( this , runnable , time , timeUnit ) ;
}
@Override
public void callEvent ( Object event ) {
this . getProxy ( ) . getPluginManager ( ) . callEvent ( ( Event ) event ) ;
}
@Override
public boolean isOnlineMode ( ) {
return this . getProxy ( ) . getConfig ( ) . isOnlineMode ( ) ;
}
@Override
public void logInfo ( String msg ) {
this . getLogger ( ) . info ( msg ) ;
}
@Override
public void logWarn ( String msg ) {
this . getLogger ( ) . warning ( msg ) ;
}
@Override
public void logFatal ( String msg ) {
this . getLogger ( ) . severe ( msg ) ;
}
@Override
public ProxiedPlayer getPlayer ( UUID uuid ) {
return this . getProxy ( ) . getPlayer ( uuid ) ;
}
@Override
public ProxiedPlayer getPlayer ( String name ) {
return this . getProxy ( ) . getPlayer ( name ) ;
}
@Override
public UUID getPlayerUUID ( String player ) {
return this . getProxy ( ) . getPlayer ( player ) . getUniqueId ( ) ;
}
@Override
public String getPlayerName ( UUID player ) {
return this . getProxy ( ) . getPlayer ( player ) . getName ( ) ;
}
@Override
public String getPlayerServerName ( ProxiedPlayer player ) {
return player . getServer ( ) . getInfo ( ) . getName ( ) ;
}
@Override
public boolean isPlayerOnAServer ( ProxiedPlayer player ) {
return player . getServer ( ) ! = null ;
}
@Override
public InetAddress getPlayerIp ( ProxiedPlayer player ) {
return player . getAddress ( ) . getAddress ( ) ;
}
@Override
public void sendProxyCommand ( String cmd ) {
checkArgument ( getServerIds ( ) . contains ( this . configuration . getServerId ( ) ) | | this . configuration . getServerId ( ) . equals ( " allservers " ) , " proxyId is invalid " ) ;
sendChannelMessage ( " redisbungee- " + this . configuration . getServerId ( ) , cmd ) ;
}
@Override
public long getRedisTime ( List < String > timeRes ) {
return Long . parseLong ( timeRes . get ( 0 ) ) ;
}
@Override
2022-07-07 23:23:44 +00:00
public void initialize ( ) {
2022-04-13 18:17:38 +00:00
ThreadFactory factory = ( ( ThreadPoolExecutor ) getExecutorService ( ) ) . getThreadFactory ( ) ;
ScheduledExecutorService service = Executors . newScheduledThreadPool ( 24 , factory ) ;
try {
Field field = Plugin . class . getDeclaredField ( " service " ) ;
field . setAccessible ( true ) ;
ExecutorService builtinService = ( ExecutorService ) field . get ( this ) ;
field . set ( this , service ) ;
builtinService . shutdownNow ( ) ;
} catch ( IllegalAccessException | NoSuchFieldException e ) {
getLogger ( ) . log ( Level . WARNING , " Can't replace BungeeCord thread pool with our own " ) ;
getLogger ( ) . log ( Level . INFO , " skipping replacement..... " ) ;
}
try {
loadConfig ( ) ;
} catch ( IOException e ) {
throw new RuntimeException ( " Unable to load/save config " , e ) ;
} catch ( JedisConnectionException e ) {
throw new RuntimeException ( " Unable to connect to your Redis server! " , e ) ;
}
2022-04-14 10:12:47 +00:00
this . api = new RedisBungeeAPI ( this ) ;
// call old plugin class to support old plugins
new RedisBungee ( api ) ;
2022-04-13 18:17:38 +00:00
if ( isJedisAvailable ( ) ) {
try ( Jedis tmpRsc = requestJedis ( ) ) {
// This is more portable than INFO <section>
String info = tmpRsc . info ( ) ;
for ( String s : info . split ( " \ r \ n " ) ) {
if ( s . startsWith ( " redis_version: " ) ) {
String version = s . split ( " : " ) [ 1 ] ;
getLogger ( ) . info ( version + " <- redis version " ) ;
if ( ! RedisUtil . isRedisVersionRight ( version ) ) {
2022-07-08 02:47:50 +00:00
getLogger ( ) . severe ( " Your version of Redis ( " + version + " ) is not at least version 6.0 RedisBungee requires a newer version of Redis. " ) ;
2022-04-13 18:17:38 +00:00
throw new RuntimeException ( " Unsupported Redis version detected " ) ;
} else {
LuaManager manager = new LuaManager ( this ) ;
serverToPlayersScript = manager . createScript ( IOUtil . readInputStreamAsString ( getResourceAsStream ( " lua/server_to_players.lua " ) ) ) ;
getPlayerCountScript = manager . createScript ( IOUtil . readInputStreamAsString ( getResourceAsStream ( " lua/get_player_count.lua " ) ) ) ;
2022-07-08 02:47:50 +00:00
getLogger ( ) . info ( " lua manager was loaded " ) ;
2022-04-13 18:17:38 +00:00
}
break ;
}
}
tmpRsc . hset ( " heartbeats " , configuration . getServerId ( ) , tmpRsc . time ( ) . get ( 0 ) ) ;
long uuidCacheSize = tmpRsc . hlen ( " uuid-cache " ) ;
if ( uuidCacheSize > 750000 ) {
getLogger ( ) . info ( " Looks like you have a really big UUID cache! Run https://www.spigotmc.org/resources/redisbungeecleaner.8505/ as soon as possible. " ) ;
}
}
serverIds = getCurrentServerIds ( true , false ) ;
uuidTranslator = new UUIDTranslator ( this ) ;
2022-07-08 02:47:50 +00:00
heartbeatTask = service . scheduleAtFixedRate ( ( ) - > {
try ( Jedis rsc = requestJedis ( ) ) {
long redisTime = getRedisTime ( rsc . time ( ) ) ;
rsc . hset ( " heartbeats " , configuration . getServerId ( ) , String . valueOf ( redisTime ) ) ;
} catch ( JedisConnectionException e ) {
// Redis server has disappeared!
getLogger ( ) . log ( Level . SEVERE , " Unable to update heartbeat - did your Redis server go away? " , e ) ;
return ;
}
try {
serverIds = getCurrentServerIds ( true , false ) ;
globalPlayerCount . set ( getCurrentCount ( ) ) ;
} catch ( Throwable e ) {
getLogger ( ) . log ( Level . SEVERE , " Unable to update data - did your Redis server go away? " , e ) ;
2022-04-13 18:17:38 +00:00
}
} , 0 , 3 , TimeUnit . SECONDS ) ;
dataManager = new BungeeDataManager ( this ) ;
2022-07-14 23:05:53 +00:00
getProxy ( ) . getPluginManager ( ) . registerListener ( this , new RedisBungeeBungeeListener ( this , configuration . getExemptAddresses ( ) ) ) ;
2022-04-13 18:17:38 +00:00
getProxy ( ) . getPluginManager ( ) . registerListener ( this , dataManager ) ;
psl = new PubSubListener ( this ) ;
getProxy ( ) . getScheduler ( ) . runAsync ( this , psl ) ;
2022-07-08 02:47:50 +00:00
integrityCheck = service . scheduleAtFixedRate ( ( ) - > {
try ( Jedis tmpRsc = requestJedis ( ) ) {
Set < String > players = getLocalPlayersAsUuidStrings ( ) ;
Set < String > playersInRedis = tmpRsc . smembers ( " proxy: " + configuration . getServerId ( ) + " :usersOnline " ) ;
List < String > lagged = getCurrentServerIds ( false , true ) ;
// Clean up lagged players.
for ( String s : lagged ) {
Set < String > laggedPlayers = tmpRsc . smembers ( " proxy: " + s + " :usersOnline " ) ;
tmpRsc . del ( " proxy: " + s + " :usersOnline " ) ;
if ( ! laggedPlayers . isEmpty ( ) ) {
getLogger ( ) . info ( " Cleaning up lagged proxy " + s + " ( " + laggedPlayers . size ( ) + " players)... " ) ;
for ( String laggedPlayer : laggedPlayers ) {
RedisUtil . cleanUpPlayer ( laggedPlayer , tmpRsc ) ;
2022-04-13 18:17:38 +00:00
}
}
2022-07-08 02:47:50 +00:00
}
2022-04-13 18:17:38 +00:00
2022-07-08 02:47:50 +00:00
Set < String > absentLocally = new HashSet < > ( playersInRedis ) ;
absentLocally . removeAll ( players ) ;
Set < String > absentInRedis = new HashSet < > ( players ) ;
absentInRedis . removeAll ( playersInRedis ) ;
for ( String member : absentLocally ) {
boolean found = false ;
for ( String proxyId : getServerIds ( ) ) {
if ( proxyId . equals ( configuration . getServerId ( ) ) ) continue ;
if ( tmpRsc . sismember ( " proxy: " + proxyId + " :usersOnline " , member ) ) {
// Just clean up the set.
found = true ;
break ;
2022-04-13 18:17:38 +00:00
}
}
2022-07-08 02:47:50 +00:00
if ( ! found ) {
RedisUtil . cleanUpPlayer ( member , tmpRsc ) ;
getLogger ( ) . warning ( " Player found in set that was not found locally and globally: " + member ) ;
} else {
tmpRsc . srem ( " proxy: " + configuration . getServerId ( ) + " :usersOnline " , member ) ;
getLogger ( ) . warning ( " Player found in set that was not found locally, but is on another proxy: " + member ) ;
}
}
2022-04-13 18:17:38 +00:00
2022-07-08 02:47:50 +00:00
Pipeline pipeline = tmpRsc . pipelined ( ) ;
2022-04-13 18:17:38 +00:00
2022-07-08 02:47:50 +00:00
for ( String player : absentInRedis ) {
// Player not online according to Redis but not BungeeCord.
getLogger ( ) . warning ( " Player " + player + " is on the proxy but not in Redis. " ) ;
2022-04-13 18:17:38 +00:00
2022-07-08 02:47:50 +00:00
ProxiedPlayer proxiedPlayer = ProxyServer . getInstance ( ) . getPlayer ( UUID . fromString ( player ) ) ;
if ( proxiedPlayer = = null )
continue ; // We'll deal with it later.
2022-04-13 18:17:38 +00:00
2022-07-08 02:47:50 +00:00
RBUtils . createPlayer ( proxiedPlayer , pipeline , true ) ;
2022-04-13 18:17:38 +00:00
}
2022-07-08 02:47:50 +00:00
pipeline . sync ( ) ;
} catch ( Throwable e ) {
getLogger ( ) . log ( Level . SEVERE , " Unable to fix up stored player data " , e ) ;
2022-04-13 18:17:38 +00:00
}
} , 0 , 1 , TimeUnit . MINUTES ) ;
}
getProxy ( ) . registerChannel ( " legacy:redisbungee " ) ;
getProxy ( ) . registerChannel ( " RedisBungee " ) ;
2022-06-15 02:32:22 +00:00
// register commands
if ( configuration . doOverrideBungeeCommands ( ) ) {
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . GlistCommand ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . FindCommand ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . LastSeenCommand ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . IpCommand ( this ) ) ;
}
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . SendToAll ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . ServerId ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . ServerIds ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . PlayerProxyCommand ( this ) ) ;
getProxy ( ) . getPluginManager ( ) . registerCommand ( this , new RedisBungeeCommands . PlistCommand ( this ) ) ;
2022-04-13 18:17:38 +00:00
}
@Override
2022-07-06 19:04:09 +00:00
public void stop ( ) {
2022-04-13 18:17:38 +00:00
if ( isJedisAvailable ( ) ) {
// Poison the PubSub listener
psl . poison ( ) ;
integrityCheck . cancel ( true ) ;
heartbeatTask . cancel ( true ) ;
getProxy ( ) . getPluginManager ( ) . unregisterListeners ( this ) ;
try ( Jedis tmpRsc = requestJedis ( ) ) {
tmpRsc . hdel ( " heartbeats " , configuration . getServerId ( ) ) ;
if ( tmpRsc . scard ( " proxy: " + configuration . getServerId ( ) + " :usersOnline " ) > 0 ) {
Set < String > players = tmpRsc . smembers ( " proxy: " + configuration . getServerId ( ) + " :usersOnline " ) ;
for ( String member : players )
RedisUtil . cleanUpPlayer ( member , tmpRsc ) ;
}
}
2022-07-06 19:04:09 +00:00
try {
this . jedisSummoner . close ( ) ;
} catch ( IOException e ) {
throw new RuntimeException ( e ) ;
}
2022-04-13 18:17:38 +00:00
}
}
2022-07-15 22:58:48 +00:00
@Override
2022-07-16 05:18:33 +00:00
public Summoner getSummoner ( ) {
2022-07-15 22:58:48 +00:00
return this . jedisSummoner ;
}
2022-04-13 18:17:38 +00:00
@Override
public void loadConfig ( ) throws IOException {
2022-07-08 02:47:50 +00:00
if ( ! getDataFolder ( ) . exists ( ) & & getDataFolder ( ) . mkdir ( ) ) {
getLogger ( ) . info ( " data folder was created " ) ;
2022-04-13 18:17:38 +00:00
}
File file = new File ( getDataFolder ( ) , " config.yml " ) ;
2022-07-08 02:47:50 +00:00
if ( ! file . exists ( ) & & file . createNewFile ( ) ) {
2022-04-13 18:17:38 +00:00
try ( InputStream in = getResourceAsStream ( " example_config.yml " ) ;
2022-07-08 02:47:50 +00:00
OutputStream out = Files . newOutputStream ( file . toPath ( ) ) ) {
2022-04-13 18:17:38 +00:00
ByteStreams . copy ( in , out ) ;
}
}
final Configuration y amlConfiguration = ConfigurationProvider . getProvider ( YamlConfiguration . class ) . load ( file ) ;
final String redisServer = yamlConfiguration . getString ( " redis-server " , " localhost " ) ;
final int redisPort = yamlConfiguration . getInt ( " redis-port " , 6379 ) ;
final boolean useSSL = yamlConfiguration . getBoolean ( " useSSL " , false ) ;
String redisPassword = yamlConfiguration . getString ( " redis-password " , " " ) ;
String serverId = yamlConfiguration . getString ( " server-id " ) ;
// check redis password
if ( redisPassword ! = null & & ( redisPassword . isEmpty ( ) | | redisPassword . equals ( " none " ) ) ) {
redisPassword = null ;
getLogger ( ) . warning ( " INSECURE setup was detected Please set password for your redis instance. " ) ;
}
if ( ! useSSL ) {
getLogger ( ) . warning ( " INSECURE setup was detected Please setup ssl for your redis instance. " ) ;
}
// Configuration sanity checks.
if ( serverId = = null | | serverId . isEmpty ( ) ) {
/ *
* this check causes the config comments to disappear somehow
* I think due snake yaml limitations so as todo : write our own yaml parser ?
* /
String genId = UUID . randomUUID ( ) . toString ( ) ;
getLogger ( ) . info ( " Generated server id " + genId + " and saving it to config. " ) ;
yamlConfiguration . set ( " server-id " , genId ) ;
ConfigurationProvider . getProvider ( YamlConfiguration . class ) . save ( yamlConfiguration , new File ( getDataFolder ( ) , " config.yml " ) ) ;
getLogger ( ) . info ( " Server id was generated: " + serverId ) ;
} else {
getLogger ( ) . info ( " Loaded server id " + serverId + '.' ) ;
}
2022-06-15 02:32:22 +00:00
this . configuration = new RedisBungeeConfiguration ( serverId , yamlConfiguration . getStringList ( " exempt-ip-addresses " ) , yamlConfiguration . getBoolean ( " register-bungee-commands " , true ) ) ;
2022-04-13 18:17:38 +00:00
if ( redisServer ! = null & & ! redisServer . isEmpty ( ) ) {
try {
JedisPoolConfig config = new JedisPoolConfig ( ) ;
config . setMaxTotal ( yamlConfiguration . getInt ( " max-redis-connections " , 8 ) ) ;
2022-07-06 19:04:09 +00:00
this . jedisSummoner = new SinglePoolJedisSummoner ( new JedisPool ( config , redisServer , redisPort , 0 , redisPassword , useSSL ) ) ;
2022-04-13 18:17:38 +00:00
} catch ( JedisConnectionException e ) {
throw new RuntimeException ( " Unable to create Redis pool " , e ) ;
}
// Test the connection
try ( Jedis rsc = requestJedis ( ) ) {
rsc . ping ( ) ;
// If that worked, now we can check for an existing, alive Bungee:
File crashFile = new File ( getDataFolder ( ) , " restarted_from_crash.txt " ) ;
2022-07-08 02:47:50 +00:00
if ( crashFile . exists ( ) & & crashFile . delete ( ) ) {
getLogger ( ) . info ( " crash file was deleted " ) ;
2022-04-13 18:17:38 +00:00
} else if ( rsc . hexists ( " heartbeats " , serverId ) ) {
try {
long value = Long . parseLong ( rsc . hget ( " heartbeats " , serverId ) ) ;
long redisTime = getRedisTime ( rsc . time ( ) ) ;
if ( redisTime < value + 20 ) {
2022-07-07 00:16:09 +00:00
getLogger ( ) . severe ( " You have launched a possible impostor Velocity / Bungeecord instance. Another instance is already running. " ) ;
2022-04-13 18:17:38 +00:00
getLogger ( ) . severe ( " For data consistency reasons, RedisBungee will now disable itself. " ) ;
getLogger ( ) . severe ( " If this instance is coming up from a crash, create a file in your RedisBungee plugins directory with the name 'restarted_from_crash.txt' and RedisBungee will not perform this check. " ) ;
throw new RuntimeException ( " Possible impostor instance! " ) ;
}
} catch ( NumberFormatException ignored ) {
}
}
httpClient = new OkHttpClient ( ) ;
Dispatcher dispatcher = new Dispatcher ( getExecutorService ( ) ) ;
httpClient . setDispatcher ( dispatcher ) ;
NameFetcher . setHttpClient ( httpClient ) ;
UUIDFetcher . setHttpClient ( httpClient ) ;
getLogger ( ) . log ( Level . INFO , " Successfully connected to Redis. " ) ;
} catch ( JedisConnectionException e ) {
2022-07-06 19:04:09 +00:00
this . jedisSummoner . close ( ) ;
2022-04-13 18:17:38 +00:00
throw e ;
}
} else {
throw new RuntimeException ( " No redis server specified! " ) ;
}
}
@Override
public void onEnable ( ) {
2022-07-07 23:23:44 +00:00
initialize ( ) ;
2022-04-13 18:17:38 +00:00
}
@Override
public void onDisable ( ) {
2022-07-06 19:04:09 +00:00
stop ( ) ;
2022-04-13 18:17:38 +00:00
}
2022-04-13 21:16:31 +00:00
@Override
public Class < ? > getPubSubEventClass ( ) {
return PubSubMessageEvent . class ;
}
@Override
public Class < ? > getNetworkJoinEventClass ( ) {
return PlayerJoinedNetworkEvent . class ;
}
@Override
public Class < ? > getServerChangeEventClass ( ) {
return PlayerChangedServerNetworkEvent . class ;
}
@Override
public Class < ? > getNetworkQuitEventClass ( ) {
return PlayerJoinedNetworkEvent . class ;
}
2022-04-13 18:17:38 +00:00
}