Fixed issues relating to using a separate repository instance when determining the latest status of a resource.

This commit is contained in:
CalDescent 2023-05-13 19:20:18 +01:00
parent 633f73aa86
commit f5f82dc3f6
4 changed files with 66 additions and 59 deletions

View File

@ -3,6 +3,8 @@ package org.qortal.api.gateway.resource;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.qortal.api.ApiError;
import org.qortal.api.ApiExceptionFactory;
import org.qortal.api.Security; import org.qortal.api.Security;
import org.qortal.arbitrary.ArbitraryDataFile; import org.qortal.arbitrary.ArbitraryDataFile;
import org.qortal.arbitrary.ArbitraryDataFile.ResourceIdType; import org.qortal.arbitrary.ArbitraryDataFile.ResourceIdType;
@ -11,6 +13,9 @@ import org.qortal.arbitrary.ArbitraryDataRenderer;
import org.qortal.arbitrary.ArbitraryDataResource; import org.qortal.arbitrary.ArbitraryDataResource;
import org.qortal.arbitrary.misc.Service; import org.qortal.arbitrary.misc.Service;
import org.qortal.data.arbitrary.ArbitraryResourceStatus; import org.qortal.data.arbitrary.ArbitraryResourceStatus;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -31,30 +36,6 @@ public class GatewayResource {
@Context HttpServletResponse response; @Context HttpServletResponse response;
@Context ServletContext context; @Context ServletContext context;
/**
* We need to allow resource status checking (and building) via the gateway, as the node's API port
* may not be forwarded and will almost certainly not be authenticated. Since gateways allow for
* all resources to be loaded except those that are blocked, there is no need for authentication.
*/
@GET
@Path("/arbitrary/resource/status/{service}/{name}")
public ArbitraryResourceStatus getDefaultResourceStatus(@PathParam("service") Service service,
@PathParam("name") String name,
@QueryParam("build") Boolean build) {
return this.getStatus(service, name, null, build);
}
@GET
@Path("/arbitrary/resource/status/{service}/{name}/{identifier}")
public ArbitraryResourceStatus getResourceStatus(@PathParam("service") Service service,
@PathParam("name") String name,
@PathParam("identifier") String identifier,
@QueryParam("build") Boolean build) {
return this.getStatus(service, name, identifier, build);
}
private ArbitraryResourceStatus getStatus(Service service, String name, String identifier, Boolean build) { private ArbitraryResourceStatus getStatus(Service service, String name, String identifier, Boolean build) {
// If "build=true" has been specified in the query string, build the resource before returning its status // If "build=true" has been specified in the query string, build the resource before returning its status
@ -69,8 +50,13 @@ public class GatewayResource {
} }
} }
try (final Repository repository = RepositoryManager.getRepository()) {
ArbitraryDataResource resource = new ArbitraryDataResource(name, ResourceIdType.NAME, service, identifier); ArbitraryDataResource resource = new ArbitraryDataResource(name, ResourceIdType.NAME, service, identifier);
return resource.getStatus(); return resource.getStatus(repository);
} catch (DataException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
}
} }

View File

@ -531,8 +531,14 @@ public class ArbitraryResource {
@PathParam("identifier") String identifier) { @PathParam("identifier") String identifier) {
Security.checkApiCallAllowed(request); Security.checkApiCallAllowed(request);
try (final Repository repository = RepositoryManager.getRepository()) {
ArbitraryDataResource resource = new ArbitraryDataResource(name, ResourceIdType.NAME, service, identifier); ArbitraryDataResource resource = new ArbitraryDataResource(name, ResourceIdType.NAME, service, identifier);
return resource.delete(false); return resource.delete(repository, false);
} catch (DataException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
}
} }
@POST @POST

View File

@ -59,28 +59,34 @@ public class ArbitraryDataResource {
} }
public ArbitraryResourceStatus getStatusAndUpdateCache(boolean updateCache) { public ArbitraryResourceStatus getStatusAndUpdateCache(boolean updateCache) {
ArbitraryResourceStatus arbitraryResourceStatus = this.getStatus(); ArbitraryResourceStatus arbitraryResourceStatus = null;
try (final Repository repository = RepositoryManager.getRepository()) {
arbitraryResourceStatus = this.getStatus(repository);
if (updateCache) { if (updateCache) {
// Update cache if possible // Update cache if possible
ArbitraryResourceStatus.Status status = arbitraryResourceStatus != null ? arbitraryResourceStatus.getStatus() : null; ArbitraryResourceStatus.Status status = arbitraryResourceStatus != null ? arbitraryResourceStatus.getStatus() : null;
ArbitraryResourceData arbitraryResourceData = new ArbitraryResourceData(this.service, this.resourceId, this.identifier); ArbitraryResourceData arbitraryResourceData = new ArbitraryResourceData(this.service, this.resourceId, this.identifier);
try (final Repository repository = RepositoryManager.getRepository()) {
repository.getArbitraryRepository().setStatus(arbitraryResourceData, status); repository.getArbitraryRepository().setStatus(arbitraryResourceData, status);
repository.saveChanges(); repository.saveChanges();
} catch (DataException e) {
LOGGER.info("Unable to update status cache for resource {}: {}", arbitraryResourceData, e.getMessage());
} }
} catch (DataException e) {
LOGGER.info("Unable to update status cache for resource {}: {}", this.toString(), e.getMessage());
} }
return arbitraryResourceStatus; return arbitraryResourceStatus;
} }
public ArbitraryResourceStatus getStatus() { /**
* Get current status of resource
*
* @param repository
* @return the resource's status
*/
public ArbitraryResourceStatus getStatus(Repository repository) {
// Calculate the chunk counts // Calculate the chunk counts
this.calculateChunkCounts(); this.calculateChunkCounts(repository);
if (!this.exists) { if (!this.exists) {
return new ArbitraryResourceStatus(Status.NOT_PUBLISHED, this.localChunkCount, this.totalChunkCount); return new ArbitraryResourceStatus(Status.NOT_PUBLISHED, this.localChunkCount, this.totalChunkCount);
@ -111,11 +117,11 @@ public class ArbitraryDataResource {
} }
// Check if we have all data locally for this resource // Check if we have all data locally for this resource
if (!this.allFilesDownloaded()) { if (!this.allFilesDownloaded(repository)) {
if (this.isDownloading()) { if (this.isDownloading(repository)) {
return new ArbitraryResourceStatus(Status.DOWNLOADING, this.localChunkCount, this.totalChunkCount); return new ArbitraryResourceStatus(Status.DOWNLOADING, this.localChunkCount, this.totalChunkCount);
} }
else if (this.isDataPotentiallyAvailable()) { else if (this.isDataPotentiallyAvailable(repository)) {
return new ArbitraryResourceStatus(Status.PUBLISHED, this.localChunkCount, this.totalChunkCount); return new ArbitraryResourceStatus(Status.PUBLISHED, this.localChunkCount, this.totalChunkCount);
} }
return new ArbitraryResourceStatus(Status.MISSING_DATA, this.localChunkCount, this.totalChunkCount); return new ArbitraryResourceStatus(Status.MISSING_DATA, this.localChunkCount, this.totalChunkCount);
@ -157,9 +163,9 @@ public class ArbitraryDataResource {
return null; return null;
} }
public boolean delete(boolean deleteMetadata) { public boolean delete(Repository repository, boolean deleteMetadata) {
try { try {
this.fetchTransactions(); this.fetchTransactions(repository);
if (this.transactions == null) { if (this.transactions == null) {
return false; return false;
} }
@ -208,7 +214,7 @@ public class ArbitraryDataResource {
} }
} }
private boolean allFilesDownloaded() { private boolean allFilesDownloaded(Repository repository) {
// Use chunk counts to speed things up if we can // Use chunk counts to speed things up if we can
if (this.localChunkCount != null && this.totalChunkCount != null && if (this.localChunkCount != null && this.totalChunkCount != null &&
this.localChunkCount >= this.totalChunkCount) { this.localChunkCount >= this.totalChunkCount) {
@ -216,7 +222,7 @@ public class ArbitraryDataResource {
} }
try { try {
this.fetchTransactions(); this.fetchTransactions(repository);
if (this.transactions == null) { if (this.transactions == null) {
return false; return false;
} }
@ -236,9 +242,14 @@ public class ArbitraryDataResource {
} }
} }
private void calculateChunkCounts() { /**
* Calculate chunk counts of a resource
*
* @param repository optional - a new instance will be created if null
*/
private void calculateChunkCounts(Repository repository) {
try { try {
this.fetchTransactions(); this.fetchTransactions(repository);
if (this.transactions == null) { if (this.transactions == null) {
this.exists = false; this.exists = false;
this.localChunkCount = 0; this.localChunkCount = 0;
@ -263,9 +274,9 @@ public class ArbitraryDataResource {
} catch (DataException e) {} } catch (DataException e) {}
} }
private boolean isRateLimited() { private boolean isRateLimited(Repository repository) {
try { try {
this.fetchTransactions(); this.fetchTransactions(repository);
if (this.transactions == null) { if (this.transactions == null) {
return true; return true;
} }
@ -289,9 +300,9 @@ public class ArbitraryDataResource {
* This is only used to give an indication to the user of progress * This is only used to give an indication to the user of progress
* @return - whether data might be available on the network * @return - whether data might be available on the network
*/ */
private boolean isDataPotentiallyAvailable() { private boolean isDataPotentiallyAvailable(Repository repository) {
try { try {
this.fetchTransactions(); this.fetchTransactions(repository);
if (this.transactions == null) { if (this.transactions == null) {
return false; return false;
} }
@ -324,9 +335,9 @@ public class ArbitraryDataResource {
* This is only used to give an indication to the user of progress * This is only used to give an indication to the user of progress
* @return - whether we are trying to download the resource * @return - whether we are trying to download the resource
*/ */
private boolean isDownloading() { private boolean isDownloading(Repository repository) {
try { try {
this.fetchTransactions(); this.fetchTransactions(repository);
if (this.transactions == null) { if (this.transactions == null) {
return false; return false;
} }
@ -357,15 +368,19 @@ public class ArbitraryDataResource {
} }
/**
private void fetchTransactions() throws DataException { * Fetch relevant arbitrary transactions for resource
*
* @param repository
* @throws DataException
*/
private void fetchTransactions(Repository repository) throws DataException {
if (this.transactions != null && !this.transactions.isEmpty()) { if (this.transactions != null && !this.transactions.isEmpty()) {
// Already fetched // Already fetched
return; return;
} }
try (final Repository repository = RepositoryManager.getRepository()) { try {
// Get the most recent PUT // Get the most recent PUT
ArbitraryTransactionData latestPut = repository.getArbitraryRepository() ArbitraryTransactionData latestPut = repository.getArbitraryRepository()
.getLatestTransaction(this.resourceId, this.service, ArbitraryTransactionData.Method.PUT, this.identifier); .getLatestTransaction(this.resourceId, this.service, ArbitraryTransactionData.Method.PUT, this.identifier);

View File

@ -407,7 +407,7 @@ public class ArbitraryTransaction extends Transaction {
// Update status // Update status
ArbitraryDataResource resource = new ArbitraryDataResource(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier); ArbitraryDataResource resource = new ArbitraryDataResource(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
ArbitraryResourceStatus arbitraryResourceStatus = resource.getStatus(); ArbitraryResourceStatus arbitraryResourceStatus = resource.getStatus(repository);
ArbitraryResourceStatus.Status status = arbitraryResourceStatus != null ? arbitraryResourceStatus.getStatus() : null; ArbitraryResourceStatus.Status status = arbitraryResourceStatus != null ? arbitraryResourceStatus.getStatus() : null;
repository.getArbitraryRepository().setStatus(arbitraryResourceData, status); repository.getArbitraryRepository().setStatus(arbitraryResourceData, status);
} }