2022-10-29 20:02:09 +00:00
/ *
* Copyright ( c ) 2013 - present RedisBungee contributors
*
* All rights reserved . This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1 . 0
* which accompanies this distribution , and is available at
*
* http : //www.eclipse.org/legal/epl-v10.html
* /
2022-07-22 08:29:39 +00:00
package com.imaginarycode.minecraft.redisbungee.api.config ;
2022-07-22 11:12:32 +00:00
2022-11-11 16:30:16 +00:00
import com.google.common.collect.ImmutableMap ;
2022-07-25 12:49:57 +00:00
import com.google.common.reflect.TypeToken ;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode ;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin ;
2022-07-25 15:13:25 +00:00
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisClusterSummoner ;
2022-07-26 13:47:18 +00:00
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner ;
2022-07-25 12:49:57 +00:00
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner ;
import ninja.leaping.configurate.ConfigurationNode ;
import ninja.leaping.configurate.objectmapping.ObjectMappingException ;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader ;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig ;
import redis.clients.jedis.* ;
2022-10-25 11:52:50 +00:00
import redis.clients.jedis.providers.ClusterConnectionProvider ;
2022-10-25 04:01:41 +00:00
import redis.clients.jedis.providers.PooledConnectionProvider ;
2022-07-25 12:49:57 +00:00
import java.io.File ;
2022-07-22 08:29:39 +00:00
import java.io.IOException ;
2022-07-22 11:12:32 +00:00
import java.io.InputStream ;
import java.nio.file.Files ;
2022-07-22 08:29:39 +00:00
import java.nio.file.Path ;
2022-07-22 11:12:32 +00:00
import java.nio.file.StandardCopyOption ;
2022-07-25 12:49:57 +00:00
import java.util.* ;
2022-07-22 08:29:39 +00:00
public interface ConfigLoader {
2022-07-25 12:49:57 +00:00
default void loadConfig ( RedisBungeePlugin < ? > plugin , File dataFolder ) throws IOException {
loadConfig ( plugin , dataFolder . toPath ( ) ) ;
}
default void loadConfig ( RedisBungeePlugin < ? > plugin , Path dataFolder ) throws IOException {
Path configFile = createConfigFile ( dataFolder ) ;
final YAMLConfigurationLoader yamlConfigurationFileLoader = YAMLConfigurationLoader . builder ( ) . setPath ( configFile ) . build ( ) ;
ConfigurationNode node = yamlConfigurationFileLoader . load ( ) ;
if ( node . getNode ( " config-version " ) . getInt ( 0 ) ! = RedisBungeeConfiguration . CONFIG_VERSION ) {
handleOldConfig ( dataFolder ) ;
node = yamlConfigurationFileLoader . load ( ) ;
}
final boolean useSSL = node . getNode ( " useSSL " ) . getBoolean ( false ) ;
final boolean overrideBungeeCommands = node . getNode ( " override-bungee-commands " ) . getBoolean ( false ) ;
final boolean registerLegacyCommands = node . getNode ( " register-legacy-commands " ) . getBoolean ( false ) ;
2022-11-27 08:29:13 +00:00
final boolean restoreOldKickBehavior = node . getNode ( " disable-kick-when-online " ) . getBoolean ( false ) ;
2022-11-16 04:22:30 +00:00
String redisPassword = node . getNode ( " redis-password " ) . getString ( " " ) ;
2023-04-12 18:40:01 +00:00
String redisUsername = node . getNode ( " redis-username " ) . getString ( " " ) ;
2022-07-25 12:49:57 +00:00
String proxyId = node . getNode ( " proxy-id " ) . getString ( " test-1 " ) ;
final int maxConnections = node . getNode ( " max-redis-connections " ) . getInt ( 10 ) ;
List < String > exemptAddresses ;
try {
exemptAddresses = node . getNode ( " exempt-ip-addresses " ) . getList ( TypeToken . of ( String . class ) ) ;
} catch ( ObjectMappingException e ) {
exemptAddresses = Collections . emptyList ( ) ;
}
// check redis password
2022-11-16 04:22:30 +00:00
if ( ( redisPassword . isEmpty ( ) | | redisPassword . equals ( " none " ) ) ) {
2022-07-25 12:49:57 +00:00
redisPassword = null ;
2022-11-16 04:22:30 +00:00
plugin . logWarn ( " password is empty " ) ;
2022-07-26 11:14:14 +00:00
}
2023-04-12 18:40:01 +00:00
if ( ( redisUsername . isEmpty ( ) | | redisUsername . equals ( " none " ) ) ) {
redisUsername = null ;
}
2022-11-16 04:22:30 +00:00
if ( useSSL ) {
plugin . logInfo ( " Using ssl " ) ;
2022-07-25 12:49:57 +00:00
}
// Configuration sanity checks.
if ( proxyId = = null | | proxyId . isEmpty ( ) ) {
String genId = UUID . randomUUID ( ) . toString ( ) ;
plugin . logInfo ( " Generated proxy id " + genId + " and saving it to config. " ) ;
node . getNode ( " proxy-id " ) . setValue ( genId ) ;
yamlConfigurationFileLoader . save ( node ) ;
proxyId = genId ;
plugin . logInfo ( " proxy id was generated: " + proxyId ) ;
} else {
plugin . logInfo ( " Loaded proxy id " + proxyId ) ;
}
2022-11-27 08:29:13 +00:00
RedisBungeeConfiguration configuration = new RedisBungeeConfiguration ( proxyId , exemptAddresses , registerLegacyCommands , overrideBungeeCommands , getMessagesFromPath ( createMessagesFile ( dataFolder ) ) , restoreOldKickBehavior ) ;
2022-07-25 12:49:57 +00:00
Summoner < ? > summoner ;
RedisBungeeMode redisBungeeMode ;
if ( node . getNode ( " cluster-mode-enabled " ) . getBoolean ( false ) ) {
plugin . logInfo ( " RedisBungee MODE: CLUSTER " ) ;
Set < HostAndPort > hostAndPortSet = new HashSet < > ( ) ;
GenericObjectPoolConfig < Connection > poolConfig = new GenericObjectPoolConfig < > ( ) ;
poolConfig . setMaxTotal ( maxConnections ) ;
2022-07-26 13:51:41 +00:00
poolConfig . setBlockWhenExhausted ( true ) ;
2022-07-25 12:49:57 +00:00
node . getNode ( " redis-cluster-servers " ) . getChildrenList ( ) . forEach ( ( childNode ) - > {
Map < Object , ? extends ConfigurationNode > hostAndPort = childNode . getChildrenMap ( ) ;
String host = hostAndPort . get ( " host " ) . getString ( ) ;
int port = hostAndPort . get ( " port " ) . getInt ( ) ;
hostAndPortSet . add ( new HostAndPort ( host , port ) ) ;
} ) ;
plugin . logInfo ( hostAndPortSet . size ( ) + " cluster nodes were specified " ) ;
if ( hostAndPortSet . isEmpty ( ) ) {
throw new RuntimeException ( " No redis cluster servers specified " ) ;
}
2023-04-12 18:40:01 +00:00
summoner = new JedisClusterSummoner ( new ClusterConnectionProvider ( hostAndPortSet , DefaultJedisClientConfig . builder ( ) . user ( redisUsername ) . password ( redisPassword ) . ssl ( useSSL ) . socketTimeoutMillis ( 5000 ) . timeoutMillis ( 10000 ) . build ( ) , poolConfig ) ) ;
2022-07-25 12:49:57 +00:00
redisBungeeMode = RedisBungeeMode . CLUSTER ;
} else {
plugin . logInfo ( " RedisBungee MODE: SINGLE " ) ;
final String redisServer = node . getNode ( " redis-server " ) . getString ( " 127.0.0.1 " ) ;
final int redisPort = node . getNode ( " redis-port " ) . getInt ( 6379 ) ;
if ( redisServer ! = null & & redisServer . isEmpty ( ) ) {
throw new RuntimeException ( " No redis server specified " ) ;
}
2022-07-26 13:47:18 +00:00
JedisPool jedisPool = null ;
2023-08-31 09:00:19 +00:00
if ( node . getNode ( " enable-jedis-pool-compatibility " ) . getBoolean ( false ) ) {
2022-07-26 13:47:18 +00:00
JedisPoolConfig config = new JedisPoolConfig ( ) ;
2022-07-26 13:51:41 +00:00
config . setMaxTotal ( node . getNode ( " compatibility-max-connections " ) . getInt ( 3 ) ) ;
config . setBlockWhenExhausted ( true ) ;
2023-04-12 18:40:01 +00:00
jedisPool = new JedisPool ( config , redisServer , redisPort , 5000 , redisUsername , redisPassword , useSSL ) ;
2022-07-26 13:55:16 +00:00
plugin . logInfo ( " Compatibility JedisPool was created " ) ;
2022-07-26 13:47:18 +00:00
}
GenericObjectPoolConfig < Connection > poolConfig = new GenericObjectPoolConfig < > ( ) ;
poolConfig . setMaxTotal ( maxConnections ) ;
2022-07-26 13:51:41 +00:00
poolConfig . setBlockWhenExhausted ( true ) ;
2023-04-12 18:40:01 +00:00
summoner = new JedisPooledSummoner ( new PooledConnectionProvider ( new ConnectionFactory ( new HostAndPort ( redisServer , redisPort ) , DefaultJedisClientConfig . builder ( ) . user ( redisUsername ) . timeoutMillis ( 5000 ) . ssl ( useSSL ) . password ( redisPassword ) . build ( ) ) , poolConfig ) , jedisPool ) ;
2022-07-25 12:49:57 +00:00
redisBungeeMode = RedisBungeeMode . SINGLE ;
}
plugin . logInfo ( " Successfully connected to Redis. " ) ;
onConfigLoad ( configuration , summoner , redisBungeeMode ) ;
}
void onConfigLoad ( RedisBungeeConfiguration configuration , Summoner < ? > summoner , RedisBungeeMode mode ) ;
2022-07-22 08:29:39 +00:00
2022-11-11 16:30:16 +00:00
default ImmutableMap < RedisBungeeConfiguration . MessageType , String > getMessagesFromPath ( Path path ) throws IOException {
final YAMLConfigurationLoader yamlConfigurationFileLoader = YAMLConfigurationLoader . builder ( ) . setPath ( path ) . build ( ) ;
ConfigurationNode node = yamlConfigurationFileLoader . load ( ) ;
HashMap < RedisBungeeConfiguration . MessageType , String > messages = new HashMap < > ( ) ;
messages . put ( RedisBungeeConfiguration . MessageType . LOGGED_IN_OTHER_LOCATION , node . getNode ( " logged-in-other-location " ) . getString ( " §cLogged in from another location. " ) ) ;
2022-11-27 08:29:13 +00:00
messages . put ( RedisBungeeConfiguration . MessageType . ALREADY_LOGGED_IN , node . getNode ( " already-logged-in " ) . getString ( " §cYou are already logged in! " ) ) ;
2022-11-11 16:30:16 +00:00
return ImmutableMap . copyOf ( messages ) ;
}
default Path createMessagesFile ( Path dataFolder ) throws IOException {
if ( Files . notExists ( dataFolder ) ) {
Files . createDirectory ( dataFolder ) ;
}
Path file = dataFolder . resolve ( " messages.yml " ) ;
if ( Files . notExists ( file ) ) {
try ( InputStream in = getClass ( ) . getClassLoader ( ) . getResourceAsStream ( " messages.yml " ) ) {
Files . createFile ( file ) ;
assert in ! = null ;
Files . copy ( in , file , StandardCopyOption . REPLACE_EXISTING ) ;
}
}
return file ;
}
2022-07-22 11:12:32 +00:00
default Path createConfigFile ( Path dataFolder ) throws IOException {
if ( Files . notExists ( dataFolder ) ) {
Files . createDirectory ( dataFolder ) ;
}
Path file = dataFolder . resolve ( " config.yml " ) ;
if ( Files . notExists ( file ) ) {
try ( InputStream in = getClass ( ) . getClassLoader ( ) . getResourceAsStream ( " config.yml " ) ) {
Files . createFile ( file ) ;
assert in ! = null ;
Files . copy ( in , file , StandardCopyOption . REPLACE_EXISTING ) ;
}
}
return file ;
}
default void handleOldConfig ( Path dataFolder ) throws IOException {
Path oldConfigFolder = dataFolder . resolve ( " old_config " ) ;
if ( Files . notExists ( oldConfigFolder ) ) {
Files . createDirectory ( oldConfigFolder ) ;
}
Path oldConfigPath = dataFolder . resolve ( " config.yml " ) ;
Files . move ( oldConfigPath , oldConfigFolder . resolve ( UUID . randomUUID ( ) + " _config.yml " ) ) ;
createConfigFile ( dataFolder ) ;
}
2022-07-22 08:29:39 +00:00
}