ge plugin: submit partially completed trades
This commit is contained in:
@@ -30,7 +30,10 @@ import lombok.Data;
|
|||||||
public class GrandExchangeTrade
|
public class GrandExchangeTrade
|
||||||
{
|
{
|
||||||
private boolean buy;
|
private boolean buy;
|
||||||
|
private boolean cancel;
|
||||||
private int itemId;
|
private int itemId;
|
||||||
private int quantity;
|
private int quantity;
|
||||||
|
private int total;
|
||||||
private int price;
|
private int price;
|
||||||
|
private int offer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.util.Collection;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import net.runelite.http.api.RuneLiteAPI;
|
||||||
import net.runelite.http.api.ge.GrandExchangeTrade;
|
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||||
import net.runelite.http.service.account.AuthFilter;
|
import net.runelite.http.service.account.AuthFilter;
|
||||||
import net.runelite.http.service.account.beans.SessionEntry;
|
import net.runelite.http.service.account.beans.SessionEntry;
|
||||||
@@ -58,14 +59,23 @@ public class GrandExchangeController
|
|||||||
@PostMapping
|
@PostMapping
|
||||||
public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException
|
public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException
|
||||||
{
|
{
|
||||||
SessionEntry session = authFilter.handle(request, response);
|
SessionEntry session = null;
|
||||||
|
if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null)
|
||||||
if (session == 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
|
@GetMapping
|
||||||
|
|||||||
@@ -371,39 +371,88 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
|
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
|
||||||
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
|
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
|
||||||
|
|
||||||
submitTrades(slot, offer);
|
submitTrade(slot, offer);
|
||||||
|
|
||||||
updateConfig(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 &&
|
GrandExchangeOfferState state = offer.getState();
|
||||||
offer.getState() != GrandExchangeOfferState.CANCELLED_BUY && offer.getState() != GrandExchangeOfferState.CANCELLED_SELL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancelled offers may have been cancelled before buying/selling any items
|
if (state != GrandExchangeOfferState.CANCELLED_BUY && state != GrandExchangeOfferState.CANCELLED_SELL && state != GrandExchangeOfferState.BUYING && state != GrandExchangeOfferState.SELLING)
|
||||||
if (offer.getQuantitySold() == 0)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SavedOffer savedOffer = getOffer(slot);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPrice() is the price of the offer, not necessarily what the item bought at
|
// offer.getPrice() is the price of the offer, not necessarily what the item bought at, so we compute it
|
||||||
int priceEach = offer.getSpent() / offer.getQuantitySold();
|
// 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 grandExchangeTrade = new GrandExchangeTrade();
|
||||||
grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT || offer.getState() == GrandExchangeOfferState.CANCELLED_BUY);
|
grandExchangeTrade.setBuy(state == GrandExchangeOfferState.BUYING);
|
||||||
grandExchangeTrade.setItemId(offer.getItemId());
|
grandExchangeTrade.setItemId(offer.getItemId());
|
||||||
grandExchangeTrade.setQuantity(offer.getQuantitySold());
|
grandExchangeTrade.setQuantity(qty);
|
||||||
grandExchangeTrade.setPrice(priceEach);
|
grandExchangeTrade.setTotal(offer.getTotalQuantity());
|
||||||
|
grandExchangeTrade.setPrice(price);
|
||||||
|
grandExchangeTrade.setOffer(offer.getPrice());
|
||||||
|
|
||||||
log.debug("Submitting trade: {}", grandExchangeTrade);
|
log.debug("Submitting trade: {}", grandExchangeTrade);
|
||||||
grandExchangeClient.submit(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
|
@Subscribe
|
||||||
public void onChatMessage(ChatMessage event)
|
public void onChatMessage(ChatMessage event)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,14 +24,100 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.grandexchange;
|
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.Arrays;
|
||||||
import java.util.List;
|
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.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.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
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
|
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
|
@Test
|
||||||
public void testFindFuzzyIndices()
|
public void testFindFuzzyIndices()
|
||||||
{
|
{
|
||||||
@@ -39,4 +125,94 @@ public class GrandExchangePluginTest
|
|||||||
// r<u>ob</u>e <u>b</u>ottom
|
// r<u>ob</u>e <u>b</u>ottom
|
||||||
assertEquals(Arrays.asList(11, 12, 15), fuzzyIndices);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user