diff --git a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java index a8ac3738..9a284c6f 100644 --- a/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java +++ b/application/src/integrationTest/java/de/cotto/lndmanagej/controller/LegacyControllerIT.java @@ -1,5 +1,6 @@ package de.cotto.lndmanagej.controller; +import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.NodeService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +27,9 @@ class LegacyControllerIT { @MockBean private NodeService nodeService; + @MockBean + private ChannelService channelService; + @Test void getAlias() throws Exception { when(nodeService.getAlias(PUBKEY)).thenReturn(ALIAS); @@ -39,7 +43,7 @@ class LegacyControllerIT { @Test void getOpenChannelIds() throws Exception { - when(nodeService.getOpenChannelIds(PUBKEY)).thenReturn(List.of(CHANNEL_ID, CHANNEL_ID_3)); + when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(List.of(CHANNEL_ID, CHANNEL_ID_3)); mockMvc.perform(get("/legacy/node/" + PUBKEY + "/open-channels")) .andExpect(content().string(CHANNEL_ID + "\n" + CHANNEL_ID_3)); } diff --git a/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java b/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java index 86c7efac..0e2f217f 100644 --- a/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java +++ b/application/src/main/java/de/cotto/lndmanagej/controller/LegacyController.java @@ -2,6 +2,7 @@ package de.cotto.lndmanagej.controller; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.Pubkey; +import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.NodeService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -15,9 +16,11 @@ import java.util.stream.Collectors; public class LegacyController { private static final String NEWLINE = "\n"; private final NodeService nodeService; + private final ChannelService channelService; - public LegacyController(NodeService nodeService) { + public LegacyController(NodeService nodeService, ChannelService channelService) { this.nodeService = nodeService; + this.channelService = channelService; } @GetMapping("/alias") @@ -27,7 +30,7 @@ public class LegacyController { @GetMapping("/open-channels") public String getOpenChannelIds(@PathVariable Pubkey pubkey) { - return nodeService.getOpenChannelIds(pubkey).stream() + return channelService.getOpenChannelsWith(pubkey).stream() .map(ChannelId::toString) .collect(Collectors.joining(NEWLINE)); } diff --git a/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java b/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java index 45be0444..f28b9bd4 100644 --- a/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java +++ b/application/src/main/java/de/cotto/lndmanagej/service/ChannelService.java @@ -1,30 +1,57 @@ package de.cotto.lndmanagej.service; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import de.cotto.lndmanagej.grpc.GrpcChannels; import de.cotto.lndmanagej.model.Channel; +import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.Node; import de.cotto.lndmanagej.model.Pubkey; import org.springframework.stereotype.Component; -import java.util.Set; +import javax.annotation.Nonnull; +import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Component public class ChannelService { + private static final int MAXIMUM_SIZE = 500; + private static final int CACHE_EXPIRY_MINUTES = 5; + private final GrpcChannels grpcChannels; + private final LoadingCache> channelsWithPeerCache; public ChannelService(GrpcChannels grpcChannels) { this.grpcChannels = grpcChannels; + CacheLoader> loader = new CacheLoader<>() { + @Nonnull + @Override + public List load(@Nonnull Node peer) { + return getOpenChannelsWithWithoutCache(peer); + } + }; + channelsWithPeerCache = CacheBuilder.newBuilder() + .expireAfterWrite(CACHE_EXPIRY_MINUTES, TimeUnit.MINUTES) + .maximumSize(MAXIMUM_SIZE) + .build(loader); } - public Set getOpenChannelsWith(Pubkey peer) { + public List getOpenChannelsWith(Pubkey peer) { Node peerNode = Node.forPubkey(peer); return getOpenChannelsWith(peerNode); } - public Set getOpenChannelsWith(Node peer) { + public List getOpenChannelsWith(Node peer) { + return channelsWithPeerCache.getUnchecked(peer); + } + + public List getOpenChannelsWithWithoutCache(Node peer) { return grpcChannels.getChannels().stream() .filter(c -> c.getNodes().contains(peer)) - .collect(Collectors.toSet()); + .map(Channel::getId) + .sorted() + .collect(Collectors.toList()); } } diff --git a/application/src/main/java/de/cotto/lndmanagej/service/NodeService.java b/application/src/main/java/de/cotto/lndmanagej/service/NodeService.java index 20044f42..313fd102 100644 --- a/application/src/main/java/de/cotto/lndmanagej/service/NodeService.java +++ b/application/src/main/java/de/cotto/lndmanagej/service/NodeService.java @@ -4,16 +4,12 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import de.cotto.lndmanagej.grpc.GrpcNodeInfo; -import de.cotto.lndmanagej.model.Channel; -import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.Node; import de.cotto.lndmanagej.model.Pubkey; import org.springframework.stereotype.Component; import javax.annotation.Nonnull; -import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; @Component public class NodeService { @@ -21,12 +17,10 @@ public class NodeService { private static final int CACHE_EXPIRY_MINUTES = 30; private final GrpcNodeInfo grpcNodeInfo; - private final ChannelService channelService; private final LoadingCache aliasCache; - public NodeService(GrpcNodeInfo grpcNodeInfo, ChannelService channelService) { + public NodeService(GrpcNodeInfo grpcNodeInfo) { this.grpcNodeInfo = grpcNodeInfo; - this.channelService = channelService; CacheLoader loader = new CacheLoader<>() { @Nonnull @Override @@ -40,13 +34,6 @@ public class NodeService { .build(loader); } - public List getOpenChannelIds(Pubkey peer) { - return channelService.getOpenChannelsWith(peer).stream() - .map(Channel::getId) - .sorted() - .collect(Collectors.toList()); - } - public String getAlias(Pubkey pubkey) { return aliasCache.getUnchecked(pubkey); } diff --git a/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java b/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java index 85865e46..75ddfa87 100644 --- a/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/controller/LegacyControllerTest.java @@ -1,5 +1,6 @@ package de.cotto.lndmanagej.controller; +import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.NodeService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -24,6 +25,9 @@ class LegacyControllerTest { @Mock private NodeService nodeService; + @Mock + private ChannelService channelService; + @Test void getAlias() { when(nodeService.getAlias(PUBKEY)).thenReturn(ALIAS); @@ -32,7 +36,7 @@ class LegacyControllerTest { @Test void getOpenChannelIds() { - when(nodeService.getOpenChannelIds(PUBKEY)).thenReturn(List.of(CHANNEL_ID, CHANNEL_ID_3)); + when(channelService.getOpenChannelsWith(PUBKEY)).thenReturn(List.of(CHANNEL_ID, CHANNEL_ID_3)); assertThat(legacyController.getOpenChannelIds(PUBKEY)).isEqualTo( CHANNEL_ID + "\n" + CHANNEL_ID_3 ); diff --git a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java index 678d3bea..a3fe3b4c 100644 --- a/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/service/ChannelServiceTest.java @@ -13,7 +13,9 @@ import java.util.Set; import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL; import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_3; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_2; +import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_3; import static de.cotto.lndmanagej.model.NodeFixtures.NODE; import static de.cotto.lndmanagej.model.NodeFixtures.NODE_2; import static de.cotto.lndmanagej.model.NodeFixtures.NODE_3; @@ -32,19 +34,25 @@ class ChannelServiceTest { @Test void getOpenChannelsWith_by_pubkey() { when(grpcChannels.getChannels()).thenReturn(Set.of(CHANNEL, CHANNEL_3)); - assertThat(channelService.getOpenChannelsWith(PUBKEY_2)).containsExactlyInAnyOrder(CHANNEL, CHANNEL_3); + assertThat(channelService.getOpenChannelsWith(PUBKEY_2)).containsExactly(CHANNEL_ID, CHANNEL_ID_3); } @Test void getOpenChannelsWith_by_node() { when(grpcChannels.getChannels()).thenReturn(Set.of(CHANNEL, CHANNEL_3)); - assertThat(channelService.getOpenChannelsWith(NODE_2)).containsExactlyInAnyOrder(CHANNEL, CHANNEL_3); + assertThat(channelService.getOpenChannelsWith(NODE_2)).containsExactly(CHANNEL_ID, CHANNEL_ID_3); } @Test void getOpenChannelsWith_ignores_channel_to_other_node() { Channel channel2 = ChannelFixtures.create(NODE, NODE_3, CHANNEL_ID_2); when(grpcChannels.getChannels()).thenReturn(Set.of(CHANNEL, channel2, CHANNEL_3)); - assertThat(channelService.getOpenChannelsWith(NODE_2)).containsExactlyInAnyOrder(CHANNEL, CHANNEL_3); + assertThat(channelService.getOpenChannelsWith(NODE_2)).containsExactly(CHANNEL_ID, CHANNEL_ID_3); + } + + @Test + void getOpenChannelsWith_ordered() { + when(grpcChannels.getChannels()).thenReturn(Set.of(CHANNEL_3, CHANNEL)); + assertThat(channelService.getOpenChannelsWith(NODE_2)).containsExactly(CHANNEL_ID, CHANNEL_ID_3); } } \ No newline at end of file diff --git a/application/src/test/java/de/cotto/lndmanagej/service/NodeServiceTest.java b/application/src/test/java/de/cotto/lndmanagej/service/NodeServiceTest.java index 40f70a93..b2a059f1 100644 --- a/application/src/test/java/de/cotto/lndmanagej/service/NodeServiceTest.java +++ b/application/src/test/java/de/cotto/lndmanagej/service/NodeServiceTest.java @@ -7,16 +7,9 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Set; - -import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL; -import static de.cotto.lndmanagej.model.ChannelFixtures.CHANNEL_3; -import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; -import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_3; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS; import static de.cotto.lndmanagej.model.NodeFixtures.NODE; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; -import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; @@ -25,9 +18,6 @@ class NodeServiceTest { @InjectMocks private NodeService nodeService; - @Mock - private ChannelService channelService; - @Mock private GrpcNodeInfo grpcNodeInfo; @@ -36,16 +26,4 @@ class NodeServiceTest { when(grpcNodeInfo.getNode(PUBKEY)).thenReturn(NODE); assertThat(nodeService.getAlias(PUBKEY)).isEqualTo(ALIAS); } - - @Test - void getOpenChannelIds() { - when(channelService.getOpenChannelsWith(PUBKEY_2)).thenReturn(Set.of(CHANNEL, CHANNEL_3)); - assertThat(nodeService.getOpenChannelIds(PUBKEY_2)).containsExactly(CHANNEL_ID, CHANNEL_ID_3); - } - - @Test - void getOpenChannelIds_ordered() { - when(channelService.getOpenChannelsWith(PUBKEY_2)).thenReturn(Set.of(CHANNEL_3, CHANNEL)); - assertThat(nodeService.getOpenChannelIds(PUBKEY_2)).containsExactly(CHANNEL_ID, CHANNEL_ID_3); - } } \ No newline at end of file