Skip to content

Commit

Permalink
chore: Service and rank permissions improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
phinner committed May 16, 2024
1 parent 5e4f598 commit 4f0bfd8
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,40 @@

public interface ServiceManager {

<T> void register(final MindustryPlugin plugin, final Class<T> clazz, final Priority priority, final T instance);
<T> void register(final MindustryPlugin plugin, final Class<T> service, final T instance, final Priority priority);

default <T> T provide(final Class<T> clazz) {
return provideOrDefault(clazz, () -> {
throw new IllegalStateException("Expected provider for " + clazz.getCanonicalName() + ", got nothing.");
default <T> void register(final MindustryPlugin plugin, final Class<T> service, final T instance) {
this.register(plugin, service, instance, Priority.NORMAL);
}

default <T> T provide(final Class<T> service) {
return provideOrDefault(service, () -> {
throw new IllegalStateException("Expected provider for " + service.getCanonicalName() + ", got nothing.");
});
}

default <T> T provideOrDefault(final Class<T> clazz, final Supplier<T> factory) {
final var providers = this.getProviders(clazz);
default <T> T provideOrDefault(final Class<T> service, final Supplier<T> factory) {
final var providers = this.getProviders(service);
return providers.isEmpty() ? factory.get() : providers.get(0).getInstance();
}

<T> List<Provider<T>> getProviders(final Class<T> clazz);
<T> List<Provider<T>> getProviders(final Class<T> service);

@DistributorDataClass
@Value.Immutable
sealed interface Provider<T> permits ProviderImpl {

static <T> Provider<T> of(
final MindustryPlugin plugin, final Class<T> clazz, final Priority priority, final T instance) {
return ProviderImpl.of(plugin, clazz, priority, instance);
final MindustryPlugin plugin, final Class<T> service, final T instance, final Priority priority) {
return ProviderImpl.of(plugin, service, instance, priority);
}

MindustryPlugin getPlugin();

Class<T> getClazz();

Priority getPriority();
Class<T> getService();

T getInstance();

Priority getPriority();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public PluginScheduler getPluginScheduler() {

@Override
public void onInit() {
this.getLogger().info("Loading distributor api");
this.getLogger().info("Loading distributor common api");
DistributorProvider.set(this);
this.getGlobalTranslationSource().register(TranslationSource.router());
this.addListener((PluginSchedulerImpl) this.scheduler);
Expand All @@ -89,7 +89,7 @@ public void onInit() {
public void onLoad() {
this.lookup = services.provideOrDefault(PlayerLookup.class, PlayerLookup::create);
this.permissions = services.provideOrDefault(PermissionReader.class, PermissionReader::empty);
this.getLogger().info("Loaded distributor api");
this.getLogger().info("Loaded distributor common api");
}

private <T> T ensureInitialized(final @Nullable T instance, final String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@ public final class ServiceManagerImpl implements ServiceManager {

@Override
public <T> void register(
final MindustryPlugin plugin, final Class<T> clazz, final Priority priority, final T instance) {
final MindustryPlugin plugin, final Class<T> service, final T instance, final Priority priority) {
synchronized (this.lock) {
this.services
.computeIfAbsent(
clazz, k -> new PriorityQueue<Provider<?>>(Comparator.comparing(Provider::getPriority)))
.add(Provider.of(plugin, clazz, priority, instance));
service, k -> new PriorityQueue<Provider<?>>(Comparator.comparing(Provider::getPriority)))
.add(Provider.of(plugin, service, instance, priority));
}
}

@SuppressWarnings("unchecked")
@Override
public <T> List<Provider<T>> getProviders(final Class<T> clazz) {
public <T> List<Provider<T>> getProviders(final Class<T> service) {
synchronized (this.lock) {
final Object implementation = this.services.get(clazz);
final Object implementation = this.services.get(service);
return implementation != null
? List.copyOf((Collection<? extends Provider<T>>) implementation)
: Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ public final class DistributorPermissionRankPlugin extends AbstractMindustryPlug
public void onInit() {
final var services = DistributorProvider.get().getServiceManager();

services.register(this, PermissionReader.class, Priority.HIGH, new RankPermissionReader());
services.register(this, RankSource.class, Priority.LOW, new MindustryRankSource());
services.register(this, PermissionReader.class, new RankPermissionReader(), Priority.HIGH);
services.register(this, RankSource.class, new MindustryRankSource(), Priority.LOW);
final var source = new YamlRankPermissionSource(() -> Files.newBufferedReader(this.getConfigFile()));
this.addListener(source);
services.register(this, RankPermissionSource.class, Priority.NORMAL, source);
services.register(this, RankPermissionSource.class, Priority.LOW, new MindustryRankPermissionSource());
services.register(this, RankPermissionSource.class, source);
services.register(this, RankPermissionSource.class, new MindustryRankPermissionSource(), Priority.LOW);

this.getLogger().info("Initialized distributor permission rank plugin");
}
Expand All @@ -51,7 +51,7 @@ private Path getConfigFile() throws IOException {
.getResourceAsStream("com/xpdustry/distributor/api/permission/rank/default.yaml"))) {
Files.copy(stream, path);
} catch (final IOException error) {
throw new IOException("Failed to create the default permission file.", error);
throw new IOException("Failed to create the default permission file", error);
}
}
return path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
*/
public interface RankNode {

Pattern NAME_PATTERN = Pattern.compile("^[\\w:]+$");
Pattern NAME_PATTERN = Pattern.compile("^\\w+$");

/**
* Returns the name of this rank node.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -81,27 +82,28 @@ public PermissionTree getRankPermissions(final RankNode node) {
}

private PermissionTree getRankPermissions0(final RankNode node, final Set<RankNode> visited) {
if (!RankNode.NAME_PATTERN.matcher(node.getName()).matches()) {
final var name = node.getName().toLowerCase(Locale.ROOT);
if (!RankNode.NAME_PATTERN.matcher(name).matches()) {
return PermissionTree.empty();
}
final var cached = this.cache.get(node.getName());
final var cached = this.cache.get(name);
if (cached != null) {
return cached;
}
final var tree = MutablePermissionTree.create();
final var previous = node.getPrevious();
if (previous != null) {
if (!visited.add(node)) {
throw new IllegalStateException("Circular rank node: " + node.getName());
throw new IllegalStateException("Circular rank node: " + name);
}
tree.setPermissions(getRankPermissions0(previous, visited));
}
final var permissions = this.permissions.get(node.getName());
final var permissions = this.permissions.get(name);
if (permissions != null) {
tree.setPermissions(permissions, true);
}
final var immutable = PermissionTree.from(tree);
this.cache.put(node.getName(), immutable);
this.cache.put(name, immutable);
return immutable;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public final class RankPermissionReaderTest {
void setup() {
this.reader = new RankPermissionReader();
this.services = new ServiceManagerImpl();
this.services.register(plugin, RankSource.class, Priority.NORMAL, rankSource);
this.services.register(plugin, RankSource.class, rankSource, Priority.NORMAL);
final var distributor = Mockito.mock(Distributor.class);
Mockito.when(distributor.getServiceManager()).thenReturn(this.services);
DistributorProvider.set(distributor);
Expand All @@ -79,7 +79,7 @@ void test_simple() {
final var permissionSource = Mockito.mock(RankPermissionSource.class);
Mockito.when(permissionSource.getRankPermissions(rank1)).thenReturn(permissions1);
Mockito.when(permissionSource.getRankPermissions(rank2)).thenReturn(permissions2);
this.services.register(this.plugin, RankPermissionSource.class, Priority.NORMAL, permissionSource);
this.services.register(this.plugin, RankPermissionSource.class, permissionSource, Priority.NORMAL);

assertThat(this.reader.getPermission(this.player1, "test")).isEqualTo(TriState.FALSE);
assertThat(this.reader.getPermission(this.player1, "unknown")).isEqualTo(TriState.UNDEFINED);
Expand Down

0 comments on commit 4f0bfd8

Please sign in to comment.