-
-
Notifications
You must be signed in to change notification settings - Fork 21
GH-930 Msg placeholders & Async placeholder for future #1203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 8 commits
b3764bd
af593f1
1f98392
cf7151e
1407a28
a8c6659
2633ef6
dc6f963
aa360dd
a128154
6e7e842
81b610e
450a2d7
9f0d5eb
3e5a511
082e063
229af5e
7b5eee0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| package com.eternalcode.core.feature.msg; | ||
|
|
||
| import com.eternalcode.core.feature.msg.toggle.MsgState; | ||
| import com.eternalcode.core.feature.msg.toggle.MsgToggleRepository; | ||
| import com.eternalcode.core.injector.annotations.Inject; | ||
| import com.eternalcode.core.injector.annotations.component.Controller; | ||
| import com.eternalcode.core.placeholder.PlaceholderRegistry; | ||
| import com.eternalcode.core.placeholder.PlaceholderReplacer; | ||
| import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCacheRegistry; | ||
| import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCached; | ||
| import com.eternalcode.core.publish.Subscribe; | ||
| import com.eternalcode.core.publish.event.EternalInitializeEvent; | ||
| import com.eternalcode.core.translation.Translation; | ||
| import com.eternalcode.core.translation.TranslationManager; | ||
| import java.time.Duration; | ||
| import java.util.UUID; | ||
|
|
||
| @Controller | ||
| public class MsgPlaceholderSetup { | ||
|
|
||
| public static final String MSG_STATE_CACHE_KEY = "msg_state"; | ||
|
|
||
| private final MsgService msgService; | ||
| private final MsgToggleRepository msgToggleRepository; | ||
| private final TranslationManager translationManager; | ||
| private final AsyncPlaceholderCacheRegistry cacheRegistry; | ||
|
|
||
| @Inject | ||
| MsgPlaceholderSetup( | ||
| MsgService msgService, | ||
| MsgToggleRepository msgToggleRepository, | ||
| TranslationManager translationManager, | ||
| AsyncPlaceholderCacheRegistry cacheRegistry | ||
| ) { | ||
| this.msgService = msgService; | ||
| this.msgToggleRepository = msgToggleRepository; | ||
| this.translationManager = translationManager; | ||
| this.cacheRegistry = cacheRegistry; | ||
| } | ||
|
|
||
| @Subscribe(EternalInitializeEvent.class) | ||
| void setUpPlaceholders(PlaceholderRegistry placeholderRegistry) { | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Translation translation = this.translationManager.getMessages(); | ||
|
|
||
| AsyncPlaceholderCached<MsgState> stateCache = this.cacheRegistry.register( | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| MSG_STATE_CACHE_KEY, | ||
| this.msgToggleRepository::getPrivateChatState, | ||
| Duration.ofMinutes(10) | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
|
|
||
| placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( | ||
| "socialspy_status", | ||
| player -> String.valueOf(this.msgService.isSpy(player.getUniqueId())) | ||
Rollczi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Rollczi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| )); | ||
|
|
||
| placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "socialspy_status_formatted", | ||
| player -> { | ||
| UUID uuid = player.getUniqueId(); | ||
| return this.msgService.isSpy(uuid) | ||
| ? translation.msg().placeholders().socialSpyEnabled() | ||
| : translation.msg().placeholders().socialSpyDisabled(); | ||
| } | ||
| )); | ||
|
|
||
| placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( | ||
| "msg_status", | ||
| player -> { | ||
| UUID uuid = player.getUniqueId(); | ||
| MsgState state = stateCache.getCached(uuid); | ||
|
|
||
| if (state == null) { | ||
| return translation.msg().placeholders().loading(); | ||
| } | ||
|
|
||
| return state.name().toLowerCase(); | ||
| } | ||
| )); | ||
|
|
||
| placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of( | ||
| "msg_status_formatted", | ||
| player -> { | ||
| UUID uuid = player.getUniqueId(); | ||
| MsgState state = stateCache.getCached(uuid); | ||
|
|
||
| if (state == null) { | ||
| return translation.msg().placeholders().loading(); | ||
| } | ||
|
|
||
| return state == MsgState.ENABLED | ||
| ? translation.msg().placeholders().msgEnabled() | ||
| : translation.msg().placeholders().msgDisabled(); | ||
| } | ||
| )); | ||
P1otrulla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -36,4 +36,22 @@ public class ENMsgMessages extends OkaeriConfig implements MsgMessages { | |||||
| public Notice socialSpyEnable = Notice.chat("<green>► <white>SocialSpy has been {STATE}<white>!"); | ||||||
| public Notice socialSpyDisable = Notice.chat("<red>► <white>SocialSpy has been {STATE}<white>!"); | ||||||
|
|
||||||
| @Comment("# Formatowanie placeholderów") | ||||||
P1otrulla marked this conversation as resolved.
Show resolved
Hide resolved
CitralFlo marked this conversation as resolved.
Show resolved
Hide resolved
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is EN translation, so we use English comments
Suggested change
|
||||||
| public ENPlaceholders placeholders = new ENPlaceholders(); | ||||||
|
|
||||||
| @Getter | ||||||
| @Accessors(fluent = true) | ||||||
| public static class ENPlaceholders extends OkaeriConfig implements MsgMessages.Placeholders { | ||||||
CitralFlo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| private String loading = "<yellow>Loading..."; | ||||||
|
|
||||||
| private String msgEnabled = "<green>Enabled"; | ||||||
| private String msgDisabled = "<red>Disabled"; | ||||||
| private String socialSpyEnabled = "<green>Enabled"; | ||||||
| private String socialSpyDisabled = "<red>Disabled"; | ||||||
| } | ||||||
|
|
||||||
| public ENPlaceholders placeholders() { | ||||||
| return this.placeholders; | ||||||
| } | ||||||
|
|
||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,41 +1,40 @@ | ||
| package com.eternalcode.core.feature.msg.toggle; | ||
|
|
||
| import com.eternalcode.core.feature.msg.MsgPlaceholderSetup; | ||
| import com.eternalcode.core.injector.annotations.Inject; | ||
| import com.eternalcode.core.injector.annotations.component.Service; | ||
| import com.eternalcode.core.placeholder.cache.AsyncPlaceholderCacheRegistry; | ||
| import java.util.UUID; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
|
|
||
| @Service | ||
| class MsgToggleServiceImpl implements MsgToggleService { | ||
Rollczi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private final MsgToggleRepository msgToggleRepository; | ||
| private final ConcurrentHashMap<UUID, MsgState> cachedToggleStates; | ||
| private final AsyncPlaceholderCacheRegistry cacheRegistry; | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| @Inject | ||
| MsgToggleServiceImpl(MsgToggleRepository msgToggleRepository) { | ||
| this.cachedToggleStates = new ConcurrentHashMap<>(); | ||
| MsgToggleServiceImpl(MsgToggleRepository msgToggleRepository, AsyncPlaceholderCacheRegistry cacheRegistry) { | ||
| this.msgToggleRepository = msgToggleRepository; | ||
|
|
||
| this.cacheRegistry = cacheRegistry; | ||
| } | ||
|
|
||
|
|
||
| @Override | ||
| public CompletableFuture<MsgState> getState(UUID playerUniqueId) { | ||
| if (this.cachedToggleStates.containsKey(playerUniqueId)) { | ||
| return CompletableFuture.completedFuture(this.cachedToggleStates.get(playerUniqueId)); | ||
| } | ||
|
|
||
| return this.msgToggleRepository.getPrivateChatState(playerUniqueId); | ||
| return this.msgToggleRepository.getPrivateChatState(playerUniqueId) | ||
| .thenApply(state -> { | ||
| this.updateCache(playerUniqueId, state); | ||
| return state; | ||
| }); | ||
| } | ||
|
|
||
| @Override | ||
| public CompletableFuture<Void> setState(UUID playerUniqueId, MsgState state) { | ||
| this.cachedToggleStates.put(playerUniqueId, state); | ||
| this.updateCache(playerUniqueId, state); | ||
|
|
||
| return this.msgToggleRepository.setPrivateChatState(playerUniqueId, state) | ||
| .exceptionally(throwable -> { | ||
| this.cachedToggleStates.remove(playerUniqueId); | ||
| this.invalidateCache(playerUniqueId); | ||
| return null; | ||
| }); | ||
| } | ||
|
Comment on lines
23
to
32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous implementation of this service used a The new |
||
|
|
@@ -48,4 +47,14 @@ public CompletableFuture<MsgState> toggleState(UUID playerUniqueId) { | |
| .thenApply(aVoid -> newState); | ||
| }); | ||
| } | ||
|
|
||
| private void updateCache(UUID uuid, MsgState state) { | ||
| this.cacheRegistry.<MsgState>get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) | ||
| .ifPresent(cache -> cache.update(uuid, state)); | ||
| } | ||
|
|
||
| private void invalidateCache(UUID uuid) { | ||
| this.cacheRegistry.<MsgState>get(MsgPlaceholderSetup.MSG_STATE_CACHE_KEY) | ||
| .ifPresent(cache -> cache.invalidate(uuid)); | ||
P1otrulla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package com.eternalcode.core.placeholder.cache; | ||
|
|
||
| import com.eternalcode.core.injector.annotations.Inject; | ||
| import com.eternalcode.core.injector.annotations.component.Controller; | ||
| import com.eternalcode.core.publish.Subscribe; | ||
| import com.eternalcode.core.publish.event.EternalReloadEvent; | ||
| import com.eternalcode.core.publish.event.EternalShutdownEvent; | ||
| import org.bukkit.event.EventHandler; | ||
| import org.bukkit.event.EventPriority; | ||
| import org.bukkit.event.Listener; | ||
| import org.bukkit.event.player.PlayerQuitEvent; | ||
|
|
||
| @Controller | ||
| class AsyncPlaceholderCacheController implements Listener { | ||
|
|
||
| private final AsyncPlaceholderCacheRegistry cacheRegistry; | ||
|
|
||
| @Inject | ||
| AsyncPlaceholderCacheController(AsyncPlaceholderCacheRegistry cacheRegistry) { | ||
| this.cacheRegistry = cacheRegistry; | ||
| } | ||
|
|
||
| @EventHandler(priority = EventPriority.MONITOR) | ||
| void onPlayerQuit(PlayerQuitEvent event) { | ||
| this.cacheRegistry.invalidatePlayer(event.getPlayer().getUniqueId()); | ||
| } | ||
|
|
||
| @Subscribe | ||
| void onDisable(EternalShutdownEvent event) { | ||
| this.cacheRegistry.invalidateAll(); | ||
| } | ||
|
|
||
| @Subscribe | ||
| void onReload(EternalReloadEvent event) { | ||
| this.cacheRegistry.invalidateAll(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package com.eternalcode.core.placeholder.cache; | ||
|
|
||
| import com.eternalcode.core.injector.annotations.Inject; | ||
| import com.eternalcode.core.injector.annotations.component.Service; | ||
| import java.time.Duration; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import java.util.UUID; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.function.Function; | ||
|
|
||
| @Service | ||
| public class AsyncPlaceholderCacheRegistry { | ||
|
|
||
| private static final Duration DEFAULT_EXPIRE_DURATION = Duration.ofMinutes(30); | ||
|
|
||
| private final Map<String, AsyncPlaceholderCached<?>> caches = new ConcurrentHashMap<>(); | ||
|
|
||
| @Inject | ||
| public AsyncPlaceholderCacheRegistry() { | ||
| } | ||
|
|
||
| public <T> AsyncPlaceholderCached<T> register(String key, Function<UUID, CompletableFuture<T>> loader) { | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return this.register(key, loader, DEFAULT_EXPIRE_DURATION); | ||
| } | ||
|
|
||
| public <T> AsyncPlaceholderCached<T> register(String key, Function<UUID, CompletableFuture<T>> loader, Duration expireAfterWrite) { | ||
| AsyncPlaceholderCached<T> cache = new AsyncPlaceholderCached<>(loader, expireAfterWrite); | ||
| this.caches.put(key, cache); | ||
| return cache; | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| public <T> Optional<AsyncPlaceholderCached<T>> get(String key) { | ||
| return Optional.ofNullable((AsyncPlaceholderCached<T>) this.caches.get(key)); | ||
| } | ||
|
|
||
| public void invalidatePlayer(UUID uuid) { | ||
| this.caches.values().forEach(cache -> cache.invalidate(uuid)); | ||
| } | ||
|
|
||
| public void invalidateAll() { | ||
| this.caches.values().forEach(AsyncPlaceholderCached::clear); | ||
| } | ||
|
|
||
| public void unregister(String key) { | ||
| AsyncPlaceholderCached<?> cache = this.caches.remove(key); | ||
| if (cache != null) { | ||
| cache.clear(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.eternalcode.core.placeholder.cache; | ||
|
|
||
| import com.google.common.cache.Cache; | ||
| import com.google.common.cache.CacheBuilder; | ||
| import java.time.Duration; | ||
| import java.util.UUID; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.function.Function; | ||
|
|
||
| public class AsyncPlaceholderCached<T> { | ||
|
|
||
| private final Cache<UUID, T> cache; | ||
| private final Function<UUID, CompletableFuture<T>> loader; | ||
|
|
||
| public AsyncPlaceholderCached(Function<UUID, CompletableFuture<T>> loader, Duration expireAfterWrite) { | ||
| this.loader = loader; | ||
| this.cache = CacheBuilder.newBuilder() | ||
| .expireAfterWrite(expireAfterWrite) | ||
| .build(); | ||
| } | ||
|
|
||
| public T getCached(UUID uuid) { | ||
CitralFlo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| T cached = this.cache.getIfPresent(uuid); | ||
|
|
||
| if (cached != null) { | ||
| return cached; | ||
| } | ||
|
|
||
| this.loader.apply(uuid).thenAccept(value -> | ||
| this.cache.put(uuid, value) | ||
| ); | ||
|
|
||
| return null; | ||
| } | ||
P1otrulla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| public void update(UUID uuid, T value) { | ||
| this.cache.put(uuid, value); | ||
| } | ||
|
|
||
| public void invalidate(UUID uuid) { | ||
| this.cache.invalidate(uuid); | ||
| } | ||
|
|
||
| public void clear() { | ||
| this.cache.invalidateAll(); | ||
| } | ||
|
|
||
| public boolean contains(UUID uuid) { | ||
| return this.cache.getIfPresent(uuid) != null; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.