Skip to content

Commit

Permalink
Merge pull request #3000 from bsc7/feature/2634/Simple_HTML_NodeMonitor
Browse files Browse the repository at this point in the history
Feature/2634/simple html node monitor
  • Loading branch information
HenrikJannsen authored Nov 19, 2024
2 parents 7bc13b2 + e069f38 commit 28119b2
Show file tree
Hide file tree
Showing 30 changed files with 2,092 additions and 778 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@
import bisq.account.AccountService;
import bisq.bisq_easy.BisqEasyService;
import bisq.bonded_roles.BondedRolesService;
import bisq.bonded_roles.bonded_role.AuthorizedBondedRole;
import bisq.bonded_roles.bonded_role.BondedRole;
import bisq.chat.ChatService;
import bisq.common.application.Service;
import bisq.common.network.Address;
import bisq.common.network.TransportType;
import bisq.common.observable.Observable;
import bisq.common.platform.OS;
import bisq.common.util.CompletableFutureUtils;
Expand All @@ -51,13 +47,9 @@
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.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.concurrent.CompletableFuture.supplyAsync;
Expand Down Expand Up @@ -102,7 +94,7 @@ public enum State {
public RestApiApplicationService(String[] args) {
super("rest_api", args);

restApiConfig= getConfig("restApi");
restApiConfig = getConfig("restApi");

securityService = new SecurityService(persistenceService, SecurityService.Config.from(getConfig("security")));
com.typesafe.config.Config bitcoinWalletConfig = getConfig("bitcoinWallet");
Expand Down Expand Up @@ -274,7 +266,6 @@ public KeyBundleService getKeyBundleService() {
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 @@ -300,29 +291,4 @@ private Optional<OsSpecificNotificationService> findSystemNotificationDelegate()
return Optional.empty();
}
}

public List<String> getAddressList() {
Set<Address> bannedAddresses = bondedRolesService.getAuthorizedBondedRolesService().getBondedRoles().stream()
.filter(BondedRole::isBanned)
.map(BondedRole::getAuthorizedBondedRole)
.map(AuthorizedBondedRole::getAddressByTransportTypeMap)
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(map -> map.values().stream())
.collect(Collectors.toSet());
Map<TransportType, Set<Address>> seedAddressesByTransport = networkService.getSeedAddressesByTransportFromConfig();
Set<TransportType> supportedTransportTypes = networkService.getSupportedTransportTypes();
List<String> addresslist = 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");

return addresslist;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public RestApiResourceConfig(RestApiApplicationService applicationService, Strin
protected void configure() {
bind(new SwaggerResolution(baseUrl)).to(SwaggerResolution.class);
bind(new UserIdentityRestApi(applicationService.getUserService().getUserIdentityService())).to(UserIdentityRestApi.class);
bind(new ReportRestApi(applicationService.getNetworkService(), applicationService.getBondedRolesService())).to(ReportRestApi.class);
bind(new ReportRestApi(applicationService.getNetworkService(), applicationService.getBondedRolesService(), applicationService.getUserService())).to(ReportRestApi.class);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.report;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Getter
@EqualsAndHashCode
@ToString
@Schema(name = "AddressDetails")
public final class AddressDetails {
private final String address;
private final String bondedRoleType;
private final String nickNameOrBondUserName;

public AddressDetails(String address, String bondedRoleType, String nickNameOrBondUserName) {
this.address = address;
this.bondedRoleType = bondedRoleType;
this.nickNameOrBondUserName = nickNameOrBondUserName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@
import bisq.common.util.CompletableFutureUtils;
import bisq.network.NetworkService;
import bisq.network.p2p.services.reporting.Report;
import bisq.user.UserService;
import bisq.user.profile.UserProfile;
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.MediaType;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -45,6 +44,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Path("/report")
Expand All @@ -53,10 +53,14 @@
public class ReportRestApi {
private final NetworkService networkService;
private final BondedRolesService bondedRolesService;
private final UserService userService;

public ReportRestApi(NetworkService networkService, BondedRolesService bondedRolesService) {
public ReportRestApi(NetworkService networkService,
BondedRolesService bondedRolesService,
UserService userService) {
this.networkService = networkService;
this.bondedRolesService = bondedRolesService;
this.userService = userService;
}

@Operation(description = "Get a address list of seed and oracle nodes")
Expand All @@ -67,7 +71,7 @@ public ReportRestApi(NetworkService networkService, BondedRolesService bondedRol
)}
)
@GET
@Path("address-list")
@Path("addresses")
public List<String> getAddressList() {
try {
Set<Address> bannedAddresses = bondedRolesService.getAuthorizedBondedRolesService().getBondedRoles().stream()
Expand Down Expand Up @@ -145,4 +149,38 @@ public List<Report> getReports(
throw new RestApiException(e);
}
}

@GET
@Path("/addresses/details")
@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 = AddressDetails[].class)))
public List<AddressDetails> getAddressDetailsDto(
@QueryParam("addresses") String addresses) { // Comma-separated list
try {
log.info("Received request to get address infos for: {}", addresses);
List<String> addressList = CollectionUtil.streamFromCsv(addresses).toList();
return getAddressDetailsProtobufs(addressList);
} catch (Exception e) {
throw new RestApiException(e);
}
}

public List<AddressDetails> getAddressDetailsProtobufs(List<String> addressList) {
Set<BondedRole> bondedRoles = bondedRolesService.getAuthorizedBondedRolesService().getBondedRoles();
return bondedRoles.stream()
.flatMap(bondedRole -> bondedRole.getAuthorizedBondedRole().getAddressByTransportTypeMap()
.map(addressMap -> addressMap.entrySet().stream()
.filter(entry -> addressList.contains(entry.getValue().toString())) // Nutze addressList
.map(entry -> new AddressDetails(
entry.getValue().toString(),
bondedRole.getAuthorizedBondedRole().getBondedRoleType().name(),
userService.getUserProfileService()
.findUserProfile(bondedRole.getAuthorizedBondedRole().getProfileId())
.map(UserProfile::getNickName)
.orElse(bondedRole.getAuthorizedBondedRole().getBondUserName())
))
).orElse(Stream.empty()))
.collect(Collectors.toList());
}
}
54 changes: 41 additions & 13 deletions apps/rest-api-app/src/main/resources/node-monitor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,54 @@ The application provides a user interface to input a list of hosts and ports, re
The project is organized into different modules to ensure a clear separation of concerns and ease of maintenance. Each part of the application has a dedicated file or directory, as outlined below:

```
projekt-root/
project-root/
├── index.html # Main HTML file that defines the application's structure
├── index.html # Main HTML file defining the application's structure
├── index.js # Main JavaScript file for initializing the application
├── README.md # Project README file with documentation
├── README.md # Project documentation
├── js/ # JavaScript files organized by functionality
│ ├── constants.js # Global constants used throughout the application
│ ├── controllers/ # Application controllers
│ │ └── appController.js # Main application controller for handling user input and API calls
│ ├── services/ # Application services for data and storage management
│ │ ├── dataService.js # Service handling API requests and data retrieval
│ │ └── storageService.js # Service for handling local storage interactions
│ ├── Constants.js # Global constants used throughout the application
│ ├── controllers/ # Controllers for managing application logic
│ │ ├── AppController.js # Main controller for user interaction and API calls
│ │ ├── ReportController.js # Controller for handling reports
│ │ └── ReportDiffsController.js # Controller for report comparison and analysis
│ ├── errors.js # Error handling logic
│ ├── services/ # Services for data and storage management
│ │ ├── DataService.js # Service for managing API requests and data retrieval
│ │ └── StorageService.js # Service for handling local storage
│ ├── utils/ # Utility functions
│ │ ├── DOMUtils.js # Functions for DOM manipulation
│ │ ├── FormatUtils.js # Formatting utilities
│ │ └── KeyUtils.js # Utilities for key management
│ └── views/ # View components for different sections
│ ├── settingsView.js # View handling settings display and input
│ └── reportView.js # View managing the display of node reports
│ ├── ReportView.js # View for displaying reports
│ └── SettingsView.js # View for handling settings
└── styles/ # Directory containing CSS files for styling
├── resources/ # Resources such as images and icons
│ └── Bisq2_icon.svg # Application icon
└── styles/ # CSS files for styling
├── global.css # Global styles, typography, colors, and basic element styling
├── page-layout.css # Layout and positioning of main areas, responsive styling
├── page-layout.css # Layout and positioning of main areas, responsive styles
├── reportView.css # Styling for the report view section
└── settingsView.css # Styling for the settings view section
```

## Description

Here’s a revised version integrating your requirements:

ReportDiffs enables comparison across all reports and highlights deviations.
It provides average values and supports three configurable thresholds, which
can be adjusted in the settings. Threshold violations are visually marked,
with a hover showing the specific average value and the extent of the deviation.
For subtables, the background of the button toggling the detail view is marked
based on the highest exceeded threshold.

For certain metrics, deviations are highlighted based on fixed reference values
rather than averages:
numConnections: Marked as critical if below 10, highlighting downward deviations.
memoryUsed: Marked as critical if exceeding 500 MB, highlighting upward deviations.
numThreads: Marked as critical if exceeding 70, highlighting upward deviations.
nodeLoad: Marked as critical if exceeding 0.4, highlighting upward deviations.
Loading

0 comments on commit 28119b2

Please sign in to comment.