Skip to content

Commit

Permalink
feat: portable grid interactions
Browse files Browse the repository at this point in the history
Generalizes grid watcher registration management code.
  • Loading branch information
raoulvdberge committed Jan 2, 2024
1 parent fc6d121 commit eea3eee
Show file tree
Hide file tree
Showing 29 changed files with 362 additions and 180 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.refinedmods.refinedstorage2.api.grid.operations;

import com.refinedmods.refinedstorage2.api.storage.ExtractableStorage;
import com.refinedmods.refinedstorage2.api.storage.InsertableStorage;

public class NoopGridOperations<T> implements GridOperations<T> {
@Override
public boolean extract(final T resource,
final GridExtractMode extractMode,
final InsertableStorage<T> destination) {
return false;
}

@Override
public boolean insert(final T resource,
final GridInsertMode insertMode,
final ExtractableStorage<T> source) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.refinedmods.refinedstorage2.api.grid.watcher;

import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannel;
import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannelType;

import java.util.Set;

import org.apiguardian.api.API;

/**
* Provides the {@link GridWatcherManagerImpl} with {@link StorageChannel}s.
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.3.3")
public interface GridStorageChannelProvider {
Set<StorageChannelType<?>> getStorageChannelTypes();

<T> StorageChannel<T> getStorageChannel(StorageChannelType<T> type);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.refinedmods.refinedstorage2.api.grid;
package com.refinedmods.refinedstorage2.api.grid.watcher;

import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannelType;
import com.refinedmods.refinedstorage2.api.storage.tracked.TrackedResource;
Expand Down Expand Up @@ -38,5 +38,5 @@ <T> void onChanged(
/**
* Usually called when the grid network has been changed.
*/
void clear();
void invalidate();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.refinedmods.refinedstorage2.api.grid.watcher;

import com.refinedmods.refinedstorage2.api.storage.Actor;

import org.apiguardian.api.API;

/**
* This manager helps with attaching and detaching listeners to
* {@link com.refinedmods.refinedstorage2.api.storage.channel.StorageChannel}s.
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.3.3")
public interface GridWatcherManager {
void addWatcher(
GridWatcher watcher,
Class<? extends Actor> actorType,
GridStorageChannelProvider storageChannelProvider
);

void attachAll(GridStorageChannelProvider storageChannelProvider);

void removeWatcher(GridWatcher watcher, GridStorageChannelProvider storageChannelProvider);

void detachAll(GridStorageChannelProvider storageChannelProvider);

void activeChanged(boolean active);
}
Original file line number Diff line number Diff line change
@@ -1,105 +1,110 @@
package com.refinedmods.refinedstorage2.api.network.impl.node.grid;
package com.refinedmods.refinedstorage2.api.grid.watcher;

import com.refinedmods.refinedstorage2.api.grid.GridWatcher;
import com.refinedmods.refinedstorage2.api.network.Network;
import com.refinedmods.refinedstorage2.api.network.component.StorageNetworkComponent;
import com.refinedmods.refinedstorage2.api.storage.Actor;
import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannel;
import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannelType;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apiguardian.api.API;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GridWatchers {
public static final Logger LOGGER = LoggerFactory.getLogger(GridWatchers.class);
// TODO: test.
@API(status = API.Status.STABLE, since = "2.0.0-milestone.3.3")
public class GridWatcherManagerImpl implements GridWatcherManager {
private static final Logger LOGGER = LoggerFactory.getLogger(GridWatcherManagerImpl.class);

private final Collection<? extends StorageChannelType<?>> storageChannelTypes;
private final Map<GridWatcher, GridWatcherRegistration> watchers = new HashMap<>();

public GridWatchers(final Collection<? extends StorageChannelType<?>> storageChannelTypes) {
this.storageChannelTypes = storageChannelTypes;
}

private <T> StorageChannel<T> getStorageChannel(final Network network, final StorageChannelType<T> type) {
return network.getComponent(StorageNetworkComponent.class).getStorageChannel(type);
}

@Override
public void addWatcher(
final GridWatcher watcher,
final Class<? extends Actor> actorType,
final Network network
final GridStorageChannelProvider storageChannelProvider
) {
if (watchers.containsKey(watcher)) {
throw new IllegalArgumentException("Watcher is already registered");
}
final GridWatcherRegistration registration = new GridWatcherRegistration(watcher, actorType);
attachAll(registration, network, false);
attachAll(registration, storageChannelProvider, false);
watchers.put(watcher, registration);
LOGGER.info("Added watcher {}, new count is {}", watcher, watchers.size());
}

public void attachAll(final Network network) {
@Override
public void attachAll(final GridStorageChannelProvider storageChannelProvider) {
// If we get here we are affected by a network split or network merge.
// At this point, all the storages that are affected by the split or merge have not yet been processed
// as the grid has the highest priority.
watchers.forEach((watcher, registration) -> {
// Invalidate all watcher data, the resources that were synced earlier are no longer valid because we have
// a brand-new network.
watcher.clear();
watcher.invalidate();
// Re-attach the watcher to the new network, and send all the resources from the new network.
// Resources from the old network are not part of the new network yet, as mentioned above,
// but those will be synced when the storages are re-added.
attachAll(registration, network, true);
attachAll(registration, storageChannelProvider, true);
});
}

private void attachAll(final GridWatcherRegistration registration, final Network network, final boolean replay) {
storageChannelTypes.forEach(storageChannelType -> attach(registration, storageChannelType, network, replay));
private void attachAll(final GridWatcherRegistration registration,
final GridStorageChannelProvider storageChannelProvider,
final boolean replay) {
storageChannelProvider.getStorageChannelTypes().forEach(storageChannelType -> attach(
registration,
storageChannelType,
storageChannelProvider,
replay
));
}

private <T> void attach(
final GridWatcherRegistration registration,
final StorageChannelType<T> storageChannelType,
final Network network,
final GridStorageChannelProvider storageChannelProvider,
final boolean replay
) {
LOGGER.info("Attaching {} to {}", registration, storageChannelType);
final StorageChannel<T> storageChannel = getStorageChannel(network, storageChannelType);
registration.attach(storageChannel, storageChannelType, replay);
registration.attach(storageChannelProvider.getStorageChannel(storageChannelType), storageChannelType, replay);
}

public void removeWatcher(final GridWatcher watcher, final Network network) {
@Override
public void removeWatcher(final GridWatcher watcher, final GridStorageChannelProvider storageChannelProvider) {
final GridWatcherRegistration registration = watchers.get(watcher);
if (registration == null) {
throw new IllegalArgumentException("Watcher is not registered");
}
detachAll(registration, network);
detachAll(registration, storageChannelProvider);
watchers.remove(watcher);
LOGGER.info("Removed watcher {}, remaining {}", watcher, watchers.size());
}

public void detachAll(final Network network) {
@Override
public void detachAll(final GridStorageChannelProvider storageChannelProvider) {
LOGGER.info("Detaching {} watchers", watchers.size());
watchers.values().forEach(w -> detachAll(w, network));
watchers.values().forEach(w -> detachAll(w, storageChannelProvider));
}

private void detachAll(final GridWatcherRegistration registration, final Network network) {
storageChannelTypes.forEach(storageChannelType -> detach(registration, storageChannelType, network));
private void detachAll(final GridWatcherRegistration registration,
final GridStorageChannelProvider storageChannelProvider) {
storageChannelProvider.getStorageChannelTypes().forEach(storageChannelType -> detach(
registration,
storageChannelType,
storageChannelProvider
));
}

private <T> void detach(
final GridWatcherRegistration registration,
final StorageChannelType<T> storageChannelType,
final Network network
final GridStorageChannelProvider storageChannelProvider
) {
LOGGER.info("Detaching {} from {}", registration, storageChannelType);
registration.detach(getStorageChannel(network, storageChannelType), storageChannelType);
registration.detach(storageChannelProvider.getStorageChannel(storageChannelType), storageChannelType);
}

@Override
public void activeChanged(final boolean active) {
watchers.keySet().forEach(watcher -> watcher.onActiveChanged(active));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.refinedmods.refinedstorage2.api.network.impl.node.grid;
package com.refinedmods.refinedstorage2.api.grid.watcher;

import com.refinedmods.refinedstorage2.api.grid.GridWatcher;
import com.refinedmods.refinedstorage2.api.resource.list.listenable.ResourceListListener;
import com.refinedmods.refinedstorage2.api.storage.Actor;
import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@ParametersAreNonnullByDefault
@FieldsAndMethodsAreNonnullByDefault
package com.refinedmods.refinedstorage2.api.grid;
package com.refinedmods.refinedstorage2.api.grid.watcher;

import com.refinedmods.refinedstorage2.api.core.FieldsAndMethodsAreNonnullByDefault;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.refinedmods.refinedstorage2.api.network.component;

import com.refinedmods.refinedstorage2.api.grid.watcher.GridStorageChannelProvider;
import com.refinedmods.refinedstorage2.api.storage.Actor;
import com.refinedmods.refinedstorage2.api.storage.Storage;
import com.refinedmods.refinedstorage2.api.storage.TrackedResourceAmount;
Expand All @@ -12,7 +13,7 @@
import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.1.1")
public interface StorageNetworkComponent extends NetworkComponent {
public interface StorageNetworkComponent extends NetworkComponent, GridStorageChannelProvider {
<T> StorageChannel<T> getStorageChannel(StorageChannelType<T> type);

boolean hasSource(Predicate<Storage<?>> matcher);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

import com.refinedmods.refinedstorage2.api.network.impl.node.grid.GridNetworkNode;
import com.refinedmods.refinedstorage2.network.test.AddNetworkNode;
import com.refinedmods.refinedstorage2.network.test.NetworkTestFixtures;

import java.util.Map;

public class GridNetworkNodeFactory extends AbstractNetworkNodeFactory<GridNetworkNode> {
@Override
protected GridNetworkNode innerCreate(final AddNetworkNode ctx, final Map<String, Object> properties) {
return new GridNetworkNode(getEnergyUsage(properties), NetworkTestFixtures.STORAGE_CHANNEL_TYPES);
return new GridNetworkNode(getEnergyUsage(properties));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -76,6 +77,11 @@ public <T> StorageChannel<T> getStorageChannel(final StorageChannelType<T> type)
return (StorageChannel<T>) channels.get(type);
}

@Override
public Set<StorageChannelType<?>> getStorageChannelTypes() {
return channels.keySet();
}

@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public boolean hasSource(final Predicate<Storage<?>> matcher) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
package com.refinedmods.refinedstorage2.api.network.impl.node.grid;

import com.refinedmods.refinedstorage2.api.grid.GridWatcher;
import com.refinedmods.refinedstorage2.api.grid.watcher.GridWatcher;
import com.refinedmods.refinedstorage2.api.grid.watcher.GridWatcherManager;
import com.refinedmods.refinedstorage2.api.grid.watcher.GridWatcherManagerImpl;
import com.refinedmods.refinedstorage2.api.network.Network;
import com.refinedmods.refinedstorage2.api.network.component.StorageNetworkComponent;
import com.refinedmods.refinedstorage2.api.network.node.AbstractNetworkNode;
import com.refinedmods.refinedstorage2.api.storage.Actor;
import com.refinedmods.refinedstorage2.api.storage.channel.StorageChannelType;

import java.util.Collection;
import javax.annotation.Nullable;

import static java.util.Objects.requireNonNull;

public class GridNetworkNode extends AbstractNetworkNode {
private final long energyUsage;
private final GridWatchers watchers;
private final GridWatcherManager watchers = new GridWatcherManagerImpl();

public GridNetworkNode(final long energyUsage,
final Collection<? extends StorageChannelType<?>> storageChannelTypes) {
public GridNetworkNode(final long energyUsage) {
this.energyUsage = energyUsage;
this.watchers = new GridWatchers(storageChannelTypes);
}

@Override
Expand All @@ -27,11 +26,11 @@ public long getEnergyUsage() {
}

public void addWatcher(final GridWatcher watcher, final Class<? extends Actor> actorType) {
watchers.addWatcher(watcher, actorType, requireNonNull(network));
watchers.addWatcher(watcher, actorType, requireNonNull(network).getComponent(StorageNetworkComponent.class));
}

public void removeWatcher(final GridWatcher watcher) {
watchers.removeWatcher(watcher, requireNonNull(network));
watchers.removeWatcher(watcher, requireNonNull(network).getComponent(StorageNetworkComponent.class));
}

@Override
Expand All @@ -43,11 +42,11 @@ protected void onActiveChanged(final boolean newActive) {
@Override
public void setNetwork(@Nullable final Network network) {
if (this.network != null) {
watchers.detachAll(this.network);
watchers.detachAll(this.network.getComponent(StorageNetworkComponent.class));
}
super.setNetwork(network);
if (this.network != null) {
watchers.attachAll(this.network);
watchers.attachAll(this.network.getComponent(StorageNetworkComponent.class));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.slf4j.LoggerFactory;

public class StorageNetworkNode<T> extends AbstractStorageNetworkNode implements StorageProvider {
public static final Logger LOGGER = LoggerFactory.getLogger(StorageNetworkNode.class);
private static final Logger LOGGER = LoggerFactory.getLogger(StorageNetworkNode.class);

private final long energyUsage;
private final StorageChannelType<?> type;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.refinedmods.refinedstorage2.api.network.impl;

import com.refinedmods.refinedstorage2.api.core.Action;
import com.refinedmods.refinedstorage2.api.grid.GridWatcher;
import com.refinedmods.refinedstorage2.api.grid.watcher.GridWatcher;
import com.refinedmods.refinedstorage2.api.network.ConnectionProvider;
import com.refinedmods.refinedstorage2.api.network.Network;
import com.refinedmods.refinedstorage2.api.network.impl.node.container.NetworkNodeContainerPriorities;
Expand Down Expand Up @@ -52,7 +52,7 @@ void shouldRespectPriorityWhenSplitting() {
assertThat(slave.nodeB.getNetwork()).isNotSameAs(master.nodeA.getNetwork());

final InOrder inOrder = inOrder(slave.watcher);
inOrder.verify(slave.watcher, times(1)).clear();
inOrder.verify(slave.watcher, times(1)).invalidate();
inOrder.verify(slave.watcher, times(1)).onChanged(
NetworkTestFixtures.STORAGE_CHANNEL_TYPE,
"slave",
Expand Down Expand Up @@ -93,7 +93,7 @@ void shouldRespectPriorityWhenMerging() {
assertThat(slave.nodeB.getNetwork()).isSameAs(master.nodeA.getNetwork());

final InOrder inOrder = inOrder(slave.watcher);
inOrder.verify(slave.watcher, times(1)).clear();
inOrder.verify(slave.watcher, times(1)).invalidate();
inOrder.verify(slave.watcher).onChanged(
NetworkTestFixtures.STORAGE_CHANNEL_TYPE,
"slave",
Expand Down Expand Up @@ -131,7 +131,7 @@ private NetworkSide createNetworkSide(final String name, final Supplier<Network>
0
);
nodeA.setActive(true);
final GridNetworkNode nodeB = new GridNetworkNode(0, NetworkTestFixtures.STORAGE_CHANNEL_TYPES);
final GridNetworkNode nodeB = new GridNetworkNode(0);
final NetworkNodeContainer b = createContainerWithNetwork(
nodeB,
container -> a.getNode().getNetwork(),
Expand Down
Loading

0 comments on commit eea3eee

Please sign in to comment.