diff --git a/src/main/java/org/qortal/api/resource/AddressesResource.java b/src/main/java/org/qortal/api/resource/AddressesResource.java index 20e4da5a..4dfa52d6 100644 --- a/src/main/java/org/qortal/api/resource/AddressesResource.java +++ b/src/main/java/org/qortal/api/resource/AddressesResource.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -38,6 +39,7 @@ import org.qortal.crypto.Crypto; import org.qortal.data.account.AccountData; import org.qortal.data.account.RewardShareData; import org.qortal.data.network.OnlineAccountData; +import org.qortal.data.network.OnlineAccountLevel; import org.qortal.data.transaction.PublicizeTransactionData; import org.qortal.data.transaction.RewardShareTransactionData; import org.qortal.data.transaction.TransactionData; @@ -180,6 +182,66 @@ public class AddressesResource { } } + @GET + @Path("/online/levels") + @Operation( + summary = "Return currently 'online' accounts counts, grouped by level", + responses = { + @ApiResponse( + description = "online accounts", + content = @Content(mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema(schema = @Schema(implementation = ApiOnlineAccount.class))) + ) + } + ) + @ApiErrors({ApiError.PUBLIC_KEY_NOT_FOUND, ApiError.REPOSITORY_ISSUE}) + public List getOnlineAccountsByLevel() { + List onlineAccounts = Controller.getInstance().getOnlineAccounts(); + + try (final Repository repository = RepositoryManager.getRepository()) { + List onlineAccountLevels = new ArrayList<>(); + + for (OnlineAccountData onlineAccountData : onlineAccounts) { + try { + final int minterLevel = Account.getRewardShareEffectiveMintingLevel(repository, onlineAccountData.getPublicKey()); + + OnlineAccountLevel onlineAccountLevel = onlineAccountLevels.stream() + .filter(a -> a.getLevel() == minterLevel) + .findFirst().orElse(null); + + // Note: I don't think we can use the level as the List index here because there will be gaps. + // So we are forced to manually look up the existing item each time. + // There's probably a nice shorthand java way of doing this, but this approach gets the same result. + + if (onlineAccountLevel == null) { + // No entry exists for this level yet, so create one + onlineAccountLevel = new OnlineAccountLevel(minterLevel, 1); + onlineAccountLevels.add(onlineAccountLevel); + } + else { + // Already exists - so increment the count + int existingCount = onlineAccountLevel.getCount(); + onlineAccountLevel.setCount(++existingCount); + + // Then replace the existing item + int index = onlineAccountLevels.indexOf(onlineAccountLevel); + onlineAccountLevels.set(index, onlineAccountLevel); + } + + } catch (DataException e) { + continue; + } + } + + // Sort by level + onlineAccountLevels.sort(Comparator.comparingInt(OnlineAccountLevel::getLevel)); + + return onlineAccountLevels; + + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + @GET @Path("/balance/{address}") @Operation( diff --git a/src/main/java/org/qortal/data/network/OnlineAccountLevel.java b/src/main/java/org/qortal/data/network/OnlineAccountLevel.java new file mode 100644 index 00000000..0589b239 --- /dev/null +++ b/src/main/java/org/qortal/data/network/OnlineAccountLevel.java @@ -0,0 +1,55 @@ +package org.qortal.data.network; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + + +// All properties to be converted to JSON via JAXB +@XmlAccessorType(XmlAccessType.FIELD) +public class OnlineAccountLevel { + + protected int level; + protected int count; + + // Constructors + + // necessary for JAXB serialization + protected OnlineAccountLevel() { + } + + public OnlineAccountLevel(int level, int count) { + this.level = level; + this.count = count; + } + + public int getLevel() { + return this.level; + } + + public int getCount() { + return this.count; + } + + public void setCount(int count) { + this.count = count; + } + + + // Comparison + + @Override + public boolean equals(Object other) { + if (other == this) + return true; + + if (!(other instanceof OnlineAccountLevel)) + return false; + + OnlineAccountLevel otherOnlineAccountData = (OnlineAccountLevel) other; + + if (otherOnlineAccountData.level != this.level) + return false; + + return true; + } +}