diff --git a/src/main/java/org/qortal/controller/Controller.java b/src/main/java/org/qortal/controller/Controller.java index cbb91e66..f5ff5763 100644 --- a/src/main/java/org/qortal/controller/Controller.java +++ b/src/main/java/org/qortal/controller/Controller.java @@ -478,6 +478,7 @@ public class Controller extends Thread { ArbitraryDataBuildManager.getInstance().start(); ArbitraryDataCleanupManager.getInstance().start(); ArbitraryDataStorageManager.getInstance().start(); + ArbitraryDataRenderManager.getInstance().start(); // Auto-update service? if (Settings.getInstance().isAutoUpdateEnabled()) { @@ -1069,6 +1070,7 @@ public class Controller extends Thread { ArbitraryDataBuildManager.getInstance().shutdown(); ArbitraryDataCleanupManager.getInstance().shutdown(); ArbitraryDataStorageManager.getInstance().shutdown(); + ArbitraryDataRenderManager.getInstance().shutdown(); if (blockMinter != null) { LOGGER.info("Shutting down block minter"); diff --git a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataRenderManager.java b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataRenderManager.java index ca98c484..483ab92f 100644 --- a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataRenderManager.java +++ b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataRenderManager.java @@ -1,20 +1,22 @@ package org.qortal.controller.arbitrary; import org.qortal.arbitrary.ArbitraryDataResource; +import org.qortal.utils.NTP; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; -public class ArbitraryDataRenderManager { +public class ArbitraryDataRenderManager extends Thread { private static ArbitraryDataRenderManager instance; + private volatile boolean isStopping = false; /** - * List to keep track of authorized resources for rendering. + * Map to keep track of authorized resources for rendering. + * Keyed by resource ID, with the authorization time as the value. */ - private List authorizedResources = Collections.synchronizedList(new ArrayList<>()); + private Map authorizedResources = Collections.synchronizedMap(new HashMap<>()); + + private static long AUTHORIZATION_TIMEOUT = 60 * 60 * 1000L; // 1 hour public ArbitraryDataRenderManager() { @@ -28,17 +30,46 @@ public class ArbitraryDataRenderManager { return instance; } + @Override + public void run() { + Thread.currentThread().setName("Arbitrary Data Manager"); + + try { + while (!isStopping) { + Thread.sleep(60000); + + Long now = NTP.getTime(); + this.cleanup(now); + } + } catch (InterruptedException e) { + // Fall-through to exit thread... + } + } + + public void shutdown() { + isStopping = true; + this.interrupt(); + } + + public void cleanup(Long now) { + if (now == null) { + return; + } + final long minimumTimestamp = now - AUTHORIZATION_TIMEOUT; + this.authorizedResources.entrySet().removeIf(entry -> entry.getValue() == null || entry.getValue() < minimumTimestamp); + } + public boolean isAuthorized(ArbitraryDataResource resource) { ArbitraryDataResource broadResource = new ArbitraryDataResource(resource.getResourceId(), null, null, null); - for (ArbitraryDataResource authorizedResource : this.authorizedResources) { - if (authorizedResource != null && resource != null) { + for (String authorizedResourceKey : this.authorizedResources.keySet()) { + if (authorizedResourceKey != null && resource != null) { // Check for exact match - if (Objects.equals(authorizedResource.getUniqueKey(), resource.getUniqueKey())) { + if (Objects.equals(authorizedResourceKey, resource.getUniqueKey())) { return true; } // Check for a broad authorization (which applies to all services and identifiers under an authorized name) - if (Objects.equals(authorizedResource.getUniqueKey(), broadResource.getUniqueKey())) { + if (Objects.equals(authorizedResourceKey, broadResource.getUniqueKey())) { return true; } } @@ -48,7 +79,7 @@ public class ArbitraryDataRenderManager { public void addToAuthorizedResources(ArbitraryDataResource resource) { if (!this.isAuthorized(resource)) { - this.authorizedResources.add(resource); + this.authorizedResources.put(resource.getUniqueKey(), NTP.getTime()); } }