diff --git a/backend/build.gradle b/backend/build.gradle index bb9f0f8e..82963c16 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -7,8 +7,9 @@ dependencies { implementation project(':forwarding-history') implementation project(':grpc-adapter') implementation project(':model') - implementation project(':transactions') + implementation project(':onlinepeers') implementation project(':selfpayments') + implementation project(':transactions') testImplementation testFixtures(project(':model')) testImplementation testFixtures(project(':transactions')) } diff --git a/backend/src/main/java/de/cotto/lndmanagej/service/NodeDetailsService.java b/backend/src/main/java/de/cotto/lndmanagej/service/NodeDetailsService.java index 0168643f..7dac7bf0 100644 --- a/backend/src/main/java/de/cotto/lndmanagej/service/NodeDetailsService.java +++ b/backend/src/main/java/de/cotto/lndmanagej/service/NodeDetailsService.java @@ -7,6 +7,7 @@ import de.cotto.lndmanagej.model.FeeReport; import de.cotto.lndmanagej.model.Node; import de.cotto.lndmanagej.model.NodeDetails; import de.cotto.lndmanagej.model.OnChainCosts; +import de.cotto.lndmanagej.model.OnlineReport; import de.cotto.lndmanagej.model.Pubkey; import de.cotto.lndmanagej.model.RebalanceReport; import org.springframework.stereotype.Component; @@ -24,6 +25,7 @@ public class NodeDetailsService { private final BalanceService balanceService; private final FeeService feeService; private final RebalanceService rebalanceService; + private final OnlinePeersService onlinePeersService; public NodeDetailsService( ChannelService channelService, @@ -31,7 +33,8 @@ public class NodeDetailsService { OnChainCostService onChainCostService, BalanceService balanceService, FeeService feeService, - RebalanceService rebalanceService + RebalanceService rebalanceService, + OnlinePeersService onlinePeersService ) { this.channelService = channelService; this.nodeService = nodeService; @@ -39,10 +42,12 @@ public class NodeDetailsService { this.balanceService = balanceService; this.feeService = feeService; this.rebalanceService = rebalanceService; + this.onlinePeersService = onlinePeersService; } public NodeDetails getDetails(Pubkey pubkey) { CompletableFuture node = getNode(pubkey); + CompletableFuture onlineReport = node.thenApply(onlinePeersService::getOnlineReport); CompletableFuture onChainCosts = getOnChainCosts(pubkey); CompletableFuture balanceInformation = getBalanceInformation(pubkey); CompletableFuture feeReport = getFeeReport(pubkey); @@ -65,7 +70,7 @@ public class NodeDetailsService { forceClosingChannelIds, onChainCosts.get(), balanceInformation.get(), - node.get().online(), + onlineReport.get(), feeReport.get(), rebalanceReport.get() ); diff --git a/backend/src/main/java/de/cotto/lndmanagej/service/OnlinePeersService.java b/backend/src/main/java/de/cotto/lndmanagej/service/OnlinePeersService.java new file mode 100644 index 00000000..ea1268c4 --- /dev/null +++ b/backend/src/main/java/de/cotto/lndmanagej/service/OnlinePeersService.java @@ -0,0 +1,33 @@ +package de.cotto.lndmanagej.service; + +import de.cotto.lndmanagej.model.Node; +import de.cotto.lndmanagej.model.OnlineReport; +import de.cotto.lndmanagej.model.OnlineStatus; +import de.cotto.lndmanagej.onlinepeers.OnlinePeersDao; +import org.springframework.stereotype.Component; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; + +@Component +public class OnlinePeersService { + private final OnlinePeersDao dao; + + public OnlinePeersService(OnlinePeersDao dao) { + this.dao = dao; + } + + public OnlineReport getOnlineReport(Node node) { + boolean online = node.online(); + OnlineStatus mostRecentOnlineStatus = dao.getMostRecentOnlineStatus(node.pubkey()).orElse(null); + if (mostRecentOnlineStatus != null && mostRecentOnlineStatus.online() == online) { + return OnlineReport.createFromStatus(mostRecentOnlineStatus); + } + return new OnlineReport(online, now()); + } + + private ZonedDateTime now() { + return ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS); + } +} diff --git a/backend/src/test/java/de/cotto/lndmanagej/service/NodeDetailsServiceTest.java b/backend/src/test/java/de/cotto/lndmanagej/service/NodeDetailsServiceTest.java index a171a3ef..b35410b3 100644 --- a/backend/src/test/java/de/cotto/lndmanagej/service/NodeDetailsServiceTest.java +++ b/backend/src/test/java/de/cotto/lndmanagej/service/NodeDetailsServiceTest.java @@ -2,7 +2,6 @@ package de.cotto.lndmanagej.service; import de.cotto.lndmanagej.model.BalanceInformation; import de.cotto.lndmanagej.model.FeeReport; -import de.cotto.lndmanagej.model.NodeDetailsFixtures; import de.cotto.lndmanagej.model.OnChainCosts; import de.cotto.lndmanagej.model.RebalanceReport; import org.junit.jupiter.api.Test; @@ -18,9 +17,13 @@ import static de.cotto.lndmanagej.model.CoopClosedChannelFixtures.CLOSED_CHANNEL import static de.cotto.lndmanagej.model.FeeReportFixtures.FEE_REPORT; import static de.cotto.lndmanagej.model.ForceClosingChannelFixtures.FORCE_CLOSING_CHANNEL_4; import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHANNEL; +import static de.cotto.lndmanagej.model.NodeDetailsFixtures.NODE_DETAILS; +import static de.cotto.lndmanagej.model.NodeDetailsFixtures.NODE_DETAILS_EMPTY; import static de.cotto.lndmanagej.model.NodeFixtures.NODE; import static de.cotto.lndmanagej.model.NodeFixtures.NODE_PEER; import static de.cotto.lndmanagej.model.OnChainCostsFixtures.ON_CHAIN_COSTS; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT_OFFLINE; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.RebalanceReportFixtures.REBALANCE_REPORT; import static de.cotto.lndmanagej.model.WaitingCloseChannelFixtures.WAITING_CLOSE_CHANNEL_TO_NODE_3; @@ -50,6 +53,9 @@ class NodeDetailsServiceTest { @Mock private RebalanceService rebalanceService; + @Mock + private OnlinePeersService onlinePeersService; + @Test void getDetails_no_channel() { when(nodeService.getNode(PUBKEY)).thenReturn(NODE); @@ -57,7 +63,8 @@ class NodeDetailsServiceTest { when(onChainCostService.getOnChainCostsForPeer(PUBKEY)).thenReturn(OnChainCosts.NONE); when(feeService.getFeeReportForPeer(PUBKEY)).thenReturn(FeeReport.EMPTY); when(rebalanceService.getReportForPeer(PUBKEY)).thenReturn(RebalanceReport.EMPTY); - assertThat(nodeDetailsService.getDetails(PUBKEY)).isEqualTo(NodeDetailsFixtures.NODE_DETAILS_EMPTY); + when(onlinePeersService.getOnlineReport(NODE_PEER)).thenReturn(ONLINE_REPORT_OFFLINE); + assertThat(nodeDetailsService.getDetails(PUBKEY)).isEqualTo(NODE_DETAILS_EMPTY); } @Test @@ -71,6 +78,7 @@ class NodeDetailsServiceTest { when(channelService.getForceClosingChannelsWith(PUBKEY)).thenReturn(Set.of(FORCE_CLOSING_CHANNEL_4)); when(feeService.getFeeReportForPeer(PUBKEY)).thenReturn(FEE_REPORT); when(rebalanceService.getReportForPeer(PUBKEY)).thenReturn(REBALANCE_REPORT); - assertThat(nodeDetailsService.getDetails(PUBKEY)).isEqualTo(NodeDetailsFixtures.NODE_DETAILS); + when(onlinePeersService.getOnlineReport(NODE_PEER)).thenReturn(ONLINE_REPORT); + assertThat(nodeDetailsService.getDetails(PUBKEY)).isEqualTo(NODE_DETAILS); } } \ No newline at end of file diff --git a/backend/src/test/java/de/cotto/lndmanagej/service/OnlinePeersServiceTest.java b/backend/src/test/java/de/cotto/lndmanagej/service/OnlinePeersServiceTest.java new file mode 100644 index 00000000..c7adef82 --- /dev/null +++ b/backend/src/test/java/de/cotto/lndmanagej/service/OnlinePeersServiceTest.java @@ -0,0 +1,65 @@ +package de.cotto.lndmanagej.service; + +import de.cotto.lndmanagej.model.OnlineReport; +import de.cotto.lndmanagej.onlinepeers.OnlinePeersDao; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Optional; + +import static de.cotto.lndmanagej.model.NodeFixtures.NODE; +import static de.cotto.lndmanagej.model.NodeFixtures.NODE_PEER; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS; +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS_OFFLINE; +import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class OnlinePeersServiceTest { + @InjectMocks + private OnlinePeersService onlinePeersService; + + @Mock + private OnlinePeersDao dao; + + @Test + void with_time_if_given_status_matches_last_known_status() { + when(dao.getMostRecentOnlineStatus(PUBKEY)).thenReturn(Optional.of(ONLINE_STATUS)); + assertThat(onlinePeersService.getOnlineReport(NODE_PEER)).isEqualTo(ONLINE_REPORT); + } + + @Test + void with_current_time_if_given_status_does_not_match_last_known_status() { + when(dao.getMostRecentOnlineStatus(PUBKEY)).thenReturn(Optional.of(ONLINE_STATUS_OFFLINE)); + OnlineReport report = onlinePeersService.getOnlineReport(NODE_PEER); + assertThat(report.online()).isTrue(); + assertVeryRecentSince(report); + } + + @Test + void with_current_time_if_no_persisted_status_known() { + OnlineReport report = onlinePeersService.getOnlineReport(NODE); + assertThat(report.online()).isFalse(); + assertVeryRecentSince(report); + } + + @Test + void with_current_state_if_no_persisted_status_known() { + OnlineReport report = onlinePeersService.getOnlineReport(NODE_PEER); + assertThat(report.online()).isTrue(); + assertVeryRecentSince(report); + } + + private void assertVeryRecentSince(OnlineReport report) { + assertThat(report.since()) + .isAfter(ZonedDateTime.now(ZoneOffset.UTC).minusSeconds(1)) + .asString().hasSize(20); + } +} \ No newline at end of file diff --git a/balances/build.gradle b/balances/build.gradle new file mode 100644 index 00000000..fc7ef9ad --- /dev/null +++ b/balances/build.gradle @@ -0,0 +1,10 @@ +plugins { + id 'lnd-manageJ.java-library-conventions' +} + +dependencies { + implementation project(':model') + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + testRuntimeOnly 'com.h2database:h2' + testFixturesApi testFixtures(project(':model')) +} \ No newline at end of file diff --git a/statistics/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java b/balances/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java similarity index 100% rename from statistics/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java rename to balances/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java diff --git a/statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/BalancesRepositoryIT.java b/balances/src/integrationTest/java/de/cotto/lndmanagej/balances/persistence/BalancesRepositoryIT.java similarity index 89% rename from statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/BalancesRepositoryIT.java rename to balances/src/integrationTest/java/de/cotto/lndmanagej/balances/persistence/BalancesRepositoryIT.java index c0d7f07b..32a4b6a1 100644 --- a/statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/BalancesRepositoryIT.java +++ b/balances/src/integrationTest/java/de/cotto/lndmanagej/balances/persistence/BalancesRepositoryIT.java @@ -1,13 +1,13 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import static de.cotto.lndmanagej.balances.BalancesFixtures.BALANCES; +import static de.cotto.lndmanagej.balances.BalancesFixtures.BALANCES_OLD; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_2; -import static de.cotto.lndmanagej.statistics.StatisticsFixtures.BALANCES; -import static de.cotto.lndmanagej.statistics.StatisticsFixtures.BALANCES_OLD; import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/Balances.java b/balances/src/main/java/de/cotto/lndmanagej/balances/Balances.java similarity index 87% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/Balances.java rename to balances/src/main/java/de/cotto/lndmanagej/balances/Balances.java index 51b841a2..af3dad1b 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/Balances.java +++ b/balances/src/main/java/de/cotto/lndmanagej/balances/Balances.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics; +package de.cotto.lndmanagej.balances; import de.cotto.lndmanagej.model.BalanceInformation; import de.cotto.lndmanagej.model.ChannelId; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/BalancesDao.java b/balances/src/main/java/de/cotto/lndmanagej/balances/BalancesDao.java similarity index 84% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/BalancesDao.java rename to balances/src/main/java/de/cotto/lndmanagej/balances/BalancesDao.java index 48c507f3..c7dd9a3d 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/BalancesDao.java +++ b/balances/src/main/java/de/cotto/lndmanagej/balances/BalancesDao.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics; +package de.cotto.lndmanagej.balances; import de.cotto.lndmanagej.model.ChannelId; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesDaoImpl.java b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesDaoImpl.java similarity index 84% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesDaoImpl.java rename to balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesDaoImpl.java index e4bce555..53c8723e 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesDaoImpl.java +++ b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesDaoImpl.java @@ -1,8 +1,8 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; +import de.cotto.lndmanagej.balances.Balances; +import de.cotto.lndmanagej.balances.BalancesDao; import de.cotto.lndmanagej.model.ChannelId; -import de.cotto.lndmanagej.statistics.Balances; -import de.cotto.lndmanagej.statistics.BalancesDao; import org.springframework.stereotype.Component; import javax.transaction.Transactional; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesId.java b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesId.java similarity index 94% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesId.java rename to balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesId.java index 6f7e5413..86d1ec8b 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesId.java +++ b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesId.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; import javax.annotation.Nullable; import java.io.Serial; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesJpaDto.java b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesJpaDto.java similarity index 96% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesJpaDto.java rename to balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesJpaDto.java index d17a8d1d..fada78db 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesJpaDto.java +++ b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesJpaDto.java @@ -1,10 +1,10 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; import com.google.common.annotations.VisibleForTesting; +import de.cotto.lndmanagej.balances.Balances; import de.cotto.lndmanagej.model.BalanceInformation; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.Coins; -import de.cotto.lndmanagej.statistics.Balances; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesRepository.java b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesRepository.java similarity index 83% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesRepository.java rename to balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesRepository.java index d3a82ec5..50fcd250 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/BalancesRepository.java +++ b/balances/src/main/java/de/cotto/lndmanagej/balances/persistence/BalancesRepository.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesDaoImplTest.java b/balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesDaoImplTest.java similarity index 88% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesDaoImplTest.java rename to balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesDaoImplTest.java index 46d025c3..874318c7 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesDaoImplTest.java +++ b/balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesDaoImplTest.java @@ -1,6 +1,5 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; -import de.cotto.lndmanagej.statistics.StatisticsFixtures; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -10,9 +9,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.time.ZoneOffset; import java.util.Optional; +import static de.cotto.lndmanagej.balances.BalancesFixtures.BALANCES; +import static de.cotto.lndmanagej.balances.BalancesFixtures.TIMESTAMP; import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; -import static de.cotto.lndmanagej.statistics.StatisticsFixtures.BALANCES; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.verify; @@ -31,7 +31,7 @@ class BalancesDaoImplTest { void saveStatistics() { dao.saveBalances(BALANCES); verify(balancesRepository).save(argThat(jpaDto -> - jpaDto.getTimestamp() == StatisticsFixtures.TIMESTAMP.toEpochSecond(ZoneOffset.UTC) + jpaDto.getTimestamp() == TIMESTAMP.toEpochSecond(ZoneOffset.UTC) )); verify(balancesRepository).save(argThat(jpaDto -> jpaDto.getChannelId() == CHANNEL_ID.getShortChannelId())); diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesIdTest.java b/balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesIdTest.java similarity index 66% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesIdTest.java rename to balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesIdTest.java index 5f1f1e99..d8b88db2 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesIdTest.java +++ b/balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesIdTest.java @@ -1,15 +1,14 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; import nl.jqno.equalsverifier.EqualsVerifier; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - class BalancesIdTest { @Test void test_default_constructor() { // required for JPA - assertThat(new BalancesId()).isNotNull(); + Assertions.assertThat(new BalancesId()).isNotNull(); } @Test diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesJpaDtoTest.java b/balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesJpaDtoTest.java similarity index 85% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesJpaDtoTest.java rename to balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesJpaDtoTest.java index 590763c9..36b3fac2 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/BalancesJpaDtoTest.java +++ b/balances/src/test/java/de/cotto/lndmanagej/balances/persistence/BalancesJpaDtoTest.java @@ -1,13 +1,13 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.balances.persistence; import org.junit.jupiter.api.Test; import java.time.ZoneOffset; +import static de.cotto.lndmanagej.balances.BalancesFixtures.BALANCES; +import static de.cotto.lndmanagej.balances.BalancesFixtures.TIMESTAMP; import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; -import static de.cotto.lndmanagej.statistics.StatisticsFixtures.BALANCES; -import static de.cotto.lndmanagej.statistics.StatisticsFixtures.TIMESTAMP; import static org.assertj.core.api.Assertions.assertThat; class BalancesJpaDtoTest { diff --git a/statistics/src/testFixtures/java/de/cotto/lndmanagej/statistics/StatisticsFixtures.java b/balances/src/testFixtures/java/de/cotto/lndmanagej/balances/BalancesFixtures.java similarity index 90% rename from statistics/src/testFixtures/java/de/cotto/lndmanagej/statistics/StatisticsFixtures.java rename to balances/src/testFixtures/java/de/cotto/lndmanagej/balances/BalancesFixtures.java index 274a18f5..05df9348 100644 --- a/statistics/src/testFixtures/java/de/cotto/lndmanagej/statistics/StatisticsFixtures.java +++ b/balances/src/testFixtures/java/de/cotto/lndmanagej/balances/BalancesFixtures.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics; +package de.cotto.lndmanagej.balances; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -8,7 +8,7 @@ import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFOR import static de.cotto.lndmanagej.model.BalanceInformationFixtures.BALANCE_INFORMATION_2; import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID; -public class StatisticsFixtures { +public class BalancesFixtures { public static final LocalDateTime TIMESTAMP = LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS); public static final Balances BALANCES = new Balances(TIMESTAMP, CHANNEL_ID, BALANCE_INFORMATION); diff --git a/model/src/main/java/de/cotto/lndmanagej/model/NodeDetails.java b/model/src/main/java/de/cotto/lndmanagej/model/NodeDetails.java index 3407ca32..20f90b73 100644 --- a/model/src/main/java/de/cotto/lndmanagej/model/NodeDetails.java +++ b/model/src/main/java/de/cotto/lndmanagej/model/NodeDetails.java @@ -11,7 +11,7 @@ public record NodeDetails( List pendingForceClosingChannels, OnChainCosts onChainCosts, BalanceInformation balanceInformation, - boolean online, + OnlineReport onlineReport, FeeReport feeReport, RebalanceReport rebalanceReport ) { diff --git a/model/src/main/java/de/cotto/lndmanagej/model/OnlineReport.java b/model/src/main/java/de/cotto/lndmanagej/model/OnlineReport.java new file mode 100644 index 00000000..03488906 --- /dev/null +++ b/model/src/main/java/de/cotto/lndmanagej/model/OnlineReport.java @@ -0,0 +1,9 @@ +package de.cotto.lndmanagej.model; + +import java.time.ZonedDateTime; + +public record OnlineReport(boolean online, ZonedDateTime since) { + public static OnlineReport createFromStatus(OnlineStatus onlineStatus) { + return new OnlineReport(onlineStatus.online(), onlineStatus.since()); + } +} diff --git a/model/src/main/java/de/cotto/lndmanagej/model/OnlineStatus.java b/model/src/main/java/de/cotto/lndmanagej/model/OnlineStatus.java new file mode 100644 index 00000000..fea19d76 --- /dev/null +++ b/model/src/main/java/de/cotto/lndmanagej/model/OnlineStatus.java @@ -0,0 +1,6 @@ +package de.cotto.lndmanagej.model; + +import java.time.ZonedDateTime; + +public record OnlineStatus(boolean online, ZonedDateTime since) { +} diff --git a/model/src/test/java/de/cotto/lndmanagej/model/NodeDetailsTest.java b/model/src/test/java/de/cotto/lndmanagej/model/NodeDetailsTest.java index 9ceef462..c6e5e02d 100644 --- a/model/src/test/java/de/cotto/lndmanagej/model/NodeDetailsTest.java +++ b/model/src/test/java/de/cotto/lndmanagej/model/NodeDetailsTest.java @@ -11,6 +11,7 @@ import static de.cotto.lndmanagej.model.FeeReportFixtures.FEE_REPORT; import static de.cotto.lndmanagej.model.NodeDetailsFixtures.NODE_DETAILS; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS; import static de.cotto.lndmanagej.model.OnChainCostsFixtures.ON_CHAIN_COSTS; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.RebalanceReportFixtures.REBALANCE_REPORT; import static org.assertj.core.api.Assertions.assertThat; @@ -57,11 +58,12 @@ class NodeDetailsTest { } @Test - void online() { - assertThat(NODE_DETAILS.online()).isTrue(); + void onlineReport() { + assertThat(NODE_DETAILS.onlineReport()).isEqualTo(ONLINE_REPORT); } @Test + void feeReport() { assertThat(NODE_DETAILS.feeReport()).isEqualTo(FEE_REPORT); } diff --git a/model/src/test/java/de/cotto/lndmanagej/model/OnlineReportTest.java b/model/src/test/java/de/cotto/lndmanagej/model/OnlineReportTest.java new file mode 100644 index 00000000..88d2a7f0 --- /dev/null +++ b/model/src/test/java/de/cotto/lndmanagej/model/OnlineReportTest.java @@ -0,0 +1,28 @@ +package de.cotto.lndmanagej.model; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.TIMESTAMP; +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS; +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(MockitoExtension.class) +class OnlineReportTest { + @Test + void online() { + assertThat(ONLINE_REPORT.online()).isTrue(); + } + + @Test + void since() { + assertThat(ONLINE_REPORT.since()).isEqualTo(TIMESTAMP); + } + + @Test + void createFromOnlineStatus() { + assertThat(OnlineReport.createFromStatus(ONLINE_STATUS)).isEqualTo(ONLINE_REPORT); + } +} \ No newline at end of file diff --git a/model/src/test/java/de/cotto/lndmanagej/model/OnlineStatusTest.java b/model/src/test/java/de/cotto/lndmanagej/model/OnlineStatusTest.java new file mode 100644 index 00000000..8f2faddb --- /dev/null +++ b/model/src/test/java/de/cotto/lndmanagej/model/OnlineStatusTest.java @@ -0,0 +1,25 @@ +package de.cotto.lndmanagej.model; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS; +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(MockitoExtension.class) +class OnlineStatusTest { + @Test + void online() { + assertThat(ONLINE_STATUS.online()).isTrue(); + } + + @Test + void since() { + assertThat(ONLINE_STATUS.since()) + .isEqualTo(ZonedDateTime.of(2021, 12, 23, 1, 2, 3, 0, ZoneOffset.UTC)); + } +} \ No newline at end of file diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/NodeDetailsFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/NodeDetailsFixtures.java index 961db7f4..6afc0466 100644 --- a/model/src/testFixtures/java/de/cotto/lndmanagej/model/NodeDetailsFixtures.java +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/NodeDetailsFixtures.java @@ -10,6 +10,8 @@ import static de.cotto.lndmanagej.model.ChannelIdFixtures.CHANNEL_ID_4; import static de.cotto.lndmanagej.model.FeeReportFixtures.FEE_REPORT; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS; import static de.cotto.lndmanagej.model.OnChainCostsFixtures.ON_CHAIN_COSTS; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT_OFFLINE; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.RebalanceReportFixtures.REBALANCE_REPORT; @@ -23,7 +25,7 @@ public class NodeDetailsFixtures { List.of(CHANNEL_ID_4), ON_CHAIN_COSTS, BALANCE_INFORMATION_2, - true, + ONLINE_REPORT, FEE_REPORT, REBALANCE_REPORT ); @@ -36,7 +38,7 @@ public class NodeDetailsFixtures { List.of(), OnChainCosts.NONE, BalanceInformation.EMPTY, - false, + ONLINE_REPORT_OFFLINE, FeeReport.EMPTY, RebalanceReport.EMPTY ); diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/OnlineReportFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/OnlineReportFixtures.java new file mode 100644 index 00000000..091d22a6 --- /dev/null +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/OnlineReportFixtures.java @@ -0,0 +1,12 @@ +package de.cotto.lndmanagej.model; + +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +import static java.time.ZoneOffset.UTC; + +public class OnlineReportFixtures { + public static final ZonedDateTime TIMESTAMP = LocalDateTime.of(2021, 12, 23, 1, 2, 3).atZone(UTC); + public static final OnlineReport ONLINE_REPORT = new OnlineReport(true, TIMESTAMP); + public static final OnlineReport ONLINE_REPORT_OFFLINE = new OnlineReport(false, TIMESTAMP); +} diff --git a/model/src/testFixtures/java/de/cotto/lndmanagej/model/OnlineStatusFixtures.java b/model/src/testFixtures/java/de/cotto/lndmanagej/model/OnlineStatusFixtures.java new file mode 100644 index 00000000..65530f60 --- /dev/null +++ b/model/src/testFixtures/java/de/cotto/lndmanagej/model/OnlineStatusFixtures.java @@ -0,0 +1,20 @@ +package de.cotto.lndmanagej.model; + +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +import static java.time.ZoneOffset.UTC; + +public class OnlineStatusFixtures { + private static final ZonedDateTime TIMESTAMP = LocalDateTime.of(2021, 12, 23, 1, 2, 3).atZone(UTC); + + public static final OnlineStatus ONLINE_STATUS = new OnlineStatus( + true, + TIMESTAMP + ); + + public static final OnlineStatus ONLINE_STATUS_OFFLINE = new OnlineStatus( + false, + TIMESTAMP + ); +} diff --git a/onlinepeers/build.gradle b/onlinepeers/build.gradle new file mode 100644 index 00000000..fc7ef9ad --- /dev/null +++ b/onlinepeers/build.gradle @@ -0,0 +1,10 @@ +plugins { + id 'lnd-manageJ.java-library-conventions' +} + +dependencies { + implementation project(':model') + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + testRuntimeOnly 'com.h2database:h2' + testFixturesApi testFixtures(project(':model')) +} \ No newline at end of file diff --git a/onlinepeers/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java b/onlinepeers/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java new file mode 100644 index 00000000..7b1634de --- /dev/null +++ b/onlinepeers/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java @@ -0,0 +1,10 @@ +package de.cotto.lndmanagej; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootConfiguration { + public SpringBootConfiguration() { + // default constructor + } +} diff --git a/statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersRepositoryIT.java b/onlinepeers/src/integrationTest/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersRepositoryIT.java similarity index 92% rename from statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersRepositoryIT.java rename to onlinepeers/src/integrationTest/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersRepositoryIT.java index b8664e6b..df08c764 100644 --- a/statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersRepositoryIT.java +++ b/onlinepeers/src/integrationTest/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersRepositoryIT.java @@ -1,11 +1,11 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; @@ -13,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest class OnlinePeersRepositoryIT { - private static final LocalDateTime TIMESTAMP = LocalDateTime.now(ZoneOffset.UTC); + private static final ZonedDateTime TIMESTAMP = ZonedDateTime.now(ZoneOffset.UTC); @Autowired private OnlinePeersRepository repository; diff --git a/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/OnlinePeersDao.java b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/OnlinePeersDao.java new file mode 100644 index 00000000..ad26656c --- /dev/null +++ b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/OnlinePeersDao.java @@ -0,0 +1,13 @@ +package de.cotto.lndmanagej.onlinepeers; + +import de.cotto.lndmanagej.model.OnlineStatus; +import de.cotto.lndmanagej.model.Pubkey; + +import java.time.ZonedDateTime; +import java.util.Optional; + +public interface OnlinePeersDao { + void saveOnlineStatus(Pubkey pubkey, boolean online, ZonedDateTime timestamp); + + Optional getMostRecentOnlineStatus(Pubkey pubkey); +} diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerId.java b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerId.java similarity index 94% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerId.java rename to onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerId.java index 34bc7765..4edcf693 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerId.java +++ b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerId.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; import javax.annotation.Nullable; import java.io.Serial; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerJpaDto.java b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerJpaDto.java similarity index 64% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerJpaDto.java rename to onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerJpaDto.java index 928ac9b3..61078654 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerJpaDto.java +++ b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerJpaDto.java @@ -1,5 +1,6 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; +import de.cotto.lndmanagej.model.OnlineStatus; import de.cotto.lndmanagej.model.Pubkey; import javax.annotation.CheckForNull; @@ -9,7 +10,9 @@ import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Table; import java.time.LocalDateTime; -import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import static java.time.ZoneOffset.UTC; @Entity @IdClass(OnlinePeerId.class) @@ -30,10 +33,15 @@ public class OnlinePeerJpaDto { // for JPA } - public OnlinePeerJpaDto(Pubkey pubkey, boolean online, LocalDateTime timestamp) { + public OnlinePeerJpaDto(Pubkey pubkey, boolean online, ZonedDateTime timestamp) { this.pubkey = pubkey.toString(); this.online = online; - this.timestamp = timestamp.toEpochSecond(ZoneOffset.UTC); + this.timestamp = timestamp.toEpochSecond(); + } + + public OnlineStatus toModel() { + ZonedDateTime zonedDateTime = LocalDateTime.ofEpochSecond(timestamp, 0, UTC).atZone(UTC); + return new OnlineStatus(online, zonedDateTime); } public boolean isOnline() { diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersDaoImpl.java b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersDaoImpl.java similarity index 65% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersDaoImpl.java rename to onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersDaoImpl.java index 91970d16..7e490811 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersDaoImpl.java +++ b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersDaoImpl.java @@ -1,11 +1,12 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; +import de.cotto.lndmanagej.model.OnlineStatus; import de.cotto.lndmanagej.model.Pubkey; -import de.cotto.lndmanagej.statistics.OnlinePeersDao; +import de.cotto.lndmanagej.onlinepeers.OnlinePeersDao; import org.springframework.stereotype.Component; import javax.transaction.Transactional; -import java.time.LocalDateTime; +import java.time.ZonedDateTime; import java.util.Optional; @Component @@ -18,12 +19,12 @@ class OnlinePeersDaoImpl implements OnlinePeersDao { } @Override - public void saveOnlineStatus(Pubkey pubkey, boolean online, LocalDateTime timestamp) { + public void saveOnlineStatus(Pubkey pubkey, boolean online, ZonedDateTime timestamp) { repository.save(new OnlinePeerJpaDto(pubkey, online, timestamp)); } @Override - public Optional getMostRecentOnlineStatus(Pubkey pubkey) { - return repository.findTopByPubkeyOrderByTimestampDesc(pubkey.toString()).map(OnlinePeerJpaDto::isOnline); + public Optional getMostRecentOnlineStatus(Pubkey pubkey) { + return repository.findTopByPubkeyOrderByTimestampDesc(pubkey.toString()).map(OnlinePeerJpaDto::toModel); } } diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersRepository.java b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersRepository.java similarity index 83% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersRepository.java rename to onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersRepository.java index d695678d..906c645e 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersRepository.java +++ b/onlinepeers/src/main/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersRepository.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerIdTest.java b/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerIdTest.java similarity index 89% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerIdTest.java rename to onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerIdTest.java index a27e5d9e..81330076 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeerIdTest.java +++ b/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerIdTest.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.jupiter.api.Test; diff --git a/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerJpaDtoTest.java b/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerJpaDtoTest.java new file mode 100644 index 00000000..ae2c9713 --- /dev/null +++ b/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeerJpaDtoTest.java @@ -0,0 +1,19 @@ +package de.cotto.lndmanagej.onlinepeers.persistence; + +import de.cotto.lndmanagej.model.OnlineStatus; +import org.junit.jupiter.api.Test; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; +import static org.assertj.core.api.Assertions.assertThat; + +class OnlinePeerJpaDtoTest { + @Test + void toModel() { + ZonedDateTime zonedDateTime = ZonedDateTime.of(2021, 12, 23, 1, 2, 3, 0, ZoneOffset.UTC); + OnlinePeerJpaDto onlinePeerJpaDto = new OnlinePeerJpaDto(PUBKEY, true, zonedDateTime); + assertThat(onlinePeerJpaDto.toModel()).isEqualTo(new OnlineStatus(true, zonedDateTime)); + } +} \ No newline at end of file diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersDaoImplTest.java b/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersDaoImplTest.java similarity index 87% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersDaoImplTest.java rename to onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersDaoImplTest.java index e48860ce..90ad0b27 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/OnlinePeersDaoImplTest.java +++ b/onlinepeers/src/test/java/de/cotto/lndmanagej/onlinepeers/persistence/OnlinePeersDaoImplTest.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.onlinepeers.persistence; import de.cotto.lndmanagej.model.Pubkey; import org.junit.jupiter.api.Test; @@ -7,11 +7,11 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.time.LocalDateTime; -import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.Objects; import java.util.Optional; +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS; 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; @@ -21,7 +21,7 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class OnlinePeersDaoImplTest { - private static final LocalDateTime TIMESTAMP = LocalDateTime.now(ZoneOffset.UTC); + private static final ZonedDateTime TIMESTAMP = ONLINE_STATUS.since(); @InjectMocks private OnlinePeersDaoImpl dao; @@ -50,7 +50,7 @@ class OnlinePeersDaoImplTest { void getMostRecentOnlineStatus() { OnlinePeerJpaDto dto = new OnlinePeerJpaDto(PUBKEY, true, TIMESTAMP); when(repository.findTopByPubkeyOrderByTimestampDesc(PUBKEY.toString())).thenReturn(Optional.of(dto)); - assertThat(dao.getMostRecentOnlineStatus(PUBKEY)).contains(true); + assertThat(dao.getMostRecentOnlineStatus(PUBKEY)).contains(ONLINE_STATUS); } private void verifySave(Pubkey pubkey, boolean expected) { diff --git a/privatechannels/build.gradle b/privatechannels/build.gradle new file mode 100644 index 00000000..ec81af44 --- /dev/null +++ b/privatechannels/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'lnd-manageJ.java-library-conventions' +} + +dependencies { + implementation project(':caching') + implementation project(':model') + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + testRuntimeOnly 'com.h2database:h2' + testFixturesApi testFixtures(project(':model')) +} \ No newline at end of file diff --git a/privatechannels/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java b/privatechannels/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java new file mode 100644 index 00000000..7b1634de --- /dev/null +++ b/privatechannels/src/integrationTest/java/de/cotto/lndmanagej/SpringBootConfiguration.java @@ -0,0 +1,10 @@ +package de.cotto.lndmanagej; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootConfiguration { + public SpringBootConfiguration() { + // default constructor + } +} diff --git a/statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsRepositoryIT.java b/privatechannels/src/integrationTest/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsRepositoryIT.java similarity index 95% rename from statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsRepositoryIT.java rename to privatechannels/src/integrationTest/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsRepositoryIT.java index 55830bed..26b322bd 100644 --- a/statistics/src/integrationTest/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsRepositoryIT.java +++ b/privatechannels/src/integrationTest/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsRepositoryIT.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.privatechannels.persistence; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsDao.java b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsDao.java similarity index 86% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsDao.java rename to privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsDao.java index b206b95f..28ce868a 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsDao.java +++ b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsDao.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics; +package de.cotto.lndmanagej.privatechannels; import de.cotto.lndmanagej.model.ChannelId; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsResolverImpl.java b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsResolverImpl.java similarity index 96% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsResolverImpl.java rename to privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsResolverImpl.java index 10ff0212..ffdb74ff 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsResolverImpl.java +++ b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsResolverImpl.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics; +package de.cotto.lndmanagej.privatechannels; import com.codahale.metrics.annotation.Timed; import com.github.benmanes.caffeine.cache.LoadingCache; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelJpaDto.java b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelJpaDto.java similarity index 93% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelJpaDto.java rename to privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelJpaDto.java index 6e4719f4..0d2beb76 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelJpaDto.java +++ b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelJpaDto.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.privatechannels.persistence; import de.cotto.lndmanagej.model.ChannelId; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsDaoImpl.java b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsDaoImpl.java similarity index 87% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsDaoImpl.java rename to privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsDaoImpl.java index 3fb3d332..8854a0e8 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsDaoImpl.java +++ b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsDaoImpl.java @@ -1,7 +1,7 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.privatechannels.persistence; import de.cotto.lndmanagej.model.ChannelId; -import de.cotto.lndmanagej.statistics.PrivateChannelsDao; +import de.cotto.lndmanagej.privatechannels.PrivateChannelsDao; import org.springframework.stereotype.Component; import javax.transaction.Transactional; diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsRepository.java b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsRepository.java similarity index 73% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsRepository.java rename to privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsRepository.java index 2dae505d..8cc6e094 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsRepository.java +++ b/privatechannels/src/main/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsRepository.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.privatechannels.persistence; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsResolverImplTest.java b/privatechannels/src/test/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsResolverImplTest.java similarity index 96% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsResolverImplTest.java rename to privatechannels/src/test/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsResolverImplTest.java index 0fb13531..0c6e6115 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsResolverImplTest.java +++ b/privatechannels/src/test/java/de/cotto/lndmanagej/privatechannels/PrivateChannelsResolverImplTest.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics; +package de.cotto.lndmanagej.privatechannels; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsDaoImplTest.java b/privatechannels/src/test/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsDaoImplTest.java similarity index 97% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsDaoImplTest.java rename to privatechannels/src/test/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsDaoImplTest.java index 074e880d..7d1de9a1 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/persistence/PrivateChannelsDaoImplTest.java +++ b/privatechannels/src/test/java/de/cotto/lndmanagej/privatechannels/persistence/PrivateChannelsDaoImplTest.java @@ -1,4 +1,4 @@ -package de.cotto.lndmanagej.statistics.persistence; +package de.cotto.lndmanagej.privatechannels.persistence; import de.cotto.lndmanagej.model.ChannelId; import org.junit.jupiter.api.Test; diff --git a/settings.gradle b/settings.gradle index 552e72c5..d24af1ce 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ rootProject.name = 'lnd-manageJ' include 'application' include 'backend' +include 'balances' include 'caching' include 'forwarding-history' include 'grpc-adapter' @@ -8,7 +9,9 @@ include 'grpc-client' include 'hardcoded' include 'invoices' include 'model' +include 'onlinepeers' include 'payments' +include 'privatechannels' include 'selfpayments' include 'statistics' include 'transactions' diff --git a/statistics/build.gradle b/statistics/build.gradle index 758b9ad1..92049cd4 100644 --- a/statistics/build.gradle +++ b/statistics/build.gradle @@ -4,9 +4,10 @@ plugins { dependencies { implementation project(':backend') - implementation project(':model') + implementation project(':balances') implementation project(':caching') - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - testRuntimeOnly 'com.h2database:h2' + implementation project(':model') + implementation project(':onlinepeers') + implementation project(':privatechannels') testFixturesApi testFixtures(project(':model')) } \ No newline at end of file diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/BalanceStatisticsService.java b/statistics/src/main/java/de/cotto/lndmanagej/statistics/BalancesUpdater.java similarity index 87% rename from statistics/src/main/java/de/cotto/lndmanagej/statistics/BalanceStatisticsService.java rename to statistics/src/main/java/de/cotto/lndmanagej/statistics/BalancesUpdater.java index 82bd2586..fea22cc0 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/BalanceStatisticsService.java +++ b/statistics/src/main/java/de/cotto/lndmanagej/statistics/BalancesUpdater.java @@ -1,5 +1,7 @@ package de.cotto.lndmanagej.statistics; +import de.cotto.lndmanagej.balances.Balances; +import de.cotto.lndmanagej.balances.BalancesDao; import de.cotto.lndmanagej.model.BalanceInformation; import de.cotto.lndmanagej.model.LocalOpenChannel; import de.cotto.lndmanagej.service.ChannelService; @@ -12,11 +14,11 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; @Component -public class BalanceStatisticsService { +public class BalancesUpdater { private final ChannelService channelService; private final BalancesDao balancesDao; - public BalanceStatisticsService(ChannelService channelService, BalancesDao balancesDao) { + public BalancesUpdater(ChannelService channelService, BalancesDao balancesDao) { this.channelService = channelService; this.balancesDao = balancesDao; } diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersDao.java b/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersDao.java deleted file mode 100644 index 1cd0c7fa..00000000 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersDao.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.cotto.lndmanagej.statistics; - -import de.cotto.lndmanagej.model.Pubkey; - -import java.time.LocalDateTime; -import java.util.Optional; - -public interface OnlinePeersDao { - void saveOnlineStatus(Pubkey pubkey, boolean online, LocalDateTime timestamp); - - Optional getMostRecentOnlineStatus(Pubkey pubkey); -} diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdater.java b/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdater.java index 49b57111..7ebc9b19 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdater.java +++ b/statistics/src/main/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdater.java @@ -1,13 +1,17 @@ package de.cotto.lndmanagej.statistics; import de.cotto.lndmanagej.model.LocalChannel; +import de.cotto.lndmanagej.model.Node; +import de.cotto.lndmanagej.model.OnlineStatus; +import de.cotto.lndmanagej.onlinepeers.OnlinePeersDao; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.NodeService; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Optional; import java.util.concurrent.TimeUnit; @Component @@ -24,12 +28,20 @@ public class OnlinePeersUpdater { @Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES) public void storePeerOnlineStatus() { - LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); + ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); channelService.getOpenChannels().stream() .map(LocalChannel::getRemotePubkey) .distinct() .map(nodeService::getNode) - .filter(node -> dao.getMostRecentOnlineStatus(node.pubkey()).orElse(!node.online()) != node.online()) + .filter(this::shouldUpdate) .forEach(node -> dao.saveOnlineStatus(node.pubkey(), node.online(), now)); } + + private boolean shouldUpdate(Node node) { + Optional mostRecentOnlineStatus = dao.getMostRecentOnlineStatus(node.pubkey()); + if (mostRecentOnlineStatus.isEmpty()) { + return true; + } + return mostRecentOnlineStatus.get().online() != node.online(); + } } diff --git a/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdater.java b/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdater.java index 18799910..e2b11f29 100644 --- a/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdater.java +++ b/statistics/src/main/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdater.java @@ -1,5 +1,6 @@ package de.cotto.lndmanagej.statistics; +import de.cotto.lndmanagej.privatechannels.PrivateChannelsDao; import de.cotto.lndmanagej.service.ChannelService; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/BalanceStatisticsServiceTest.java b/statistics/src/test/java/de/cotto/lndmanagej/statistics/BalancesUpdaterTest.java similarity index 91% rename from statistics/src/test/java/de/cotto/lndmanagej/statistics/BalanceStatisticsServiceTest.java rename to statistics/src/test/java/de/cotto/lndmanagej/statistics/BalancesUpdaterTest.java index cf56ff57..a7791540 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/BalanceStatisticsServiceTest.java +++ b/statistics/src/test/java/de/cotto/lndmanagej/statistics/BalancesUpdaterTest.java @@ -1,5 +1,7 @@ package de.cotto.lndmanagej.statistics; +import de.cotto.lndmanagej.balances.Balances; +import de.cotto.lndmanagej.balances.BalancesDao; import de.cotto.lndmanagej.model.ChannelId; import de.cotto.lndmanagej.model.LocalOpenChannel; import de.cotto.lndmanagej.service.ChannelService; @@ -26,10 +28,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -class BalanceStatisticsServiceTest { +class BalancesUpdaterTest { private static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.now(ZoneOffset.UTC); @InjectMocks - private BalanceStatisticsService balanceStatisticsService; + private BalancesUpdater balancesUpdater; @Mock private ChannelService channelService; @@ -43,7 +45,7 @@ class BalanceStatisticsServiceTest { LOCAL_OPEN_CHANNEL, LOCAL_OPEN_CHANNEL_MORE_BALANCE_2 )); - balanceStatisticsService.storeBalances(); + balancesUpdater.storeBalances(); verify(dao).saveBalances(argThat(withBalanceInformation(LOCAL_OPEN_CHANNEL_MORE_BALANCE_2))); verify(dao).saveBalances(argThat(withChannelId(LOCAL_OPEN_CHANNEL_MORE_BALANCE_2))); verify(dao).saveBalances(argThat(withBalanceInformation(LOCAL_OPEN_CHANNEL))); @@ -57,7 +59,7 @@ class BalanceStatisticsServiceTest { ChannelId channelId = LOCAL_OPEN_CHANNEL.getId(); Balances balances = new Balances(LOCAL_DATE_TIME, channelId, BALANCE_INFORMATION_2); when(dao.getMostRecentBalances(channelId)).thenReturn(Optional.of(balances)); - balanceStatisticsService.storeBalances(); + balancesUpdater.storeBalances(); verify(dao).saveBalances(any()); } @@ -67,7 +69,7 @@ class BalanceStatisticsServiceTest { ChannelId channelId = LOCAL_OPEN_CHANNEL.getId(); Balances balances = new Balances(LOCAL_DATE_TIME, channelId, LOCAL_OPEN_CHANNEL.getBalanceInformation()); when(dao.getMostRecentBalances(channelId)).thenReturn(Optional.of(balances)); - balanceStatisticsService.storeBalances(); + balancesUpdater.storeBalances(); verify(dao, never()).saveBalances(any()); } diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdaterTest.java b/statistics/src/test/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdaterTest.java index c3f64625..c416908c 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdaterTest.java +++ b/statistics/src/test/java/de/cotto/lndmanagej/statistics/OnlinePeersUpdaterTest.java @@ -1,5 +1,6 @@ package de.cotto.lndmanagej.statistics; +import de.cotto.lndmanagej.onlinepeers.OnlinePeersDao; import de.cotto.lndmanagej.service.ChannelService; import de.cotto.lndmanagej.service.NodeService; import org.junit.jupiter.api.BeforeEach; @@ -17,6 +18,8 @@ import static de.cotto.lndmanagej.model.LocalOpenChannelFixtures.LOCAL_OPEN_CHAN import static de.cotto.lndmanagej.model.NodeFixtures.NODE_2; import static de.cotto.lndmanagej.model.NodeFixtures.NODE_2_PEER; import static de.cotto.lndmanagej.model.NodeFixtures.NODE_3_PEER; +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS; +import static de.cotto.lndmanagej.model.OnlineStatusFixtures.ONLINE_STATUS_OFFLINE; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_2; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY_3; import static org.mockito.ArgumentMatchers.any; @@ -65,7 +68,7 @@ class OnlinePeersUpdaterTest { @Test void saveOnlineStatus_online_to_offline() { - when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(true)); + when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(ONLINE_STATUS)); when(nodeService.getNode(PUBKEY_2)).thenReturn(NODE_2); onlinePeersUpdater.storePeerOnlineStatus(); @@ -75,7 +78,7 @@ class OnlinePeersUpdaterTest { @Test void saveOnlineStatus_offline_to_online() { - when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(false)); + when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(ONLINE_STATUS_OFFLINE)); when(nodeService.getNode(PUBKEY_2)).thenReturn(NODE_2_PEER); onlinePeersUpdater.storePeerOnlineStatus(); @@ -85,7 +88,7 @@ class OnlinePeersUpdaterTest { @Test void saveOnlineStatus_still_offline() { - when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(false)); + when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(ONLINE_STATUS_OFFLINE)); when(nodeService.getNode(PUBKEY_2)).thenReturn(NODE_2); onlinePeersUpdater.storePeerOnlineStatus(); @@ -95,7 +98,7 @@ class OnlinePeersUpdaterTest { @Test void saveOnlineStatus_still_online() { - when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(true)); + when(dao.getMostRecentOnlineStatus(PUBKEY_2)).thenReturn(Optional.of(ONLINE_STATUS)); when(nodeService.getNode(PUBKEY_2)).thenReturn(NODE_2_PEER); onlinePeersUpdater.storePeerOnlineStatus(); diff --git a/statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdaterTest.java b/statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdaterTest.java index e9257ad6..12a34344 100644 --- a/statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdaterTest.java +++ b/statistics/src/test/java/de/cotto/lndmanagej/statistics/PrivateChannelsUpdaterTest.java @@ -1,5 +1,6 @@ package de.cotto.lndmanagej.statistics; +import de.cotto.lndmanagej.privatechannels.PrivateChannelsDao; import de.cotto.lndmanagej.service.ChannelService; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java index 640b29fc..3f86bd99 100644 --- a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java +++ b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/NodeControllerIT.java @@ -100,7 +100,8 @@ class NodeControllerIT { .andExpect(jsonPath("$.onChainCosts.openCosts", is("1000"))) .andExpect(jsonPath("$.onChainCosts.closeCosts", is("2000"))) .andExpect(jsonPath("$.onChainCosts.sweepCosts", is("3000"))) - .andExpect(jsonPath("$.online", is(true))); + .andExpect(jsonPath("$.onlineReport.online", is(true))) + .andExpect(jsonPath("$.onlineReport.since", is("2021-12-23T01:02:03Z"))); } @Test diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ClosedChannelDetailsDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ClosedChannelDetailsDto.java index 8366ae76..63437923 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/ClosedChannelDetailsDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/ClosedChannelDetailsDto.java @@ -15,9 +15,7 @@ public record ClosedChannelDetailsDto(String initiator, int height, boolean forc } public static ClosedChannelDetailsDto createFromModel(LocalChannel localChannel) { - boolean closed = localChannel instanceof ClosedChannel; - if (closed) { - ClosedChannel closedChannel = (ClosedChannel) localChannel; + if (localChannel instanceof ClosedChannel closedChannel) { boolean forceClosed = closedChannel instanceof ForceClosedChannel; boolean breach = forceClosed && closedChannel instanceof BreachForceClosedChannel; return new ClosedChannelDetailsDto( diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java index 58fc246c..c3d1a951 100644 --- a/web/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDto.java @@ -17,7 +17,7 @@ public record NodeDetailsDto( List pendingForceClosingChannels, OnChainCostsDto onChainCosts, BalanceInformationDto balance, - boolean online, + OnlineReportDto onlineReport, FeeReportDto feeReport, RebalanceReportDto rebalanceReport ) { @@ -31,7 +31,7 @@ public record NodeDetailsDto( nodeDetails.pendingForceClosingChannels(), OnChainCostsDto.createFromModel(nodeDetails.onChainCosts()), BalanceInformationDto.createFromModel(nodeDetails.balanceInformation()), - nodeDetails.online(), + OnlineReportDto.createFromModel(nodeDetails.onlineReport()), FeeReportDto.createFromModel(nodeDetails.feeReport()), RebalanceReportDto.createFromModel(nodeDetails.rebalanceReport()) ); diff --git a/web/src/main/java/de/cotto/lndmanagej/controller/dto/OnlineReportDto.java b/web/src/main/java/de/cotto/lndmanagej/controller/dto/OnlineReportDto.java new file mode 100644 index 00000000..1a567580 --- /dev/null +++ b/web/src/main/java/de/cotto/lndmanagej/controller/dto/OnlineReportDto.java @@ -0,0 +1,12 @@ +package de.cotto.lndmanagej.controller.dto; + +import de.cotto.lndmanagej.model.OnlineReport; + +import java.time.format.DateTimeFormatter; + +public record OnlineReportDto(boolean online, String since) { + public static OnlineReportDto createFromModel(OnlineReport onlineReport) { + String formattedDateTime = onlineReport.since().format(DateTimeFormatter.ISO_INSTANT); + return new OnlineReportDto(onlineReport.online(), formattedDateTime); + } +} diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDtoTest.java index 79281c01..9e659789 100644 --- a/web/src/test/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDtoTest.java +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/NodeDetailsDtoTest.java @@ -13,6 +13,7 @@ import static de.cotto.lndmanagej.model.FeeReportFixtures.FEE_REPORT; import static de.cotto.lndmanagej.model.NodeDetailsFixtures.NODE_DETAILS; import static de.cotto.lndmanagej.model.NodeFixtures.ALIAS; import static de.cotto.lndmanagej.model.OnChainCostsFixtures.ON_CHAIN_COSTS; +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; import static de.cotto.lndmanagej.model.PubkeyFixtures.PUBKEY; import static de.cotto.lndmanagej.model.RebalanceReportFixtures.REBALANCE_REPORT; import static org.assertj.core.api.Assertions.assertThat; @@ -29,7 +30,7 @@ class NodeDetailsDtoTest { List.of(CHANNEL_ID_4), OnChainCostsDto.createFromModel(ON_CHAIN_COSTS), BalanceInformationDto.createFromModel(BALANCE_INFORMATION_2), - true, + OnlineReportDto.createFromModel(ONLINE_REPORT), FeeReportDto.createFromModel(FEE_REPORT), RebalanceReportDto.createFromModel(REBALANCE_REPORT) ); diff --git a/web/src/test/java/de/cotto/lndmanagej/controller/dto/OnlineReportDtoTest.java b/web/src/test/java/de/cotto/lndmanagej/controller/dto/OnlineReportDtoTest.java new file mode 100644 index 00000000..633ef600 --- /dev/null +++ b/web/src/test/java/de/cotto/lndmanagej/controller/dto/OnlineReportDtoTest.java @@ -0,0 +1,20 @@ +package de.cotto.lndmanagej.controller.dto; + +import org.junit.jupiter.api.Test; + +import static de.cotto.lndmanagej.model.OnlineReportFixtures.ONLINE_REPORT; +import static org.assertj.core.api.Assertions.assertThat; + +class OnlineReportDtoTest { + @Test + void createFromModel() { + assertThat(OnlineReportDto.createFromModel(ONLINE_REPORT)).isEqualTo( + new OnlineReportDto(ONLINE_REPORT.online(), ONLINE_REPORT.since().toString()) + ); + } + + @Test + void since() { + assertThat(OnlineReportDto.createFromModel(ONLINE_REPORT).since()).isEqualTo("2021-12-23T01:02:03Z"); + } +} \ No newline at end of file