item manager: add batch item price lookup
This commit is contained in:
@@ -29,6 +29,10 @@ import com.google.common.cache.CacheLoader;
|
|||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -36,6 +40,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import static net.runelite.api.Constants.CLIENT_DEFAULT_ZOOM;
|
import static net.runelite.api.Constants.CLIENT_DEFAULT_ZOOM;
|
||||||
import net.runelite.api.ItemComposition;
|
import net.runelite.api.ItemComposition;
|
||||||
@@ -45,6 +50,7 @@ import net.runelite.http.api.item.ItemPrice;
|
|||||||
import net.runelite.http.api.item.SearchResult;
|
import net.runelite.http.api.item.SearchResult;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@Slf4j
|
||||||
public class ItemManager
|
public class ItemManager
|
||||||
{
|
{
|
||||||
@Value
|
@Value
|
||||||
@@ -58,17 +64,19 @@ public class ItemManager
|
|||||||
/**
|
/**
|
||||||
* not yet looked up
|
* not yet looked up
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static final ItemPrice EMPTY = new ItemPrice();
|
static final ItemPrice EMPTY = new ItemPrice();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* has no price
|
* has no price
|
||||||
*/
|
*/
|
||||||
static final ItemPrice NONE = new ItemPrice();
|
static final ItemPrice NONE = new ItemPrice();
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
|
private final ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
private final ItemClient itemClient = new ItemClient();
|
private final ItemClient itemClient = new ItemClient();
|
||||||
private final LoadingCache<String, SearchResult> itemSearches;
|
private final LoadingCache<String, SearchResult> itemSearches;
|
||||||
private final LoadingCache<Integer, ItemPrice> itemPrices;
|
private final LoadingCache<Integer, ItemPrice> itemPriceCache;
|
||||||
private final LoadingCache<ImageKey, BufferedImage> itemImages;
|
private final LoadingCache<ImageKey, BufferedImage> itemImages;
|
||||||
private final LoadingCache<Integer, ItemComposition> itemCompositions;
|
private final LoadingCache<Integer, ItemComposition> itemCompositions;
|
||||||
|
|
||||||
@@ -76,8 +84,10 @@ public class ItemManager
|
|||||||
public ItemManager(@Nullable Client client, ScheduledExecutorService executor)
|
public ItemManager(@Nullable Client client, ScheduledExecutorService executor)
|
||||||
{
|
{
|
||||||
this.client = client;
|
this.client = client;
|
||||||
itemPrices = CacheBuilder.newBuilder()
|
this.scheduledExecutorService = executor;
|
||||||
.maximumSize(512L)
|
|
||||||
|
itemPriceCache = CacheBuilder.newBuilder()
|
||||||
|
.maximumSize(1024L)
|
||||||
.expireAfterAccess(1, TimeUnit.HOURS)
|
.expireAfterAccess(1, TimeUnit.HOURS)
|
||||||
.build(new ItemPriceLoader(executor, itemClient));
|
.build(new ItemPriceLoader(executor, itemClient));
|
||||||
|
|
||||||
@@ -126,16 +136,74 @@ public class ItemManager
|
|||||||
*/
|
*/
|
||||||
public ItemPrice getItemPriceAsync(int itemId)
|
public ItemPrice getItemPriceAsync(int itemId)
|
||||||
{
|
{
|
||||||
ItemPrice itemPrice = itemPrices.getIfPresent(itemId);
|
ItemPrice itemPrice = itemPriceCache.getIfPresent(itemId);
|
||||||
if (itemPrice != null && itemPrice != EMPTY)
|
if (itemPrice != null && itemPrice != EMPTY)
|
||||||
{
|
{
|
||||||
return itemPrice == NONE ? null : itemPrice;
|
return itemPrice == NONE ? null : itemPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemPrices.refresh(itemId);
|
itemPriceCache.refresh(itemId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up bulk item prices asynchronously
|
||||||
|
*
|
||||||
|
* @param itemIds array of item Ids
|
||||||
|
* @return a future called with the looked up prices
|
||||||
|
*/
|
||||||
|
public CompletableFuture<ItemPrice[]> getItemPriceBatch(List<Integer> itemIds)
|
||||||
|
{
|
||||||
|
final List<Integer> lookup = new ArrayList<>();
|
||||||
|
final List<ItemPrice> existing = new ArrayList<>();
|
||||||
|
for (int itemId : itemIds)
|
||||||
|
{
|
||||||
|
ItemPrice itemPrice = itemPriceCache.getIfPresent(itemId);
|
||||||
|
if (itemPrice != null)
|
||||||
|
{
|
||||||
|
existing.add(itemPrice);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lookup.add(itemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All cached?
|
||||||
|
if (lookup.isEmpty())
|
||||||
|
{
|
||||||
|
return CompletableFuture.completedFuture(existing.toArray(new ItemPrice[existing.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompletableFuture<ItemPrice[]> future = new CompletableFuture<>();
|
||||||
|
scheduledExecutorService.execute(() ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Do a query for the items not in the cache
|
||||||
|
ItemPrice[] itemPrices = itemClient.lookupItemPrice(lookup.toArray(new Integer[lookup.size()]));
|
||||||
|
if (itemPrices != null)
|
||||||
|
{
|
||||||
|
for (int itemId : lookup)
|
||||||
|
{
|
||||||
|
itemPriceCache.put(itemId, NONE);
|
||||||
|
}
|
||||||
|
for (ItemPrice itemPrice : itemPrices)
|
||||||
|
{
|
||||||
|
itemPriceCache.put(itemPrice.getItem().getId(), itemPrice);
|
||||||
|
}
|
||||||
|
// Append these to the already cached items
|
||||||
|
Arrays.stream(itemPrices).forEach(existing::add);
|
||||||
|
}
|
||||||
|
future.complete(existing.toArray(new ItemPrice[existing.size()]));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
future.completeExceptionally(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up an item's price synchronously
|
* Look up an item's price synchronously
|
||||||
*
|
*
|
||||||
@@ -145,7 +213,7 @@ public class ItemManager
|
|||||||
*/
|
*/
|
||||||
public ItemPrice getItemPrice(int itemId) throws IOException
|
public ItemPrice getItemPrice(int itemId) throws IOException
|
||||||
{
|
{
|
||||||
ItemPrice itemPrice = itemPrices.getIfPresent(itemId);
|
ItemPrice itemPrice = itemPriceCache.getIfPresent(itemId);
|
||||||
if (itemPrice != null && itemPrice != EMPTY)
|
if (itemPrice != null && itemPrice != EMPTY)
|
||||||
{
|
{
|
||||||
return itemPrice == NONE ? null : itemPrice;
|
return itemPrice == NONE ? null : itemPrice;
|
||||||
@@ -154,11 +222,11 @@ public class ItemManager
|
|||||||
itemPrice = itemClient.lookupItemPrice(itemId);
|
itemPrice = itemClient.lookupItemPrice(itemId);
|
||||||
if (itemPrice == null)
|
if (itemPrice == null)
|
||||||
{
|
{
|
||||||
itemPrices.put(itemId, NONE);
|
itemPriceCache.put(itemId, NONE);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemPrices.put(itemId, itemPrice);
|
itemPriceCache.put(itemId, itemPrice);
|
||||||
return itemPrice;
|
return itemPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user