Implement support for instant data propagation with Redis

This commit is contained in:
Luck 2016-10-24 14:38:12 +01:00
parent bb9eab0989
commit 2cfc82f3aa
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
19 changed files with 452 additions and 72 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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: ''

View File

@ -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>

View File

@ -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();
}

View File

@ -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: ''

View File

@ -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>

View File

@ -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();

View File

@ -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())

View File

@ -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;
}
}

View File

@ -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 " +

View File

@ -92,4 +92,10 @@ public interface LPConfiguration {
Map<String, String> getSplitStorageOptions();
boolean isRedisEnabled();
String getRedisAddress();
String getRedisPassword();
}

View File

@ -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" +

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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>

View File

@ -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();
}

View File

@ -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=""
}