ge plugin: submit partially completed trades

This commit is contained in:
Adam
2020-05-29 13:49:38 -04:00
parent 6d46bb09c4
commit 17d6921a4a
4 changed files with 258 additions and 31 deletions

View File

@@ -30,7 +30,10 @@ import lombok.Data;
public class GrandExchangeTrade
{
private boolean buy;
private boolean cancel;
private int itemId;
private int quantity;
private int total;
private int price;
private int offer;
}

View File

@@ -29,6 +29,7 @@ import java.util.Collection;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.RuneLiteAPI;
import net.runelite.http.api.ge.GrandExchangeTrade;
import net.runelite.http.service.account.AuthFilter;
import net.runelite.http.service.account.beans.SessionEntry;
@@ -58,14 +59,23 @@ public class GrandExchangeController
@PostMapping
public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException
{
SessionEntry session = authFilter.handle(request, response);
if (session == null)
SessionEntry session = null;
if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null)
{
return;
session = authFilter.handle(request, response);
if (session == null)
{
// error is set here on the response, so we shouldn't continue
return;
}
}
Integer userId = session == null ? null : session.getUser();
grandExchangeService.add(session.getUser(), grandExchangeTrade);
// We don't keep track of pending trades in the web UI, so only add cancelled or completed trades
if (userId != null && (grandExchangeTrade.isCancel() || grandExchangeTrade.getQuantity() == grandExchangeTrade.getTotal()))
{
grandExchangeService.add(userId, grandExchangeTrade);
}
}
@GetMapping

View File

@@ -371,39 +371,88 @@ public class GrandExchangePlugin extends Plugin
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
submitTrades(slot, offer);
submitTrade(slot, offer);
updateConfig(slot, offer);
}
private void submitTrades(int slot, GrandExchangeOffer offer)
@VisibleForTesting
void submitTrade(int slot, GrandExchangeOffer offer)
{
if (offer.getState() != GrandExchangeOfferState.BOUGHT && offer.getState() != GrandExchangeOfferState.SOLD &&
offer.getState() != GrandExchangeOfferState.CANCELLED_BUY && offer.getState() != GrandExchangeOfferState.CANCELLED_SELL)
{
return;
}
GrandExchangeOfferState state = offer.getState();
// Cancelled offers may have been cancelled before buying/selling any items
if (offer.getQuantitySold() == 0)
if (state != GrandExchangeOfferState.CANCELLED_BUY && state != GrandExchangeOfferState.CANCELLED_SELL && state != GrandExchangeOfferState.BUYING && state != GrandExchangeOfferState.SELLING)
{
return;
}
SavedOffer savedOffer = getOffer(slot);
if (!shouldUpdate(savedOffer, offer))
if (savedOffer == null && (state == GrandExchangeOfferState.BUYING || state == GrandExchangeOfferState.SELLING) && offer.getQuantitySold() == 0)
{
// new offer
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
grandExchangeTrade.setBuy(state == GrandExchangeOfferState.BUYING);
grandExchangeTrade.setItemId(offer.getItemId());
grandExchangeTrade.setQuantity(0);
grandExchangeTrade.setTotal(offer.getTotalQuantity());
grandExchangeTrade.setPrice(0);
grandExchangeTrade.setOffer(offer.getPrice());
log.debug("Submitting new trade: {}", grandExchangeTrade);
grandExchangeClient.submit(grandExchangeTrade);
return;
}
if (savedOffer == null || savedOffer.getItemId() != offer.getItemId() || savedOffer.getPrice() != offer.getPrice() || savedOffer.getTotalQuantity() != offer.getTotalQuantity())
{
// desync
return;
}
if (savedOffer.getState() == offer.getState() && savedOffer.getQuantitySold() == offer.getQuantitySold())
{
// no change
return;
}
if (state == GrandExchangeOfferState.CANCELLED_BUY || state == GrandExchangeOfferState.CANCELLED_SELL)
{
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
grandExchangeTrade.setBuy(state == GrandExchangeOfferState.CANCELLED_BUY);
grandExchangeTrade.setCancel(true);
grandExchangeTrade.setItemId(offer.getItemId());
grandExchangeTrade.setQuantity(offer.getQuantitySold());
grandExchangeTrade.setTotal(offer.getTotalQuantity());
grandExchangeTrade.setPrice(offer.getQuantitySold() > 0 ? offer.getSpent() / offer.getQuantitySold() : 0);
grandExchangeTrade.setOffer(offer.getPrice());
log.debug("Submitting cancelled: {}", grandExchangeTrade);
grandExchangeClient.submit(grandExchangeTrade);
return;
}
final int qty = offer.getQuantitySold() - savedOffer.getQuantitySold();
if (qty <= 0)
{
return;
}
// getPrice() is the price of the offer, not necessarily what the item bought at
int priceEach = offer.getSpent() / offer.getQuantitySold();
// offer.getPrice() is the price of the offer, not necessarily what the item bought at, so we compute it
// based on how much was spent & the qty
final int dspent = offer.getSpent() - savedOffer.getSpent();
final int price = dspent / qty;
if (price <= 0)
{
return;
}
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT || offer.getState() == GrandExchangeOfferState.CANCELLED_BUY);
grandExchangeTrade.setBuy(state == GrandExchangeOfferState.BUYING);
grandExchangeTrade.setItemId(offer.getItemId());
grandExchangeTrade.setQuantity(offer.getQuantitySold());
grandExchangeTrade.setPrice(priceEach);
grandExchangeTrade.setQuantity(qty);
grandExchangeTrade.setTotal(offer.getTotalQuantity());
grandExchangeTrade.setPrice(price);
grandExchangeTrade.setOffer(offer.getPrice());
log.debug("Submitting trade: {}", grandExchangeTrade);
grandExchangeClient.submit(grandExchangeTrade);
@@ -430,17 +479,6 @@ public class GrandExchangePlugin extends Plugin
}
}
private boolean shouldUpdate(SavedOffer savedOffer, GrandExchangeOffer grandExchangeOffer)
{
if (savedOffer == null)
{
return false;
}
// Only update offer if state has changed
return savedOffer.getState() != grandExchangeOffer.getState();
}
@Subscribe
public void onChatMessage(ChatMessage event)
{

View File

@@ -24,14 +24,100 @@
*/
package net.runelite.client.plugins.grandexchange;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GrandExchangeOffer;
import net.runelite.api.GrandExchangeOfferState;
import net.runelite.api.ItemID;
import net.runelite.client.Notifier;
import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.game.ItemManager;
import net.runelite.client.input.KeyManager;
import net.runelite.client.input.MouseManager;
import static net.runelite.client.plugins.grandexchange.GrandExchangePlugin.findFuzzyIndices;
import static net.runelite.http.api.RuneLiteAPI.GSON;
import net.runelite.http.api.ge.GrandExchangeClient;
import net.runelite.http.api.ge.GrandExchangeTrade;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class GrandExchangePluginTest
{
@Inject
private GrandExchangePlugin grandExchangePlugin;
@Mock
@Bind
private GrandExchangeConfig grandExchangeConfig;
@Mock
@Bind
private Notifier notifier;
@Mock
@Bind
private SessionManager sessionManager;
@Mock
@Bind
private ConfigManager configManager;
@Mock
@Bind
private ItemManager itemManager;
@Mock
@Bind
private KeyManager keyManager;
@Mock
@Bind
private MouseManager mouseManager;
@Mock
@Bind
private ScheduledExecutorService scheduledExecutorService;
@Mock
@Bind
private GrandExchangeClient grandExchangeClient;
@Mock
@Bind
private Client client;
@Mock
@Bind
private RuneLiteConfig runeLiteConfig;
@Before
public void setUp()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(client.getUsername()).thenReturn("adam");
}
@Test
public void testFindFuzzyIndices()
{
@@ -39,4 +125,94 @@ public class GrandExchangePluginTest
// r<u>ob</u>e <u>b</u>ottom
assertEquals(Arrays.asList(11, 12, 15), fuzzyIndices);
}
@Test
public void testSubmitTrade()
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(ItemID.ABYSSAL_WHIP);
savedOffer.setQuantitySold(1);
savedOffer.setTotalQuantity(10);
savedOffer.setPrice(1000);
savedOffer.setSpent(25);
savedOffer.setState(GrandExchangeOfferState.BUYING);
when(configManager.getConfiguration("geoffer.adam", "0")).thenReturn(GSON.toJson(savedOffer));
// buy 2 @ 10/ea
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1 + 2);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
when(grandExchangeOffer.getSpent()).thenReturn(25 + 10 * 2);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.BUYING);
grandExchangePlugin.submitTrade(0, grandExchangeOffer);
ArgumentCaptor<GrandExchangeTrade> captor = ArgumentCaptor.forClass(GrandExchangeTrade.class);
verify(grandExchangeClient).submit(captor.capture());
GrandExchangeTrade trade = captor.getValue();
assertTrue(trade.isBuy());
assertEquals(ItemID.ABYSSAL_WHIP, trade.getItemId());
assertEquals(2, trade.getQuantity());
assertEquals(10, trade.getTotal());
assertEquals(10, trade.getPrice());
}
@Test
public void testDuplicateTrade()
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(ItemID.ABYSSAL_WHIP);
savedOffer.setQuantitySold(1);
savedOffer.setTotalQuantity(10);
savedOffer.setPrice(1000);
savedOffer.setSpent(25);
savedOffer.setState(GrandExchangeOfferState.BUYING);
when(configManager.getConfiguration("geoffer.adam", "0")).thenReturn(GSON.toJson(savedOffer));
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
lenient().when(grandExchangeOffer.getSpent()).thenReturn(25);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.BUYING);
grandExchangePlugin.submitTrade(0, grandExchangeOffer);
verify(grandExchangeClient, never()).submit(any(GrandExchangeTrade.class));
}
@Test
public void testCancelTrade()
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(ItemID.ABYSSAL_WHIP);
savedOffer.setQuantitySold(1);
savedOffer.setTotalQuantity(10);
savedOffer.setPrice(1000);
savedOffer.setSpent(25);
savedOffer.setState(GrandExchangeOfferState.BUYING);
when(configManager.getConfiguration("geoffer.adam", "0")).thenReturn(GSON.toJson(savedOffer));
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
when(grandExchangeOffer.getSpent()).thenReturn(25);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.CANCELLED_BUY);
grandExchangePlugin.submitTrade(0, grandExchangeOffer);
ArgumentCaptor<GrandExchangeTrade> captor = ArgumentCaptor.forClass(GrandExchangeTrade.class);
verify(grandExchangeClient).submit(captor.capture());
GrandExchangeTrade trade = captor.getValue();
assertTrue(trade.isBuy());
assertTrue(trade.isCancel());
assertEquals(ItemID.ABYSSAL_WHIP, trade.getItemId());
assertEquals(1, trade.getQuantity());
assertEquals(10, trade.getTotal());
assertEquals(25, trade.getPrice());
}
}