Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/2634/simple html node monitor #3000

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import bisq.chat.ChatService;
import bisq.common.application.Service;
import bisq.common.network.Address;
import bisq.rest_api.dto.AddressInfoDto;
import bisq.common.network.TransportType;
import bisq.common.observable.Observable;
import bisq.common.platform.OS;
Expand All @@ -46,18 +47,17 @@
import bisq.support.SupportService;
import bisq.trade.TradeService;
import bisq.user.UserService;
import bisq.user.profile.UserProfile;
import bisq.wallets.core.BitcoinWalletSelection;
import bisq.wallets.core.WalletService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.concurrent.CompletableFuture.supplyAsync;
Expand Down Expand Up @@ -271,7 +271,6 @@ public KeyBundleService getKeyPairService() {
return securityService.getKeyBundleService();
}


private void setState(State newState) {
checkArgument(state.get().ordinal() < newState.ordinal(),
"New state %s must have a higher ordinal as the current state %s", newState, state.get());
Expand All @@ -298,7 +297,7 @@ private Optional<OsSpecificNotificationService> findSystemNotificationDelegate()
}
}

public List<String> getAddressList() {
public List<String> getAddresses() {

Set<Address> bannedAddresses = bondedRolesService.getAuthorizedBondedRolesService().getBondedRoles().stream()
.filter(BondedRole::isBanned)
Expand All @@ -310,17 +309,38 @@ public List<String> getAddressList() {
.collect(Collectors.toSet());
Map<TransportType, Set<Address>> seedAddressesByTransport = networkService.getSeedAddressesByTransportFromConfig();
Set<TransportType> supportedTransportTypes = networkService.getSupportedTransportTypes();
List<String> addresslist = seedAddressesByTransport.entrySet().stream()
List<String> addresses = seedAddressesByTransport.entrySet().stream()
.filter(entry -> supportedTransportTypes.contains(entry.getKey()))
.flatMap(entry -> entry.getValue().stream())
.filter(address -> !bannedAddresses.contains(address))
.map(Address::toString)
.collect(Collectors.toList());

// Oracle Nodes
addresslist.add("kr4yvzlhwt5binpw7js2tsfqv6mjd4klmslmcxw3c5izsaqh5vvsp6ad.onion:36185");
addresslist.add("s2yxxqvyofzud32mxliya3dihj5rdlowagkblqqtntxhi7cbdaufqkid.onion:54467");
addresses.add("kr4yvzlhwt5binpw7js2tsfqv6mjd4klmslmcxw3c5izsaqh5vvsp6ad.onion:36185");
addresses.add("s2yxxqvyofzud32mxliya3dihj5rdlowagkblqqtntxhi7cbdaufqkid.onion:54467");

return addresses;
}

return addresslist;
/**
* @return The result set may be smaller than the list of addresses in the parameter.
*/
public List<AddressInfoDto> getAddressInfos(List<String> addresses) {
Set<BondedRole> bondedRoles = bondedRolesService.getAuthorizedBondedRolesService().getBondedRoles();
return bondedRoles.stream()
.flatMap(bondedRole -> bondedRole.getAuthorizedBondedRole().getAddressByTransportTypeMap()
.map(addressMap -> addressMap.entrySet().stream()
.filter(entry -> addresses.contains(entry.getValue().toString()))
.map(entry -> AddressInfoDto.getBuilder()
.address(entry.getValue())
.bondedRoleType(bondedRole.getAuthorizedBondedRole().getBondedRoleType())
.nickNameOrBondUserName(userService.getUserProfileService()
.findUserProfile(bondedRole.getAuthorizedBondedRole().getProfileId())
.map(UserProfile::getNickName)
.orElse(bondedRole.getAuthorizedBondedRole().getBondUserName())
).build())
).orElse(Stream.empty()))
.collect(Collectors.toList());
}
}
109 changes: 109 additions & 0 deletions apps/rest-api-app/src/main/java/bisq/rest_api/dto/AddressInfoDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.rest_api.dto;

import bisq.bonded_roles.BondedRoleType;
import bisq.common.network.Address;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;

@Schema(name = "AddressMeta")
@Getter
@EqualsAndHashCode
public final class AddressInfoDto {
private final String address;
private final String bondedRoleType;
private final String nickNameOrBondUserName;

public AddressInfoDto() {
this.address = null;
this.bondedRoleType = null;
this.nickNameOrBondUserName = null;
}

public AddressInfoDto(String address, String bondedRoleType, String nickNameOrBondUserName) {
this.address = address;
this.bondedRoleType = bondedRoleType;
this.nickNameOrBondUserName = nickNameOrBondUserName;
}

private AddressInfoDto(Builder builder) {
this.address = builder.address;
this.bondedRoleType = builder.bondedRoleType;
this.nickNameOrBondUserName = builder.nickNameOrBondUserName;
}

public static AddressInfoDto.Builder getBuilder() {
return new AddressInfoDto.Builder();
}

public static AddressInfoDto fromBuilder(AddressInfoDto.Builder builder) {
return builder.build();
}

public static final class Builder {
private String address;
private String bondedRoleType;
private String nickNameOrBondUserName;

private Builder() {
}

public Builder address(Address address) {
this.address = address.toString();
return this;
}

public Builder bondedRoleType(BondedRoleType bondedRoleType) {
this.bondedRoleType = bondedRoleType.name();
return this;
}

public Builder nickNameOrBondUserName(String nickNameOrBondUserName) {
this.nickNameOrBondUserName = nickNameOrBondUserName;
return this;
}

public AddressInfoDto build() {
validate();
return new AddressInfoDto(this);
}

private void validate() {
if (address == null || address.isEmpty()) {
throw new IllegalStateException("Member address must not be null or empty");
}
if (bondedRoleType == null || bondedRoleType.isEmpty()) {
throw new IllegalStateException("Member bondedRoleType must not be null or empty");
}
if (nickNameOrBondUserName == null || nickNameOrBondUserName.isEmpty()) {
throw new IllegalStateException("Member nickNameOrBondUserName must not be null or empty");
}
}
}

@Override
public String toString() {
return "AddressMetaDto{" +
"address='" + address + '\'' +
", bondedRoleType='" + bondedRoleType + '\'' +
", nickNameOrBondUserName='" + nickNameOrBondUserName + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,15 @@
import bisq.network.NetworkService;
import bisq.rest_api.JaxRsApplication;
import bisq.rest_api.RestApiApplicationService;
import bisq.rest_api.dto.AddressInfoDto;
import bisq.rest_api.dto.ReportDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
Expand Down Expand Up @@ -64,12 +62,12 @@ public ReportApi(@Context Application application) {
)}
)
@GET
@Path("get-address-list")
public List<String> getAddressList() {
@Path("get-addresses")
public List<String> getAddresses() {
try {
return applicationService.getAddressList();
return applicationService.getAddresses();
} catch (Exception e) {
throw new RuntimeException("Failed to get the node address list");
throw new RuntimeException("Failed to get the node address list.");
}
}

Expand All @@ -87,7 +85,7 @@ public ReportDto getReport(
@Parameter(description = "address from which we request the report")
@PathParam("address") String address) {
try {
return fetchReportForAddress(address).join();
return requestReportForAddress(address).join();
} catch (Exception e) {
throw new RuntimeException("Failed to get report for address: " + address);
}
Expand Down Expand Up @@ -115,15 +113,40 @@ public List<ReportDto> getReports(
}

List<CompletableFuture<ReportDto>> futures = addressList.stream()
.map(this::fetchReportForAddress)
.map(this::requestReportForAddress)
.toList();

CompletableFuture<List<ReportDto>> allFutures = CompletableFutureUtils.allOf(futures);

return allFutures.join();
}

private CompletableFuture<ReportDto> fetchReportForAddress(String addressString) {
@POST
@Path("get-address-infos")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(description = "Get address info for a set of host:port addresses")
@ApiResponse(responseCode = "200", description = "The set of address info (host, role type, nickname or bond name)",
content = {
@Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(implementation = String[][].class) // String[][] because each entry is String[]
)
})
public List<AddressInfoDto> getAddressInfos(
@Parameter(description = "Set of addresses in host:port format")
List<String> addresses) {
try {
log.info("Received request to get address infos for: {}", addresses);
List<AddressInfoDto> addressInfos = applicationService.getAddressInfos(addresses);
return addressInfos;
} catch (Exception e) {
log.error("Failed to get address infos for provided addresses: {}. Nested: {}", addresses, e.getMessage());
throw new RuntimeException("Failed to retrieve address infos.");
}
}

private CompletableFuture<ReportDto> requestReportForAddress(String addressString) {
try {
Address address = Address.fromFullAddress(addressString);
return networkService.requestReport(address)
Expand Down
Loading
Loading