Implement support for instant data propagation with Redis
This commit is contained in:
parent
bb9eab0989
commit
2cfc82f3aa
@ -75,6 +75,18 @@
|
||||
<pattern>com.google.gson</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.gson</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.jedis</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.util</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons.pool2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -70,6 +70,18 @@
|
||||
<pattern>org.h2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.h2</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.jedis</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.util</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons.pool2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -45,6 +45,7 @@ import me.lucko.luckperms.common.contexts.ServerCalculator;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.data.Importer;
|
||||
import me.lucko.luckperms.common.groups.GroupManager;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessaging;
|
||||
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.runnables.UpdateTask;
|
||||
import me.lucko.luckperms.common.storage.Datastore;
|
||||
@ -77,6 +78,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Datastore datastore;
|
||||
private RedisMessaging redisMessaging = null;
|
||||
private UuidCache uuidCache;
|
||||
private ApiProvider apiProvider;
|
||||
private Logger log;
|
||||
@ -97,6 +99,42 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new BukkitConfig(this);
|
||||
|
||||
// setup the Bukkit defaults hook
|
||||
defaultsProvider = new DefaultsProvider();
|
||||
// give all plugins a chance to load their defaults, then refresh.
|
||||
getServer().getScheduler().runTaskLater(this, () -> defaultsProvider.refresh(), 1L);
|
||||
|
||||
// register events
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
pm.registerEvents(new BukkitListener(this), this);
|
||||
|
||||
// initialise datastore
|
||||
datastore = StorageFactory.getDatastore(this, "h2");
|
||||
|
||||
// initialise redis
|
||||
if (getConfiguration().isRedisEnabled()) {
|
||||
getLog().info("Loading redis...");
|
||||
redisMessaging = new RedisMessaging(this);
|
||||
try {
|
||||
redisMessaging.init(getConfiguration().getRedisAddress(), getConfiguration().getRedisPassword());
|
||||
getLog().info("Loaded redis successfully...");
|
||||
} catch (Exception e) {
|
||||
getLog().info("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// setup the update task buffer
|
||||
final LPBukkitPlugin i = this;
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
getServer().getScheduler().runTaskAsynchronously(i, new UpdateTask(i));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// load locale
|
||||
localeManager = new LocaleManager();
|
||||
File locale = new File(getDataFolder(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
@ -108,13 +146,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
defaultsProvider = new DefaultsProvider();
|
||||
getServer().getScheduler().runTaskLater(this, () -> defaultsProvider.refresh(), 1L);
|
||||
|
||||
// register events
|
||||
PluginManager pm = getServer().getPluginManager();
|
||||
pm.registerEvents(new BukkitListener(this), this);
|
||||
|
||||
// register commands
|
||||
getLog().info("Registering commands...");
|
||||
BukkitCommand commandManager = new BukkitCommand(this);
|
||||
@ -123,8 +154,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
main.setTabCompleter(commandManager);
|
||||
main.setAliases(Arrays.asList("perms", "lp", "permissions", "p", "perm"));
|
||||
|
||||
datastore = StorageFactory.getDatastore(this, "h2");
|
||||
|
||||
// load internal managers
|
||||
getLog().info("Loading internal permission managers...");
|
||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||
userManager = new UserManager(this);
|
||||
@ -140,29 +170,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
contextManager.registerCalculator(worldCalculator);
|
||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||
|
||||
// handle server operators
|
||||
if (getConfiguration().isAutoOp()) {
|
||||
contextManager.registerListener(new AutoOPListener());
|
||||
}
|
||||
|
||||
final LPBukkitPlugin i = this;
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
getServer().getScheduler().runTaskAsynchronously(i, new UpdateTask(i));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
long ticks = mins * 60 * 20;
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> updateTaskBuffer.request(), ticks, ticks);
|
||||
}
|
||||
|
||||
getServer().getScheduler().runTaskTimer(this, BukkitSenderFactory.get(this), 1L, 1L);
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, new ExpireTemporaryTask(this), 60L, 60L);
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, consecutiveExecutor, 20L, 20L);
|
||||
|
||||
// Provide vault support
|
||||
getLog().info("Attempting to hook into Vault...");
|
||||
try {
|
||||
@ -178,15 +190,29 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// register with the LP API
|
||||
getLog().info("Registering API...");
|
||||
apiProvider = new ApiProvider(this);
|
||||
ApiHandler.registerProvider(apiProvider);
|
||||
getServer().getServicesManager().register(LuckPermsApi.class, apiProvider, this, ServicePriority.Normal);
|
||||
|
||||
// Run update task to refresh any online users
|
||||
getLog().info("Scheduling Update Task to refresh any online users.");
|
||||
updateTaskBuffer.request();
|
||||
|
||||
// schedule update tasks
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
long ticks = mins * 60 * 20;
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> updateTaskBuffer.request(), 20L, ticks);
|
||||
} else {
|
||||
// Update online users
|
||||
updateTaskBuffer.request();
|
||||
}
|
||||
|
||||
// register tasks
|
||||
getServer().getScheduler().runTaskTimer(this, BukkitSenderFactory.get(this), 1L, 1L);
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, new ExpireTemporaryTask(this), 60L, 60L);
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, consecutiveExecutor, 20L, 20L);
|
||||
|
||||
// register permissions
|
||||
registerPermissions(getConfiguration().isCommandsAllowOp() ? PermissionDefault.OP : PermissionDefault.FALSE);
|
||||
if (!getConfiguration().isOpsEnabled()) {
|
||||
getServer().getOperators().forEach(o -> o.setOp(false));
|
||||
@ -202,6 +228,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
getLog().info("Closing datastore...");
|
||||
datastore.shutdown();
|
||||
|
||||
if (redisMessaging != null) {
|
||||
getLog().info("Closing redis...");
|
||||
redisMessaging.shutdown();
|
||||
}
|
||||
|
||||
getLog().info("Unregistering API...");
|
||||
ApiHandler.unregisterProvider();
|
||||
getServer().getServicesManager().unregisterAll(this);
|
||||
|
@ -155,6 +155,19 @@ data:
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes: 3
|
||||
|
||||
# Settings for Redis.
|
||||
#
|
||||
# If enabled and configured, LuckPerms will use the Redis PubSub system to inform other
|
||||
# connected servers of changes. Use the command "/luckperms networksync" to push changes.
|
||||
# Data is NOT stored on redis. It is only used as a messaging platform.
|
||||
#
|
||||
# If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need for LuckPerms
|
||||
# to poll the database for changes.
|
||||
redis:
|
||||
enabled: false
|
||||
address: localhost:6379
|
||||
password: ''
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -69,6 +69,18 @@
|
||||
<pattern>org.sqlite</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.sqlite</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.jedis</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.util</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons.pool2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -42,6 +42,7 @@ import me.lucko.luckperms.common.contexts.ServerCalculator;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.data.Importer;
|
||||
import me.lucko.luckperms.common.groups.GroupManager;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessaging;
|
||||
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.runnables.UpdateTask;
|
||||
import me.lucko.luckperms.common.storage.Datastore;
|
||||
@ -69,6 +70,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Datastore datastore;
|
||||
private RedisMessaging redisMessaging = null;
|
||||
private UuidCache uuidCache;
|
||||
private ApiProvider apiProvider;
|
||||
private Logger log;
|
||||
@ -86,6 +88,36 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new BungeeConfig(this);
|
||||
|
||||
// register events
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
|
||||
|
||||
// initialise datastore
|
||||
datastore = StorageFactory.getDatastore(this, "h2");
|
||||
|
||||
// initialise redis
|
||||
if (getConfiguration().isRedisEnabled()) {
|
||||
getLog().info("Loading redis...");
|
||||
redisMessaging = new RedisMessaging(this);
|
||||
try {
|
||||
redisMessaging.init(getConfiguration().getRedisAddress(), getConfiguration().getRedisPassword());
|
||||
getLog().info("Loaded redis successfully...");
|
||||
} catch (Exception e) {
|
||||
getLog().info("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// setup the update task buffer
|
||||
final LPBungeePlugin i = this;
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
doAsync(new UpdateTask(i));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// load locale
|
||||
localeManager = new LocaleManager();
|
||||
File locale = new File(getDataFolder(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
@ -97,9 +129,6 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
// register events
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeListener(this));
|
||||
|
||||
// register commands
|
||||
getLog().info("Registering commands...");
|
||||
CommandManager commandManager = new CommandManager(this);
|
||||
@ -108,8 +137,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
// disable the default Bungee /perms command so it gets handled by the Bukkit plugin
|
||||
getProxy().getDisabledCommands().add("perms");
|
||||
|
||||
datastore = StorageFactory.getDatastore(this, "h2");
|
||||
|
||||
// load internal managers
|
||||
getLog().info("Loading internal permission managers...");
|
||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||
userManager = new UserManager(this);
|
||||
@ -125,32 +153,24 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
contextManager.registerCalculator(serverCalculator);
|
||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||
|
||||
final LPBungeePlugin i = this;
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
doAsync(new UpdateTask(i));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
getProxy().getScheduler().schedule(this, new UpdateTask(this), mins, mins, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
// 20 times per second (once per "tick")
|
||||
getProxy().getScheduler().schedule(this, BungeeSenderFactory.get(this), 50L, 50L, TimeUnit.MILLISECONDS);
|
||||
getProxy().getScheduler().schedule(this, new ExpireTemporaryTask(this), 3L, 3L, TimeUnit.SECONDS);
|
||||
getProxy().getScheduler().schedule(this, consecutiveExecutor, 1L, 1L, TimeUnit.SECONDS);
|
||||
|
||||
// register with the LP API
|
||||
getLog().info("Registering API...");
|
||||
apiProvider = new ApiProvider(this);
|
||||
ApiHandler.registerProvider(apiProvider);
|
||||
|
||||
// Run update task to refresh any online users
|
||||
getLog().info("Scheduling Update Task to refresh any online users.");
|
||||
updateTaskBuffer.request();
|
||||
// schedule update tasks
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
getProxy().getScheduler().schedule(this, new UpdateTask(this), mins, mins, TimeUnit.MINUTES);
|
||||
} else {
|
||||
// Update online users
|
||||
updateTaskBuffer.request();
|
||||
}
|
||||
|
||||
// register tasks
|
||||
getProxy().getScheduler().schedule(this, BungeeSenderFactory.get(this), 50L, 50L, TimeUnit.MILLISECONDS); // 20 times per second (once per "tick")
|
||||
getProxy().getScheduler().schedule(this, new ExpireTemporaryTask(this), 3L, 3L, TimeUnit.SECONDS);
|
||||
getProxy().getScheduler().schedule(this, consecutiveExecutor, 1L, 1L, TimeUnit.SECONDS);
|
||||
|
||||
getLog().info("Successfully loaded.");
|
||||
}
|
||||
@ -160,6 +180,11 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
getLog().info("Closing datastore...");
|
||||
datastore.shutdown();
|
||||
|
||||
if (redisMessaging != null) {
|
||||
getLog().info("Closing redis...");
|
||||
redisMessaging.shutdown();
|
||||
}
|
||||
|
||||
getLog().info("Unregistering API...");
|
||||
ApiHandler.unregisterProvider();
|
||||
}
|
||||
|
@ -113,6 +113,19 @@ data:
|
||||
# e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources.
|
||||
sync-minutes: 3
|
||||
|
||||
# Settings for Redis.
|
||||
#
|
||||
# If enabled and configured, LuckPerms will use the Redis PubSub system to inform other
|
||||
# connected servers of changes. Use the command "/luckpermsbungee networksync" to push changes.
|
||||
# Data is NOT stored on redis. It is only used as a messaging platform.
|
||||
#
|
||||
# If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need for LuckPerms
|
||||
# to poll the database for changes.
|
||||
redis:
|
||||
enabled: false
|
||||
address: localhost:6379
|
||||
password: ''
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -39,6 +39,13 @@
|
||||
<version>2.5.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Jedis -->
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- SQLite -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
|
@ -35,6 +35,7 @@ import me.lucko.luckperms.common.contexts.ContextManager;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.data.Importer;
|
||||
import me.lucko.luckperms.common.groups.GroupManager;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessaging;
|
||||
import me.lucko.luckperms.common.storage.Datastore;
|
||||
import me.lucko.luckperms.common.tracks.TrackManager;
|
||||
import me.lucko.luckperms.common.users.UserManager;
|
||||
@ -60,6 +61,7 @@ public interface LuckPermsPlugin {
|
||||
TrackManager getTrackManager();
|
||||
LPConfiguration getConfiguration();
|
||||
Datastore getDatastore();
|
||||
RedisMessaging getRedisMessaging();
|
||||
Logger getLog();
|
||||
UuidCache getUuidCache();
|
||||
ApiProvider getApiProvider();
|
||||
|
@ -59,6 +59,7 @@ public class CommandManager {
|
||||
.add(new TrackMainCommand())
|
||||
.add(new LogMainCommand())
|
||||
.add(new SyncCommand())
|
||||
.add(new NetworkSyncCommand())
|
||||
.add(new InfoCommand())
|
||||
.add(new DebugCommand())
|
||||
.add(new ImportCommand())
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* 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 OR COPYRIGHT HOLDERS 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.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.commands.misc;
|
||||
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.commands.CommandResult;
|
||||
import me.lucko.luckperms.common.commands.Sender;
|
||||
import me.lucko.luckperms.common.commands.SingleMainCommand;
|
||||
import me.lucko.luckperms.common.constants.Message;
|
||||
import me.lucko.luckperms.common.constants.Permission;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NetworkSyncCommand extends SingleMainCommand {
|
||||
public NetworkSyncCommand() {
|
||||
super("NetworkSync", "/%s networksync", 0, Permission.SYNC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
|
||||
Message.UPDATE_TASK_REQUEST.send(sender);
|
||||
plugin.getUpdateTaskBuffer().request().getUnchecked();
|
||||
Message.UPDATE_TASK_COMPLETE_NETWORK.send(sender);
|
||||
|
||||
if (plugin.getRedisMessaging() != null) {
|
||||
plugin.getRedisMessaging().pushUpdate();
|
||||
Message.UPDATE_TASK_PUSH_SUCCESS.send(sender);
|
||||
} else {
|
||||
Message.UPDATE_TASK_PUSH_FAILURE.send(sender);
|
||||
}
|
||||
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
}
|
@ -74,6 +74,9 @@ public abstract class AbstractConfiguration<T extends LuckPermsPlugin> implement
|
||||
private String storageMethod;
|
||||
private boolean splitStorage;
|
||||
private Map<String, String> splitStorageOptions;
|
||||
private boolean redisEnabled;
|
||||
private String redisAddress;
|
||||
private String redisPassword;
|
||||
|
||||
public AbstractConfiguration(T plugin, String defaultServerName, boolean defaultIncludeGlobal, String defaultStorage) {
|
||||
this.plugin = plugin;
|
||||
@ -142,6 +145,10 @@ public abstract class AbstractConfiguration<T extends LuckPermsPlugin> implement
|
||||
.put("uuid", getString("split-storage.methods.uuid", defaultStorage))
|
||||
.put("log", getString("split-storage.methods.log", defaultStorage))
|
||||
.build();
|
||||
|
||||
redisEnabled = getBoolean("redis.enabled", false);
|
||||
redisAddress = getString("redis.address", null);
|
||||
redisPassword = getString("redis.password", "");
|
||||
|
||||
if (Patterns.NON_ALPHA_NUMERIC.matcher(getServer()).find()) {
|
||||
plugin.getLog().severe("Server name defined in config.yml contains invalid characters. Server names can " +
|
||||
|
@ -92,4 +92,10 @@ public interface LPConfiguration {
|
||||
|
||||
Map<String, String> getSplitStorageOptions();
|
||||
|
||||
boolean isRedisEnabled();
|
||||
|
||||
String getRedisAddress();
|
||||
|
||||
String getRedisPassword();
|
||||
|
||||
}
|
||||
|
@ -110,6 +110,9 @@ public enum Message {
|
||||
|
||||
UPDATE_TASK_REQUEST("&bUpdate task scheduled.", true),
|
||||
UPDATE_TASK_COMPLETE("&aUpdate task finished.", true),
|
||||
UPDATE_TASK_COMPLETE_NETWORK("&aUpdate task finished. Now attempting to push to other servers.", true),
|
||||
UPDATE_TASK_PUSH_SUCCESS("&aOther servers were notified successfully.", true),
|
||||
UPDATE_TASK_PUSH_FAILURE("&cError whilst pushing changes to other servers. Is Redis enabled?", true),
|
||||
INFO(
|
||||
"{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2." + "\n" +
|
||||
"{PREFIX}&f-> &3Platform: &f{1}" + "\n" +
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* 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 OR COPYRIGHT HOLDERS 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.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.messaging;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
import redis.clients.jedis.JedisPubSub;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Uses Redis to push/receive changes to/from other servers
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class RedisMessaging {
|
||||
private static final String CHANNEL = "luckperms";
|
||||
|
||||
private final LuckPermsPlugin plugin;
|
||||
private JedisPool jedisPool;
|
||||
private LPSub sub;
|
||||
|
||||
public void init(String address, String password) {
|
||||
String host = address.substring(0, address.indexOf(':'));
|
||||
int port = Integer.parseInt(address.substring(address.indexOf(":") + 1));
|
||||
|
||||
if (password.equals("")) {
|
||||
jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
|
||||
} else {
|
||||
jedisPool = new JedisPool(new JedisPoolConfig(), host, port, 0, password);
|
||||
}
|
||||
|
||||
plugin.doAsync(() -> {
|
||||
sub = new LPSub(plugin);
|
||||
try (Jedis jedis = jedisPool.getResource()) {
|
||||
jedis.subscribe(sub, CHANNEL);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
sub.unsubscribe();
|
||||
jedisPool.destroy();
|
||||
}
|
||||
|
||||
public void pushUpdate() {
|
||||
plugin.doAsync(() -> {
|
||||
UUID id = sub.generateId();
|
||||
plugin.getLog().info("[Redis Messaging] Sending redis ping with id: " + id.toString());
|
||||
try (Jedis jedis = jedisPool.getResource()) {
|
||||
jedis.publish(CHANNEL, "update:" + id.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class LPSub extends JedisPubSub {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final Set<UUID> receivedMsgs = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
public UUID generateId() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
receivedMsgs.add(uuid);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String channel, String msg) {
|
||||
if (!channel.equals(CHANNEL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg.startsWith("update:")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String requestId = msg.substring("update:".length());
|
||||
UUID uuid;
|
||||
try {
|
||||
uuid = UUID.fromString(requestId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!receivedMsgs.add(uuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getLog().info("[Redis Messaging] Received update ping with id: " + uuid.toString());
|
||||
plugin.getUpdateTaskBuffer().request();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -71,6 +71,9 @@ track-empty: "The track cannot be used as it is empty or contains only one group
|
||||
|
||||
update-task-request: "&bUpdate task scheduled."
|
||||
update-task-complete: "&aUpdate task finished."
|
||||
update-task-complete-network: "&aUpdate task finished. Now attempting to push to other servers."
|
||||
update-task-push-success: "&aOther servers were notified successfully."
|
||||
update-task-push-failure: "&cError whilst pushing changes to other servers. Is Redis enabled?"
|
||||
info: >
|
||||
{PREFIX}&2Running &bLuckPerms v{0}&2 by &bLuck&2.\n
|
||||
{PREFIX}&f-> &3Platform: &f{1}\n
|
||||
|
@ -68,6 +68,18 @@
|
||||
<pattern>com.mysql</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.mysql</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.jedis</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.jedis</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>redis.clients.util</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.util</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons.pool2</pattern>
|
||||
<shadedPattern>me.lucko.luckperms.lib.jedis.pool2</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -40,6 +40,7 @@ import me.lucko.luckperms.common.contexts.ServerCalculator;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
import me.lucko.luckperms.common.data.Importer;
|
||||
import me.lucko.luckperms.common.groups.GroupManager;
|
||||
import me.lucko.luckperms.common.messaging.RedisMessaging;
|
||||
import me.lucko.luckperms.common.runnables.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.runnables.UpdateTask;
|
||||
import me.lucko.luckperms.common.storage.Datastore;
|
||||
@ -107,6 +108,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Datastore datastore;
|
||||
private RedisMessaging redisMessaging = null;
|
||||
private UuidCache uuidCache;
|
||||
private ApiProvider apiProvider;
|
||||
private me.lucko.luckperms.api.Logger log;
|
||||
@ -125,6 +127,37 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new SpongeConfig(this);
|
||||
|
||||
// register events
|
||||
Sponge.getEventManager().registerListeners(this, new SpongeListener(this));
|
||||
|
||||
// initialise datastore
|
||||
datastore = StorageFactory.getDatastore(this, "h2");
|
||||
|
||||
// initialise redis
|
||||
if (getConfiguration().isRedisEnabled()) {
|
||||
getLog().info("Loading redis...");
|
||||
redisMessaging = new RedisMessaging(this);
|
||||
try {
|
||||
redisMessaging.init(getConfiguration().getRedisAddress(), getConfiguration().getRedisPassword());
|
||||
getLog().info("Loaded redis successfully...");
|
||||
} catch (Exception e) {
|
||||
getLog().info("Couldn't load redis...");
|
||||
e.printStackTrace();
|
||||
redisMessaging = null;
|
||||
}
|
||||
}
|
||||
|
||||
// setup the update task buffer
|
||||
final LPSpongePlugin i = this;
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
scheduler.createTaskBuilder().async().execute(new UpdateTask(i)).submit(i);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// load locale
|
||||
localeManager = new LocaleManager();
|
||||
File locale = new File(getMainDir(), "lang.yml");
|
||||
if (locale.exists()) {
|
||||
@ -136,17 +169,13 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
// register events
|
||||
Sponge.getEventManager().registerListeners(this, new SpongeListener(this));
|
||||
|
||||
// register commands
|
||||
getLog().info("Registering commands...");
|
||||
CommandManager cmdService = Sponge.getCommandManager();
|
||||
SpongeCommand commandManager = new SpongeCommand(this);
|
||||
cmdService.register(this, commandManager, "luckperms", "perms", "lp", "permissions", "p", "perm");
|
||||
|
||||
datastore = StorageFactory.getDatastore(this, "h2");
|
||||
|
||||
// load internal managers
|
||||
getLog().info("Loading internal permission managers...");
|
||||
uuidCache = new UuidCache(getConfiguration().isOnlineMode());
|
||||
userManager = new UserManager(this);
|
||||
@ -160,23 +189,17 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
contextManager.registerCalculator(new ServerCalculator<>(getConfiguration().getServer()));
|
||||
contextManager.registerCalculator(new WorldCalculator(this));
|
||||
|
||||
// register the PermissionService with Sponge
|
||||
getLog().info("Registering PermissionService...");
|
||||
Sponge.getServiceManager().setProvider(this, PermissionService.class, (service = new LuckPermsService(this)));
|
||||
|
||||
// register with the LP API
|
||||
getLog().info("Registering API...");
|
||||
apiProvider = new ApiProvider(this);
|
||||
ApiHandler.registerProvider(apiProvider);
|
||||
Sponge.getServiceManager().setProvider(this, LuckPermsApi.class, apiProvider);
|
||||
|
||||
final LPSpongePlugin i = this;
|
||||
updateTaskBuffer = new BufferedRequest<Void>(1000L, this::doAsync) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
scheduler.createTaskBuilder().async().execute(new UpdateTask(i)).submit(i);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// schedule update tasks
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
scheduler.createTaskBuilder().async().interval(mins, TimeUnit.MINUTES).execute(new UpdateTask(this))
|
||||
@ -186,6 +209,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
updateTaskBuffer.request();
|
||||
}
|
||||
|
||||
// register tasks
|
||||
scheduler.createTaskBuilder().intervalTicks(1L).execute(SpongeSenderFactory.get(this)).submit(this);
|
||||
scheduler.createTaskBuilder().async().intervalTicks(60L).execute(new ExpireTemporaryTask(this)).submit(this);
|
||||
scheduler.createTaskBuilder().async().intervalTicks(20L).execute(consecutiveExecutor).submit(this);
|
||||
@ -198,6 +222,11 @@ public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
getLog().info("Closing datastore...");
|
||||
datastore.shutdown();
|
||||
|
||||
if (redisMessaging != null) {
|
||||
getLog().info("Closing redis...");
|
||||
redisMessaging.shutdown();
|
||||
}
|
||||
|
||||
getLog().info("Unregistering API...");
|
||||
ApiHandler.unregisterProvider();
|
||||
}
|
||||
|
@ -114,6 +114,20 @@ data {
|
||||
sync-minutes=3
|
||||
}
|
||||
|
||||
# Settings for Redis.
|
||||
#
|
||||
# If enabled and configured, LuckPerms will use the Redis PubSub system to inform other
|
||||
# connected servers of changes. Use the command "/luckperms networksync" to push changes.
|
||||
# Data is NOT stored on redis. It is only used as a messaging platform.
|
||||
#
|
||||
# If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need for LuckPerms
|
||||
# to poll the database for changes.
|
||||
redis {
|
||||
enabled=false
|
||||
address="localhost:6379"
|
||||
password=""
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user