mirror of
https://github.com/aljazceru/lnd-manageJ.git
synced 2026-01-24 08:24:20 +01:00
restructure project
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import de.cotto.lndmanagej.controller.dto.ChannelDetailsDto;
|
||||
import de.cotto.lndmanagej.controller.dto.ObjectMapperConfiguration;
|
||||
import de.cotto.lndmanagej.controller.dto.OnChainCostsDto;
|
||||
import de.cotto.lndmanagej.metrics.Metrics;
|
||||
import de.cotto.lndmanagej.model.BalanceInformation;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.LocalChannel;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import de.cotto.lndmanagej.service.BalanceService;
|
||||
import de.cotto.lndmanagej.service.ChannelService;
|
||||
import de.cotto.lndmanagej.service.NodeService;
|
||||
import de.cotto.lndmanagej.service.OnChainCostService;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/channel/{channelId}")
|
||||
@Import(ObjectMapperConfiguration.class)
|
||||
public class ChannelDetailsController {
|
||||
private final ChannelService channelService;
|
||||
private final NodeService nodeService;
|
||||
private final Metrics metrics;
|
||||
private final BalanceService balanceService;
|
||||
private final OnChainCostService onChainCostService;
|
||||
|
||||
public ChannelDetailsController(
|
||||
ChannelService channelService,
|
||||
NodeService nodeService,
|
||||
BalanceService balanceService,
|
||||
OnChainCostService onChainCostService,
|
||||
Metrics metrics
|
||||
) {
|
||||
this.channelService = channelService;
|
||||
this.nodeService = nodeService;
|
||||
this.balanceService = balanceService;
|
||||
this.onChainCostService = onChainCostService;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@GetMapping("/details")
|
||||
public ChannelDetailsDto getDetails(@PathVariable ChannelId channelId) throws NotFoundException {
|
||||
metrics.mark(MetricRegistry.name(getClass(), "getDetails"));
|
||||
LocalChannel localChannel = channelService.getLocalChannel(channelId).orElse(null);
|
||||
if (localChannel == null) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
Pubkey remotePubkey = localChannel.getRemotePubkey();
|
||||
String remoteAlias = nodeService.getAlias(remotePubkey);
|
||||
return new ChannelDetailsDto(
|
||||
localChannel,
|
||||
remoteAlias,
|
||||
getBalanceInformation(channelId),
|
||||
getOnChainCosts(channelId)
|
||||
);
|
||||
}
|
||||
|
||||
private BalanceInformation getBalanceInformation(ChannelId channelId) {
|
||||
return balanceService.getBalanceInformation(channelId)
|
||||
.orElse(BalanceInformation.EMPTY);
|
||||
}
|
||||
|
||||
private OnChainCostsDto getOnChainCosts(ChannelId channelId) {
|
||||
Coins openCosts = onChainCostService.getOpenCosts(channelId).orElse(Coins.NONE);
|
||||
Coins closeCosts = onChainCostService.getCloseCosts(channelId).orElse(Coins.NONE);
|
||||
return new OnChainCostsDto(openCosts, closeCosts);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@Component
|
||||
public class ChannelIdConverter implements Converter<String, ChannelId> {
|
||||
public ChannelIdConverter() {
|
||||
// default constructor
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelId convert(@Nonnull String source) {
|
||||
try {
|
||||
long shortChannelId = Long.parseLong(source);
|
||||
return ChannelId.fromShortChannelId(shortChannelId);
|
||||
} catch (NumberFormatException numberFormatException) {
|
||||
return ChannelId.fromCompactForm(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
public class CostException extends Exception {
|
||||
public CostException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class CostExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
public CostExceptionHandler() {
|
||||
super();
|
||||
}
|
||||
|
||||
@ExceptionHandler(CostException.class)
|
||||
public ResponseEntity<String> handleException(CostException exception) {
|
||||
return ResponseEntity
|
||||
.badRequest()
|
||||
.body(exception.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import de.cotto.lndmanagej.metrics.Metrics;
|
||||
import de.cotto.lndmanagej.model.Channel;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.LocalOpenChannel;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import de.cotto.lndmanagej.service.BalanceService;
|
||||
import de.cotto.lndmanagej.service.ChannelService;
|
||||
import de.cotto.lndmanagej.service.FeeService;
|
||||
import de.cotto.lndmanagej.service.NodeService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/legacy")
|
||||
public class LegacyController {
|
||||
private static final String NEWLINE = "\n";
|
||||
private final NodeService nodeService;
|
||||
private final ChannelService channelService;
|
||||
private final FeeService feeService;
|
||||
private final BalanceService balanceService;
|
||||
private final Metrics metrics;
|
||||
|
||||
public LegacyController(
|
||||
NodeService nodeService,
|
||||
ChannelService channelService,
|
||||
FeeService feeService,
|
||||
BalanceService balanceService,
|
||||
Metrics metrics
|
||||
) {
|
||||
this.nodeService = nodeService;
|
||||
this.channelService = channelService;
|
||||
this.feeService = feeService;
|
||||
this.balanceService = balanceService;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@GetMapping("/node/{pubkey}/all-channels")
|
||||
public String getAllChannelIdsForPubkey(@PathVariable Pubkey pubkey) {
|
||||
mark("getAllChannelIdsForPubkey");
|
||||
return channelService.getAllChannelsWith(pubkey).stream()
|
||||
.map(Channel::getId)
|
||||
.sorted()
|
||||
.map(ChannelId::toString)
|
||||
.collect(Collectors.joining(NEWLINE));
|
||||
}
|
||||
|
||||
@GetMapping("/open-channels")
|
||||
public String getOpenChannelIds() {
|
||||
mark("getOpenChannelIds");
|
||||
return getOpenChannelIdsSorted()
|
||||
.map(ChannelId::toString)
|
||||
.collect(Collectors.joining(NEWLINE));
|
||||
}
|
||||
|
||||
@GetMapping("/open-channels/pretty")
|
||||
public String getOpenChannelIdsPretty() {
|
||||
mark("getOpenChannelIdsPretty");
|
||||
return channelService.getOpenChannels().stream()
|
||||
.sorted(Comparator.comparing(LocalOpenChannel::getId))
|
||||
.map(localOpenChannel -> {
|
||||
Pubkey pubkey = localOpenChannel.getRemotePubkey();
|
||||
return localOpenChannel.getId().getCompactForm() +
|
||||
"\t" + pubkey +
|
||||
"\t" + localOpenChannel.getCapacity() +
|
||||
"\t" + nodeService.getAlias(pubkey);
|
||||
})
|
||||
.collect(Collectors.joining(NEWLINE));
|
||||
}
|
||||
|
||||
@GetMapping("/closed-channels")
|
||||
public String getClosedChannelIds() {
|
||||
mark("getClosedChannelIds");
|
||||
return getClosedChannelIdsSorted()
|
||||
.map(ChannelId::toString)
|
||||
.collect(Collectors.joining(NEWLINE));
|
||||
}
|
||||
|
||||
@GetMapping("/force-closing-channels")
|
||||
public String getForceClosingChannelIds() {
|
||||
mark("getForceClosingChannelIds");
|
||||
return channelService.getForceClosingChannels().stream()
|
||||
.map(Channel::getId)
|
||||
.sorted()
|
||||
.map(ChannelId::toString)
|
||||
.collect(Collectors.joining(NEWLINE));
|
||||
}
|
||||
|
||||
@GetMapping("/peer-pubkeys")
|
||||
public String getPeerPubkeys() {
|
||||
mark("getPeerPubkeys");
|
||||
return channelService.getOpenChannels().stream()
|
||||
.map(LocalOpenChannel::getRemotePubkey)
|
||||
.map(Pubkey::toString)
|
||||
.sorted()
|
||||
.distinct()
|
||||
.collect(Collectors.joining(NEWLINE));
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/incoming-fee-rate")
|
||||
public long getIncomingFeeRate(@PathVariable ChannelId channelId) {
|
||||
mark("getIncomingFeeRate");
|
||||
return feeService.getIncomingFeeRate(channelId);
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/outgoing-fee-rate")
|
||||
public long getOutgoingFeeRate(@PathVariable ChannelId channelId) {
|
||||
mark("getOutgoingFeeRate");
|
||||
return feeService.getOutgoingFeeRate(channelId);
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/incoming-base-fee")
|
||||
public long getIncomingBaseFee(@PathVariable ChannelId channelId) {
|
||||
mark("getIncomingBaseFee");
|
||||
return feeService.getIncomingBaseFee(channelId).milliSatoshis();
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/outgoing-base-fee")
|
||||
public long getOutgoingBaseFee(@PathVariable ChannelId channelId) {
|
||||
mark("getOutgoingBaseFee");
|
||||
return feeService.getOutgoingBaseFee(channelId).milliSatoshis();
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/available-local-balance")
|
||||
public long getAvailableLocalBalanceForChannel(@PathVariable ChannelId channelId) {
|
||||
mark("getAvailableLocalBalanceForChannel");
|
||||
return balanceService.getAvailableLocalBalance(channelId).satoshis();
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/available-remote-balance")
|
||||
public long getAvailableRemoteBalanceForChannel(@PathVariable ChannelId channelId) {
|
||||
mark("getAvailableRemoteBalanceForChannel");
|
||||
return balanceService.getAvailableRemoteBalance(channelId).satoshis();
|
||||
}
|
||||
|
||||
@GetMapping("/node/{pubkey}/available-local-balance")
|
||||
public long getAvailableLocalBalanceForPeer(@PathVariable Pubkey pubkey) {
|
||||
mark("getAvailableLocalBalanceForPeer");
|
||||
return balanceService.getAvailableLocalBalance(pubkey).satoshis();
|
||||
}
|
||||
|
||||
@GetMapping("/node/{pubkey}/available-remote-balance")
|
||||
public long getAvailableRemoteBalanceForPeer(@PathVariable Pubkey pubkey) {
|
||||
mark("getAvailableRemoteBalanceForPeer");
|
||||
return balanceService.getAvailableRemoteBalance(pubkey).satoshis();
|
||||
}
|
||||
|
||||
private Stream<ChannelId> getOpenChannelIdsSorted() {
|
||||
return channelService.getOpenChannels().stream()
|
||||
.map(Channel::getId)
|
||||
.sorted();
|
||||
}
|
||||
|
||||
private Stream<ChannelId> getClosedChannelIdsSorted() {
|
||||
return channelService.getClosedChannels().stream()
|
||||
.map(Channel::getId)
|
||||
.sorted();
|
||||
}
|
||||
|
||||
private void mark(String name) {
|
||||
metrics.mark(MetricRegistry.name(getClass(), name));
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import de.cotto.lndmanagej.controller.dto.BalanceInformationDto;
|
||||
import de.cotto.lndmanagej.controller.dto.ChannelsForNodeDto;
|
||||
import de.cotto.lndmanagej.controller.dto.NodeDetailsDto;
|
||||
import de.cotto.lndmanagej.controller.dto.ObjectMapperConfiguration;
|
||||
import de.cotto.lndmanagej.controller.dto.OnChainCostsDto;
|
||||
import de.cotto.lndmanagej.metrics.Metrics;
|
||||
import de.cotto.lndmanagej.model.BalanceInformation;
|
||||
import de.cotto.lndmanagej.model.Channel;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.Node;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import de.cotto.lndmanagej.service.BalanceService;
|
||||
import de.cotto.lndmanagej.service.ChannelService;
|
||||
import de.cotto.lndmanagej.service.NodeService;
|
||||
import de.cotto.lndmanagej.service.OnChainCostService;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/node/{pubkey}")
|
||||
@Import(ObjectMapperConfiguration.class)
|
||||
public class NodeController {
|
||||
private final NodeService nodeService;
|
||||
private final Metrics metrics;
|
||||
private final ChannelService channelService;
|
||||
private final OnChainCostService onChainCostService;
|
||||
private final BalanceService balanceService;
|
||||
|
||||
public NodeController(
|
||||
NodeService nodeService,
|
||||
ChannelService channelService,
|
||||
Metrics metrics,
|
||||
OnChainCostService onChainCostService,
|
||||
BalanceService balanceService
|
||||
) {
|
||||
this.nodeService = nodeService;
|
||||
this.metrics = metrics;
|
||||
this.channelService = channelService;
|
||||
this.onChainCostService = onChainCostService;
|
||||
this.balanceService = balanceService;
|
||||
}
|
||||
|
||||
@GetMapping("/alias")
|
||||
public String getAlias(Pubkey pubkey) {
|
||||
mark("getAlias");
|
||||
return nodeService.getAlias(pubkey);
|
||||
}
|
||||
|
||||
@GetMapping("/details")
|
||||
public NodeDetailsDto getDetails(@PathVariable Pubkey pubkey) {
|
||||
mark("getDetails");
|
||||
Node node = nodeService.getNode(pubkey);
|
||||
Coins openCosts = onChainCostService.getOpenCostsWith(pubkey);
|
||||
Coins closeCosts = onChainCostService.getCloseCostsWith(pubkey);
|
||||
BalanceInformation balanceInformation = balanceService.getBalanceInformation(pubkey);
|
||||
return new NodeDetailsDto(
|
||||
pubkey,
|
||||
node.alias(),
|
||||
toSortedList(channelService.getOpenChannelsWith(pubkey)),
|
||||
toSortedList(channelService.getClosedChannelsWith(pubkey)),
|
||||
toSortedList(channelService.getWaitingCloseChannelsFor(pubkey)),
|
||||
toSortedList(channelService.getForceClosingChannelsFor(pubkey)),
|
||||
new OnChainCostsDto(openCosts, closeCosts),
|
||||
BalanceInformationDto.createFrom(balanceInformation),
|
||||
node.online()
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/open-channels")
|
||||
public ChannelsForNodeDto getOpenChannelIdsForPubkey(@PathVariable Pubkey pubkey) {
|
||||
mark("getOpenChannelIdsForPubkey");
|
||||
List<ChannelId> channels = toSortedList(channelService.getOpenChannelsWith(pubkey));
|
||||
return new ChannelsForNodeDto(pubkey, channels);
|
||||
}
|
||||
|
||||
private List<ChannelId> toSortedList(Set<? extends Channel> channels) {
|
||||
return channels.stream()
|
||||
.map(Channel::getId)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void mark(String getDetails) {
|
||||
metrics.mark(MetricRegistry.name(getClass(), getDetails));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
public class NotFoundException extends Exception {
|
||||
public NotFoundException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class NotFoundExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
public NotFoundExceptionHandler() {
|
||||
super();
|
||||
}
|
||||
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<String> handleException(@SuppressWarnings("unused") NotFoundException exception) {
|
||||
return ResponseEntity
|
||||
.notFound()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import de.cotto.lndmanagej.controller.dto.OnChainCostsDto;
|
||||
import de.cotto.lndmanagej.metrics.Metrics;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import de.cotto.lndmanagej.service.OnChainCostService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/")
|
||||
public class OnChainCostsController {
|
||||
private final OnChainCostService onChainCostService;
|
||||
private final Metrics metrics;
|
||||
|
||||
public OnChainCostsController(OnChainCostService onChainCostService, Metrics metrics) {
|
||||
this.onChainCostService = onChainCostService;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@GetMapping("/node/{pubkey}/on-chain-costs")
|
||||
public OnChainCostsDto getCostsForPeer(@PathVariable Pubkey pubkey) {
|
||||
metrics.mark(MetricRegistry.name(getClass(), "getCostsForPeer"));
|
||||
return new OnChainCostsDto(
|
||||
onChainCostService.getOpenCostsWith(pubkey),
|
||||
onChainCostService.getCloseCostsWith(pubkey)
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/open-costs")
|
||||
public long getOpenCostsForChannel(@PathVariable ChannelId channelId) throws CostException {
|
||||
metrics.mark(MetricRegistry.name(getClass(), "getOpenCostsForChannel"));
|
||||
return onChainCostService.getOpenCosts(channelId).map(Coins::satoshis)
|
||||
.orElseThrow(() -> new CostException("Unable to get open costs for channel with ID " + channelId));
|
||||
}
|
||||
|
||||
@GetMapping("/channel/{channelId}/close-costs")
|
||||
public long getCloseCostsForChannel(@PathVariable ChannelId channelId) throws CostException {
|
||||
metrics.mark(MetricRegistry.name(getClass(), "getCloseCostsForChannel"));
|
||||
return onChainCostService.getCloseCosts(channelId).map(Coins::satoshis)
|
||||
.orElseThrow(() -> new CostException("Unable to get close costs for channel with ID " + channelId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@Component
|
||||
public class PubkeyConverter implements Converter<String, Pubkey> {
|
||||
public PubkeyConverter() {
|
||||
// default constructor
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pubkey convert(@Nonnull String source) {
|
||||
return Pubkey.create(source);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import de.cotto.lndmanagej.controller.dto.ObjectMapperConfiguration;
|
||||
import de.cotto.lndmanagej.metrics.Metrics;
|
||||
import de.cotto.lndmanagej.service.OwnNodeService;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/status/")
|
||||
@Import(ObjectMapperConfiguration.class)
|
||||
public class StatusController {
|
||||
private final OwnNodeService ownNodeService;
|
||||
private final Metrics metrics;
|
||||
|
||||
public StatusController(OwnNodeService ownNodeService, Metrics metrics) {
|
||||
this.ownNodeService = ownNodeService;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
@GetMapping("/synced-to-chain")
|
||||
public boolean isSyncedToChain() {
|
||||
metrics.mark(MetricRegistry.name(getClass(), "isSyncedToChain"));
|
||||
return ownNodeService.isSyncedToChain();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller.dto;
|
||||
|
||||
import de.cotto.lndmanagej.model.BalanceInformation;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
|
||||
public record BalanceInformationDto(
|
||||
String localBalance,
|
||||
String localReserve,
|
||||
String localAvailable,
|
||||
String remoteBalance,
|
||||
String remoteReserve,
|
||||
String remoteAvailable
|
||||
) {
|
||||
public static BalanceInformationDto createFrom(BalanceInformation balanceInformation) {
|
||||
return new BalanceInformationDto(
|
||||
toString(balanceInformation.localBalance()),
|
||||
toString(balanceInformation.localReserve()),
|
||||
toString(balanceInformation.localAvailable()),
|
||||
toString(balanceInformation.remoteBalance()),
|
||||
toString(balanceInformation.remoteReserve()),
|
||||
toString(balanceInformation.remoteAvailable())
|
||||
);
|
||||
}
|
||||
|
||||
private static String toString(Coins coins) {
|
||||
return String.valueOf(coins.satoshis());
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import de.cotto.lndmanagej.model.BalanceInformation;
|
||||
import de.cotto.lndmanagej.model.ChannelPoint;
|
||||
import de.cotto.lndmanagej.model.LocalChannel;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
|
||||
public record ChannelDetailsDto(
|
||||
String channelIdShort,
|
||||
String channelIdCompact,
|
||||
String channelIdCompactLnd,
|
||||
ChannelPoint channelPoint,
|
||||
Pubkey remotePubkey,
|
||||
String remoteAlias,
|
||||
@JsonProperty("private") boolean privateChannel,
|
||||
BalanceInformationDto balance,
|
||||
OnChainCostsDto onChainCosts
|
||||
) {
|
||||
public ChannelDetailsDto(
|
||||
LocalChannel localChannel,
|
||||
String remoteAlias,
|
||||
BalanceInformation balanceInformation,
|
||||
OnChainCostsDto onChainCosts
|
||||
) {
|
||||
this(
|
||||
String.valueOf(localChannel.getId().getShortChannelId()),
|
||||
localChannel.getId().getCompactForm(),
|
||||
localChannel.getId().getCompactFormLnd(),
|
||||
localChannel.getChannelPoint(),
|
||||
localChannel.getRemotePubkey(),
|
||||
remoteAlias,
|
||||
localChannel.isPrivateChannel(),
|
||||
BalanceInformationDto.createFrom(balanceInformation),
|
||||
onChainCosts
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller.dto;
|
||||
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ChannelsForNodeDto(
|
||||
Pubkey node,
|
||||
List<ChannelId> channels
|
||||
) {
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record NodeDetailsDto(
|
||||
@JsonSerialize(using = ToStringSerializer.class) Pubkey node,
|
||||
String alias,
|
||||
List<ChannelId> channels,
|
||||
List<ChannelId> closedChannels,
|
||||
List<ChannelId> waitingCloseChannels,
|
||||
List<ChannelId> pendingForceClosingChannels,
|
||||
OnChainCostsDto onChainCosts,
|
||||
BalanceInformationDto balance,
|
||||
boolean online
|
||||
) {
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.ChannelPoint;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
@Configuration
|
||||
public class ObjectMapperConfiguration {
|
||||
public ObjectMapperConfiguration() {
|
||||
// default constructor
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public ObjectMapper objectMapper() {
|
||||
SimpleModule module = new SimpleModule("SimpleModule");
|
||||
module.addSerializer(Pubkey.class, new ToStringSerializer());
|
||||
module.addSerializer(ChannelId.class, new ToStringSerializer());
|
||||
module.addSerializer(ChannelPoint.class, new ToStringSerializer());
|
||||
return new ObjectMapper().registerModule(module);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package de.cotto.lndmanagej.controller.dto;
|
||||
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
|
||||
public record OnChainCostsDto(String openCosts, String closeCosts) {
|
||||
public OnChainCostsDto(Coins openCosts, Coins closeCosts) {
|
||||
this(String.valueOf(openCosts.satoshis()), String.valueOf(closeCosts.satoshis()));
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import de.cotto.lndmanagej.grpc.GrpcChannels;
|
||||
import de.cotto.lndmanagej.model.BalanceInformation;
|
||||
import de.cotto.lndmanagej.model.Channel;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.LocalOpenChannel;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class BalanceService {
|
||||
private final GrpcChannels grpcChannels;
|
||||
private final ChannelService channelService;
|
||||
|
||||
public BalanceService(GrpcChannels grpcChannels, ChannelService channelService) {
|
||||
this.grpcChannels = grpcChannels;
|
||||
this.channelService = channelService;
|
||||
}
|
||||
|
||||
public Coins getAvailableLocalBalance(Pubkey peer) {
|
||||
return channelService.getOpenChannelsWith(peer).stream()
|
||||
.map(LocalOpenChannel::getId)
|
||||
.map(this::getAvailableLocalBalance)
|
||||
.reduce(Coins.NONE, Coins::add);
|
||||
}
|
||||
|
||||
public Coins getAvailableLocalBalance(ChannelId channelId) {
|
||||
return getBalanceInformation(channelId)
|
||||
.map(BalanceInformation::localAvailable)
|
||||
.orElse(Coins.NONE);
|
||||
}
|
||||
|
||||
public Coins getAvailableRemoteBalance(Pubkey peer) {
|
||||
return channelService.getOpenChannelsWith(peer).stream()
|
||||
.map(LocalOpenChannel::getId)
|
||||
.map(this::getAvailableRemoteBalance)
|
||||
.reduce(Coins.NONE, Coins::add);
|
||||
}
|
||||
|
||||
public Coins getAvailableRemoteBalance(ChannelId channelId) {
|
||||
return getBalanceInformation(channelId)
|
||||
.map(BalanceInformation::remoteAvailable)
|
||||
.orElse(Coins.NONE);
|
||||
}
|
||||
|
||||
public BalanceInformation getBalanceInformation(Pubkey pubkey) {
|
||||
return channelService.getOpenChannelsWith(pubkey).stream()
|
||||
.map(Channel::getId)
|
||||
.map(this::getBalanceInformation)
|
||||
.flatMap(Optional::stream)
|
||||
.reduce(BalanceInformation.EMPTY, BalanceInformation::add);
|
||||
}
|
||||
|
||||
public Optional<BalanceInformation> getBalanceInformation(ChannelId channelId) {
|
||||
return grpcChannels.getChannel(channelId)
|
||||
.map(LocalOpenChannel::getBalanceInformation);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.ChannelIdResolver;
|
||||
import de.cotto.lndmanagej.model.ChannelPoint;
|
||||
import de.cotto.lndmanagej.transactions.model.Transaction;
|
||||
import de.cotto.lndmanagej.transactions.service.TransactionService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ChannelIdResolverImpl implements ChannelIdResolver {
|
||||
private final TransactionService transactionService;
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public ChannelIdResolverImpl(TransactionService transactionService) {
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ChannelId> resolveFromChannelPoint(ChannelPoint channelPoint) {
|
||||
String transactionHash = channelPoint.getTransactionHash();
|
||||
Optional<Transaction> transactionOptional = transactionService.getTransaction(transactionHash);
|
||||
if (transactionOptional.isEmpty()) {
|
||||
logger.warn("Unable resolve transaction ID for {}", transactionHash);
|
||||
}
|
||||
return transactionOptional.map(transaction -> getChannelId(transaction, channelPoint));
|
||||
}
|
||||
|
||||
private ChannelId getChannelId(Transaction transaction, ChannelPoint channelPoint) {
|
||||
int block = transaction.blockHeight();
|
||||
int transactionIndex = transaction.positionInBlock();
|
||||
int output = channelPoint.getOutput();
|
||||
return ChannelId.fromCompactForm(block + ":" + transactionIndex + ":" + output);
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import de.cotto.lndmanagej.caching.CacheBuilder;
|
||||
import de.cotto.lndmanagej.grpc.GrpcChannels;
|
||||
import de.cotto.lndmanagej.grpc.GrpcClosedChannels;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.ClosedChannel;
|
||||
import de.cotto.lndmanagej.model.ForceClosingChannel;
|
||||
import de.cotto.lndmanagej.model.LocalChannel;
|
||||
import de.cotto.lndmanagej.model.LocalOpenChannel;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import de.cotto.lndmanagej.model.WaitingCloseChannel;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Component
|
||||
public class ChannelService {
|
||||
private static final Duration CACHE_EXPIRY = Duration.ofMinutes(1);
|
||||
|
||||
private final GrpcChannels grpcChannels;
|
||||
private final LoadingCache<Object, Set<LocalOpenChannel>> channelsCache;
|
||||
private final LoadingCache<Object, Set<ClosedChannel>> closedChannelsCache;
|
||||
private final LoadingCache<Object, Set<ForceClosingChannel>> forceClosingChannelsCache;
|
||||
private final LoadingCache<Object, Set<WaitingCloseChannel>> waitingCloseChannelsCache;
|
||||
|
||||
public ChannelService(GrpcChannels grpcChannels, GrpcClosedChannels grpcClosedChannels) {
|
||||
this.grpcChannels = grpcChannels;
|
||||
channelsCache = new CacheBuilder()
|
||||
.withExpiry(CACHE_EXPIRY)
|
||||
.build(grpcChannels::getChannels);
|
||||
closedChannelsCache = new CacheBuilder()
|
||||
.withExpiry(CACHE_EXPIRY)
|
||||
.build(grpcClosedChannels::getClosedChannels);
|
||||
forceClosingChannelsCache = new CacheBuilder()
|
||||
.withExpiry(CACHE_EXPIRY)
|
||||
.build(grpcChannels::getForceClosingChannels);
|
||||
waitingCloseChannelsCache = new CacheBuilder()
|
||||
.withExpiry(CACHE_EXPIRY)
|
||||
.build(grpcChannels::getWaitingCloseChannels);
|
||||
}
|
||||
|
||||
public boolean isClosed(ChannelId channelId) {
|
||||
return getClosedChannel(channelId).isPresent();
|
||||
}
|
||||
|
||||
public Optional<LocalChannel> getLocalChannel(ChannelId channelId) {
|
||||
return getAllLocalChannels()
|
||||
.filter(c -> channelId.equals(c.getId()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Set<LocalOpenChannel> getOpenChannels() {
|
||||
return channelsCache.get("");
|
||||
}
|
||||
|
||||
public Optional<LocalOpenChannel> getOpenChannel(ChannelId channelId) {
|
||||
return grpcChannels.getChannel(channelId);
|
||||
}
|
||||
|
||||
public Set<ClosedChannel> getClosedChannels() {
|
||||
return closedChannelsCache.get("");
|
||||
}
|
||||
|
||||
public Optional<ClosedChannel> getClosedChannel(ChannelId channelId) {
|
||||
return getClosedChannels().stream()
|
||||
.filter(c -> channelId.equals(c.getId()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Set<ForceClosingChannel> getForceClosingChannels() {
|
||||
return forceClosingChannelsCache.get("");
|
||||
}
|
||||
|
||||
public Optional<ForceClosingChannel> getForceClosingChannel(ChannelId channelId) {
|
||||
return getForceClosingChannels().stream()
|
||||
.filter(c -> channelId.equals(c.getId()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Set<WaitingCloseChannel> getWaitingCloseChannels() {
|
||||
return waitingCloseChannelsCache.get("");
|
||||
}
|
||||
|
||||
public Set<LocalOpenChannel> getOpenChannelsWith(Pubkey peer) {
|
||||
return getOpenChannels().stream()
|
||||
.filter(c -> peer.equals(c.getRemotePubkey()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<ClosedChannel> getClosedChannelsWith(Pubkey peer) {
|
||||
return getClosedChannels().stream()
|
||||
.filter(c -> peer.equals(c.getRemotePubkey()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<WaitingCloseChannel> getWaitingCloseChannelsFor(Pubkey peer) {
|
||||
return getWaitingCloseChannels().stream()
|
||||
.filter(c -> peer.equals(c.getRemotePubkey()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<ForceClosingChannel> getForceClosingChannelsFor(Pubkey peer) {
|
||||
return getForceClosingChannels().stream()
|
||||
.filter(c -> peer.equals(c.getRemotePubkey()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<LocalChannel> getAllChannelsWith(Pubkey peer) {
|
||||
return getAllLocalChannels()
|
||||
.filter(c -> peer.equals(c.getRemotePubkey()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Stream<LocalChannel> getAllLocalChannels() {
|
||||
Supplier<Set<LocalOpenChannel>> openChannels = this::getOpenChannels;
|
||||
Supplier<Set<ClosedChannel>> closedChannels = this::getClosedChannels;
|
||||
Supplier<Set<WaitingCloseChannel>> waitingCloseChannels = this::getWaitingCloseChannels;
|
||||
Supplier<Set<ForceClosingChannel>> forceClosingChannels = this::getForceClosingChannels;
|
||||
return Stream.of(
|
||||
openChannels,
|
||||
closedChannels,
|
||||
waitingCloseChannels,
|
||||
forceClosingChannels
|
||||
).map(Supplier::get).flatMap(Collection::stream);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import de.cotto.lndmanagej.grpc.GrpcFees;
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class FeeService {
|
||||
private final GrpcFees grpcFees;
|
||||
|
||||
public FeeService(GrpcFees grpcFees) {
|
||||
this.grpcFees = grpcFees;
|
||||
}
|
||||
|
||||
public long getIncomingFeeRate(ChannelId channelId) {
|
||||
return grpcFees.getIncomingFeeRate(channelId).orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
public long getOutgoingFeeRate(ChannelId channelId) {
|
||||
return grpcFees.getOutgoingFeeRate(channelId).orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
public Coins getOutgoingBaseFee(ChannelId channelId) {
|
||||
return grpcFees.getOutgoingBaseFee(channelId).orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
public Coins getIncomingBaseFee(ChannelId channelId) {
|
||||
return grpcFees.getIncomingBaseFee(channelId).orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import de.cotto.lndmanagej.caching.CacheBuilder;
|
||||
import de.cotto.lndmanagej.grpc.GrpcNodeInfo;
|
||||
import de.cotto.lndmanagej.model.Node;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Component
|
||||
public class NodeService {
|
||||
private static final int MAXIMUM_SIZE = 500;
|
||||
private static final Duration ALIAS_CACHE_EXPIRY = Duration.ofHours(24);
|
||||
private static final Duration ALIAS_CACHE_REFRESH = Duration.ofMinutes(30);
|
||||
private static final Duration NODE_CACHE_EXPIRY = Duration.ofSeconds(60);
|
||||
|
||||
private final GrpcNodeInfo grpcNodeInfo;
|
||||
private final LoadingCache<Pubkey, String> aliasCache = new CacheBuilder()
|
||||
.withExpiry(ALIAS_CACHE_EXPIRY)
|
||||
.withRefresh(ALIAS_CACHE_REFRESH)
|
||||
.withMaximumSize(MAXIMUM_SIZE)
|
||||
.build(this::getAliasWithoutCacheAndUpdateNodeCache);
|
||||
private final LoadingCache<Pubkey, Node> nodeCache = new CacheBuilder()
|
||||
.withExpiry(NODE_CACHE_EXPIRY)
|
||||
.withMaximumSize(MAXIMUM_SIZE)
|
||||
.build(this::getNodeWithoutCacheAndUpdateAliasCache);
|
||||
|
||||
public NodeService(GrpcNodeInfo grpcNodeInfo) {
|
||||
this.grpcNodeInfo = grpcNodeInfo;
|
||||
}
|
||||
|
||||
public String getAlias(Pubkey pubkey) {
|
||||
return aliasCache.get(pubkey);
|
||||
}
|
||||
|
||||
public Node getNode(Pubkey pubkey) {
|
||||
return nodeCache.get(pubkey);
|
||||
}
|
||||
|
||||
private Node getNodeWithoutCacheAndUpdateAliasCache(Pubkey pubkey) {
|
||||
Node node = grpcNodeInfo.getNode(pubkey);
|
||||
aliasCache.put(pubkey, node.alias());
|
||||
return node;
|
||||
}
|
||||
|
||||
private String getAliasWithoutCacheAndUpdateNodeCache(Pubkey pubkey) {
|
||||
Node node = grpcNodeInfo.getNode(pubkey);
|
||||
nodeCache.put(pubkey, node);
|
||||
return node.alias();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import de.cotto.lndmanagej.model.ChannelId;
|
||||
import de.cotto.lndmanagej.model.ChannelPoint;
|
||||
import de.cotto.lndmanagej.model.ClosedChannel;
|
||||
import de.cotto.lndmanagej.model.Coins;
|
||||
import de.cotto.lndmanagej.model.LocalChannel;
|
||||
import de.cotto.lndmanagej.model.OpenInitiator;
|
||||
import de.cotto.lndmanagej.model.Pubkey;
|
||||
import de.cotto.lndmanagej.transactions.model.Transaction;
|
||||
import de.cotto.lndmanagej.transactions.service.TransactionService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class OnChainCostService {
|
||||
private final TransactionService transactionService;
|
||||
private final ChannelService channelService;
|
||||
|
||||
public OnChainCostService(TransactionService transactionService, ChannelService channelService) {
|
||||
this.transactionService = transactionService;
|
||||
this.channelService = channelService;
|
||||
}
|
||||
|
||||
public Coins getOpenCostsWith(Pubkey pubkey) {
|
||||
return channelService.getAllChannelsWith(pubkey).stream()
|
||||
.map(this::getOpenCosts)
|
||||
.flatMap(Optional::stream)
|
||||
.reduce(Coins.NONE, Coins::add);
|
||||
}
|
||||
|
||||
public Optional<Coins> getOpenCosts(ChannelId channelId) {
|
||||
return channelService.getLocalChannel(channelId).flatMap(this::getOpenCosts);
|
||||
}
|
||||
|
||||
public Optional<Coins> getOpenCosts(LocalChannel localChannel) {
|
||||
if (localChannel.getOpenInitiator().equals(OpenInitiator.LOCAL)) {
|
||||
String openTransactionHash = localChannel.getChannelPoint().getTransactionHash();
|
||||
return transactionService.getTransaction(openTransactionHash)
|
||||
.map(Transaction::fees)
|
||||
.map(Coins::satoshis)
|
||||
.map(sat -> {
|
||||
long channels = getNumberOfChannelsWithOpenTransactionHash(openTransactionHash);
|
||||
return Coins.ofSatoshis(sat / channels);
|
||||
});
|
||||
}
|
||||
if (localChannel.getOpenInitiator().equals(OpenInitiator.REMOTE)) {
|
||||
return Optional.of(Coins.NONE);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Coins getCloseCostsWith(Pubkey pubkey) {
|
||||
return channelService.getClosedChannelsWith(pubkey).stream()
|
||||
.map(this::getCloseCosts)
|
||||
.flatMap(Optional::stream)
|
||||
.reduce(Coins.NONE, Coins::add);
|
||||
}
|
||||
|
||||
public Optional<Coins> getCloseCosts(ChannelId channelId) {
|
||||
if (channelService.isClosed(channelId)) {
|
||||
return channelService.getClosedChannel(channelId).flatMap(this::getCloseCosts);
|
||||
}
|
||||
return Optional.of(Coins.NONE);
|
||||
}
|
||||
|
||||
public Optional<Coins> getCloseCosts(ClosedChannel closedChannel) {
|
||||
if (closedChannel.getOpenInitiator().equals(OpenInitiator.LOCAL)) {
|
||||
return transactionService.getTransaction(closedChannel.getCloseTransactionHash())
|
||||
.map(Transaction::fees);
|
||||
}
|
||||
if (closedChannel.getOpenInitiator().equals(OpenInitiator.REMOTE)) {
|
||||
return Optional.of(Coins.NONE);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private long getNumberOfChannelsWithOpenTransactionHash(String openTransactionHash) {
|
||||
return channelService.getAllLocalChannels()
|
||||
.map(LocalChannel::getChannelPoint)
|
||||
.map(ChannelPoint::getTransactionHash)
|
||||
.filter(x -> x.equals(openTransactionHash))
|
||||
.count();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import de.cotto.lndmanagej.model.OpenInitiator;
|
||||
import de.cotto.lndmanagej.model.OpenInitiatorResolver;
|
||||
import de.cotto.lndmanagej.transactions.service.TransactionService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class OpenInitiatorResolverImpl implements OpenInitiatorResolver {
|
||||
private final TransactionService transactionService;
|
||||
|
||||
public OpenInitiatorResolverImpl(TransactionService transactionService) {
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenInitiator resolveFromOpenTransactionHash(String transactionHash) {
|
||||
Boolean knownByLnd = transactionService.isKnownByLnd(transactionHash).orElse(null);
|
||||
if (knownByLnd == null) {
|
||||
return OpenInitiator.UNKNOWN;
|
||||
}
|
||||
if (knownByLnd) {
|
||||
return OpenInitiator.LOCAL;
|
||||
}
|
||||
return OpenInitiator.REMOTE;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import de.cotto.lndmanagej.caching.CacheBuilder;
|
||||
import de.cotto.lndmanagej.grpc.GrpcGetInfo;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Component
|
||||
public class OwnNodeService {
|
||||
private static final Duration CACHE_EXPIRY = Duration.ofSeconds(30);
|
||||
|
||||
private final GrpcGetInfo grpcGetInfo;
|
||||
private final LoadingCache<Object, Boolean> syncedToChainCache = new CacheBuilder()
|
||||
.withExpiry(CACHE_EXPIRY)
|
||||
.build(this::isSyncedToChainWithoutCache);
|
||||
|
||||
public OwnNodeService(GrpcGetInfo grpcGetInfo) {
|
||||
this.grpcGetInfo = grpcGetInfo;
|
||||
}
|
||||
|
||||
public boolean isSyncedToChain() {
|
||||
return Boolean.TRUE.equals(syncedToChainCache.get(""));
|
||||
}
|
||||
|
||||
private boolean isSyncedToChainWithoutCache() {
|
||||
return grpcGetInfo.isSyncedToChain().orElse(false);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package de.cotto.lndmanagej.service;
|
||||
|
||||
import de.cotto.lndmanagej.model.Channel;
|
||||
import de.cotto.lndmanagej.model.ChannelPoint;
|
||||
import de.cotto.lndmanagej.model.ClosedOrClosingChannel;
|
||||
import de.cotto.lndmanagej.model.ForceClosingChannel;
|
||||
import de.cotto.lndmanagej.transactions.service.TransactionService;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
|
||||
@Component
|
||||
public class TransactionBackgroundLoader {
|
||||
private final ChannelService channelService;
|
||||
private final TransactionService transactionService;
|
||||
|
||||
public TransactionBackgroundLoader(ChannelService channelService, TransactionService transactionService) {
|
||||
this.channelService = channelService;
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 5, timeUnit = MINUTES)
|
||||
public void loadTransactionForOneChannel() {
|
||||
getTransactionHashes()
|
||||
.filter(transactionService::isUnknown)
|
||||
.findAny()
|
||||
.ifPresent(transactionService::getTransaction);
|
||||
}
|
||||
|
||||
private Stream<String> getTransactionHashes() {
|
||||
Stream<String> openTransactionHashes = getOpenTransactionHashes();
|
||||
Stream<String> closeTransactionHashes = getCloseTransactionHashes();
|
||||
Stream<String> htlcOutpointHashes = getHtlcOutpointHashes();
|
||||
return Stream.of(openTransactionHashes, closeTransactionHashes, htlcOutpointHashes)
|
||||
.flatMap(s -> s);
|
||||
}
|
||||
|
||||
private Stream<String> getOpenTransactionHashes() {
|
||||
return Stream.of(
|
||||
channelService.getOpenChannels(),
|
||||
channelService.getClosedChannels(),
|
||||
channelService.getForceClosingChannels(),
|
||||
channelService.getWaitingCloseChannels()
|
||||
)
|
||||
.flatMap(Collection::stream)
|
||||
.map(Channel::getChannelPoint)
|
||||
.map(ChannelPoint::getTransactionHash);
|
||||
}
|
||||
|
||||
private Stream<String> getCloseTransactionHashes() {
|
||||
return Stream.of(channelService.getClosedChannels(), channelService.getForceClosingChannels())
|
||||
.flatMap(Collection::stream)
|
||||
.map(ClosedOrClosingChannel::getCloseTransactionHash);
|
||||
}
|
||||
|
||||
private Stream<String> getHtlcOutpointHashes() {
|
||||
return channelService.getForceClosingChannels().stream()
|
||||
.map(ForceClosingChannel::getHtlcOutpoints)
|
||||
.flatMap(Collection::stream)
|
||||
.map(ChannelPoint::getTransactionHash);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user