@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.api.ge;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.runelite.http.api.RuneLiteAPI;
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.Callback;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class GrandExchangeClient
|
||||||
|
{
|
||||||
|
private static final MediaType JSON = MediaType.parse("application/json");
|
||||||
|
private static final Gson GSON = RuneLiteAPI.GSON;
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
|
||||||
|
public void submit(GrandExchangeTrade grandExchangeTrade)
|
||||||
|
{
|
||||||
|
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
||||||
|
.addPathSegment("ge")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.header(RuneLiteAPI.RUNELITE_AUTH, uuid.toString())
|
||||||
|
.post(RequestBody.create(JSON, GSON.toJson(grandExchangeTrade)))
|
||||||
|
.url(url)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e)
|
||||||
|
{
|
||||||
|
log.debug("unable to submit trade", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response)
|
||||||
|
{
|
||||||
|
log.debug("Submitted trade");
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.api.ge;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GrandExchangeTrade
|
||||||
|
{
|
||||||
|
private boolean buy;
|
||||||
|
private int itemId;
|
||||||
|
private int quantity;
|
||||||
|
private int price;
|
||||||
|
private Instant time;
|
||||||
|
}
|
||||||
@@ -35,9 +35,9 @@ import okhttp3.Request;
|
|||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GrandExchangeClient
|
public class OSBGrandExchangeClient
|
||||||
{
|
{
|
||||||
public GrandExchangeResult lookupItem(int itemId) throws IOException
|
public OSBGrandExchangeResult lookupItem(int itemId) throws IOException
|
||||||
{
|
{
|
||||||
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
||||||
.addPathSegment("osb")
|
.addPathSegment("osb")
|
||||||
@@ -59,7 +59,7 @@ public class GrandExchangeClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
final InputStream in = response.body().byteStream();
|
final InputStream in = response.body().byteStream();
|
||||||
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), GrandExchangeResult.class);
|
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), OSBGrandExchangeResult.class);
|
||||||
}
|
}
|
||||||
catch (JsonParseException ex)
|
catch (JsonParseException ex)
|
||||||
{
|
{
|
||||||
@@ -28,7 +28,7 @@ import java.time.Instant;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GrandExchangeResult
|
public class OSBGrandExchangeResult
|
||||||
{
|
{
|
||||||
private int item_id;
|
private int item_id;
|
||||||
private int buy_average;
|
private int buy_average;
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.ge;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||||
|
import net.runelite.http.service.account.AuthFilter;
|
||||||
|
import net.runelite.http.service.account.beans.SessionEntry;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ge")
|
||||||
|
public class GrandExchangeController
|
||||||
|
{
|
||||||
|
private final GrandExchangeService grandExchangeService;
|
||||||
|
private final AuthFilter authFilter;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GrandExchangeController(GrandExchangeService grandExchangeService, AuthFilter authFilter)
|
||||||
|
{
|
||||||
|
this.grandExchangeService = grandExchangeService;
|
||||||
|
this.authFilter = authFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException
|
||||||
|
{
|
||||||
|
SessionEntry session = authFilter.handle(request, response);
|
||||||
|
|
||||||
|
if (session == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grandExchangeService.add(session.getUser(), grandExchangeTrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public Collection<GrandExchangeTrade> get(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
@RequestParam(required = false, defaultValue = "1024") int limit,
|
||||||
|
@RequestParam(required = false, defaultValue = "0") int offset) throws IOException
|
||||||
|
{
|
||||||
|
SessionEntry session = authFilter.handle(request, response);
|
||||||
|
|
||||||
|
if (session == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return grandExchangeService.get(session.getUser(), limit, offset).stream()
|
||||||
|
.map(GrandExchangeController::convert)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GrandExchangeTrade convert(TradeEntry tradeEntry)
|
||||||
|
{
|
||||||
|
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
|
||||||
|
grandExchangeTrade.setBuy(tradeEntry.getAction() == TradeAction.BUY);
|
||||||
|
grandExchangeTrade.setItemId(tradeEntry.getItem());
|
||||||
|
grandExchangeTrade.setQuantity(tradeEntry.getQuantity());
|
||||||
|
grandExchangeTrade.setPrice(tradeEntry.getPrice());
|
||||||
|
grandExchangeTrade.setTime(tradeEntry.getTime());
|
||||||
|
return grandExchangeTrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping
|
||||||
|
public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||||
|
{
|
||||||
|
SessionEntry session = authFilter.handle(request, response);
|
||||||
|
|
||||||
|
if (session == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grandExchangeService.delete(session.getUser());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.ge;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.sql2o.Connection;
|
||||||
|
import org.sql2o.Sql2o;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GrandExchangeService
|
||||||
|
{
|
||||||
|
private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `ge_trades` (\n" +
|
||||||
|
" `id` int(11) NOT NULL AUTO_INCREMENT,\n" +
|
||||||
|
" `user` int(11) NOT NULL,\n" +
|
||||||
|
" `action` enum('BUY','SELL') NOT NULL,\n" +
|
||||||
|
" `item` int(11) NOT NULL,\n" +
|
||||||
|
" `quantity` int(11) NOT NULL,\n" +
|
||||||
|
" `price` int(11) NOT NULL,\n" +
|
||||||
|
" `time` timestamp NOT NULL DEFAULT current_timestamp(),\n" +
|
||||||
|
" PRIMARY KEY (`id`),\n" +
|
||||||
|
" KEY `user_time` (`user`, `time`),\n" +
|
||||||
|
" KEY `time` (`time`),\n" +
|
||||||
|
" CONSTRAINT `ge_trades_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`)\n" +
|
||||||
|
") ENGINE=InnoDB;";
|
||||||
|
|
||||||
|
private final Sql2o sql2o;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
||||||
|
{
|
||||||
|
this.sql2o = sql2o;
|
||||||
|
|
||||||
|
// Ensure necessary tables exist
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
con.createQuery(CREATE_TABLE).executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(int userId, GrandExchangeTrade grandExchangeTrade)
|
||||||
|
{
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
con.createQuery("insert into ge_trades (user, action, item, quantity, price) values (:user," +
|
||||||
|
" :action, :item, :quantity, :price)")
|
||||||
|
.addParameter("user", userId)
|
||||||
|
.addParameter("action", grandExchangeTrade.isBuy() ? "BUY" : "SELL")
|
||||||
|
.addParameter("item", grandExchangeTrade.getItemId())
|
||||||
|
.addParameter("quantity", grandExchangeTrade.getQuantity())
|
||||||
|
.addParameter("price", grandExchangeTrade.getPrice())
|
||||||
|
.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<TradeEntry> get(int userId, int limit, int offset)
|
||||||
|
{
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
return con.createQuery("select id, user, action, item, quantity, price, time from ge_trades where user = :user limit :limit offset :offset")
|
||||||
|
.addParameter("user", userId)
|
||||||
|
.addParameter("limit", limit)
|
||||||
|
.addParameter("offset", offset)
|
||||||
|
.executeAndFetch(TradeEntry.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(int userId)
|
||||||
|
{
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
con.createQuery("delete from ge_trades where user = :user")
|
||||||
|
.addParameter("user", userId)
|
||||||
|
.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 60 * 60 * 1000)
|
||||||
|
public void expire()
|
||||||
|
{
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
con.createQuery("delete from ge_trades where time < current_timestamp - interval 1 month")
|
||||||
|
.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.ge;
|
||||||
|
|
||||||
|
enum TradeAction
|
||||||
|
{
|
||||||
|
BUY,
|
||||||
|
SELL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.ge;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
class TradeEntry
|
||||||
|
{
|
||||||
|
private int id;
|
||||||
|
private int user;
|
||||||
|
private TradeAction action;
|
||||||
|
private int item;
|
||||||
|
private int quantity;
|
||||||
|
private int price;
|
||||||
|
private Instant time;
|
||||||
|
}
|
||||||
@@ -35,12 +35,12 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/osb/ge")
|
@RequestMapping("/osb/ge")
|
||||||
public class GrandExchangeController
|
public class OSBGrandExchangeController
|
||||||
{
|
{
|
||||||
private final GrandExchangeService grandExchangeService;
|
private final OSBGrandExchangeService grandExchangeService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GrandExchangeController(GrandExchangeService grandExchangeService)
|
public OSBGrandExchangeController(OSBGrandExchangeService grandExchangeService)
|
||||||
{
|
{
|
||||||
this.grandExchangeService = grandExchangeService;
|
this.grandExchangeService = grandExchangeService;
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ import org.sql2o.Sql2o;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GrandExchangeService
|
public class OSBGrandExchangeService
|
||||||
{
|
{
|
||||||
private static final String CREATE_GRAND_EXCHANGE_PRICES = "CREATE TABLE IF NOT EXISTS `osb_ge` (\n"
|
private static final String CREATE_GRAND_EXCHANGE_PRICES = "CREATE TABLE IF NOT EXISTS `osb_ge` (\n"
|
||||||
+ " `item_id` int(11) NOT NULL,\n"
|
+ " `item_id` int(11) NOT NULL,\n"
|
||||||
@@ -56,7 +56,7 @@ public class GrandExchangeService
|
|||||||
private final Sql2o sql2o;
|
private final Sql2o sql2o;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
public OSBGrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
||||||
{
|
{
|
||||||
this.sql2o = sql2o;
|
this.sql2o = sql2o;
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
*
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
* Copyright (c) 2017, Robbie <https://github.com/rbbi>
|
* Copyright (c) 2017, Robbie <https://github.com/rbbi>
|
||||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
@@ -46,6 +46,7 @@ import net.runelite.api.ChatMessageType;
|
|||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.GrandExchangeOffer;
|
import net.runelite.api.GrandExchangeOffer;
|
||||||
|
import net.runelite.api.GrandExchangeOfferState;
|
||||||
import net.runelite.api.ItemComposition;
|
import net.runelite.api.ItemComposition;
|
||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
@@ -56,11 +57,15 @@ import net.runelite.api.events.GameStateChanged;
|
|||||||
import net.runelite.api.events.GameTick;
|
import net.runelite.api.events.GameTick;
|
||||||
import net.runelite.api.events.GrandExchangeOfferChanged;
|
import net.runelite.api.events.GrandExchangeOfferChanged;
|
||||||
import net.runelite.api.events.MenuEntryAdded;
|
import net.runelite.api.events.MenuEntryAdded;
|
||||||
|
import net.runelite.api.events.SessionClose;
|
||||||
|
import net.runelite.api.events.SessionOpen;
|
||||||
import net.runelite.api.events.WidgetLoaded;
|
import net.runelite.api.events.WidgetLoaded;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetID;
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.client.Notifier;
|
import net.runelite.client.Notifier;
|
||||||
|
import net.runelite.client.account.AccountSession;
|
||||||
|
import net.runelite.client.account.SessionManager;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
@@ -73,8 +78,10 @@ import net.runelite.client.ui.NavigationButton;
|
|||||||
import net.runelite.client.util.ImageUtil;
|
import net.runelite.client.util.ImageUtil;
|
||||||
import net.runelite.client.util.StackFormatter;
|
import net.runelite.client.util.StackFormatter;
|
||||||
import net.runelite.client.util.Text;
|
import net.runelite.client.util.Text;
|
||||||
import net.runelite.http.api.osbuddy.GrandExchangeClient;
|
import net.runelite.http.api.ge.GrandExchangeClient;
|
||||||
import net.runelite.http.api.osbuddy.GrandExchangeResult;
|
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||||
|
import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
|
||||||
|
import net.runelite.http.api.osbuddy.OSBGrandExchangeResult;
|
||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "Grand Exchange",
|
name = "Grand Exchange",
|
||||||
@@ -86,7 +93,7 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
{
|
{
|
||||||
private static final int OFFER_CONTAINER_ITEM = 21;
|
private static final int OFFER_CONTAINER_ITEM = 21;
|
||||||
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
|
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
|
||||||
private static final GrandExchangeClient CLIENT = new GrandExchangeClient();
|
private static final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient();
|
||||||
private static final String OSB_GE_TEXT = "<br>OSBuddy Actively traded price: ";
|
private static final String OSB_GE_TEXT = "<br>OSBuddy Actively traded price: ";
|
||||||
|
|
||||||
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
|
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
|
||||||
@@ -134,10 +141,38 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
@Inject
|
@Inject
|
||||||
private ScheduledExecutorService executorService;
|
private ScheduledExecutorService executorService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SessionManager sessionManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ConfigManager configManager;
|
||||||
|
|
||||||
private Widget grandExchangeText;
|
private Widget grandExchangeText;
|
||||||
private Widget grandExchangeItem;
|
private Widget grandExchangeItem;
|
||||||
private Map<Integer, Integer> itemGELimits;
|
private Map<Integer, Integer> itemGELimits;
|
||||||
|
|
||||||
|
private GrandExchangeClient grandExchangeClient;
|
||||||
|
|
||||||
|
private SavedOffer getOffer(int slot)
|
||||||
|
{
|
||||||
|
String offer = configManager.getConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
|
||||||
|
if (offer == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return GSON.fromJson(offer, SavedOffer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOffer(int slot, SavedOffer offer)
|
||||||
|
{
|
||||||
|
configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), GSON.toJson(offer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteOffer(int slot)
|
||||||
|
{
|
||||||
|
configManager.unsetConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
GrandExchangeConfig provideConfig(ConfigManager configManager)
|
GrandExchangeConfig provideConfig(ConfigManager configManager)
|
||||||
{
|
{
|
||||||
@@ -167,6 +202,12 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
mouseManager.registerMouseListener(inputListener);
|
mouseManager.registerMouseListener(inputListener);
|
||||||
keyManager.registerKeyListener(inputListener);
|
keyManager.registerKeyListener(inputListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountSession accountSession = sessionManager.getAccountSession();
|
||||||
|
if (accountSession != null)
|
||||||
|
{
|
||||||
|
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -178,6 +219,27 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
grandExchangeText = null;
|
grandExchangeText = null;
|
||||||
grandExchangeItem = null;
|
grandExchangeItem = null;
|
||||||
itemGELimits = null;
|
itemGELimits = null;
|
||||||
|
grandExchangeClient = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onSessionOpen(SessionOpen sessionOpen)
|
||||||
|
{
|
||||||
|
AccountSession accountSession = sessionManager.getAccountSession();
|
||||||
|
if (accountSession.getUuid() != null)
|
||||||
|
{
|
||||||
|
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grandExchangeClient = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onSessionClose(SessionClose sessionClose)
|
||||||
|
{
|
||||||
|
grandExchangeClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -204,11 +266,79 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
|
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
|
||||||
{
|
{
|
||||||
GrandExchangeOffer offer = offerEvent.getOffer();
|
final int slot = offerEvent.getSlot();
|
||||||
|
final GrandExchangeOffer offer = offerEvent.getOffer();
|
||||||
|
|
||||||
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
|
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
|
||||||
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
|
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
|
||||||
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, offerEvent.getOffer(), offerEvent.getSlot()));
|
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
|
||||||
|
|
||||||
|
submitTrades(slot, offer);
|
||||||
|
|
||||||
|
updateConfig(slot, offer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void submitTrades(int slot, GrandExchangeOffer offer)
|
||||||
|
{
|
||||||
|
if (grandExchangeClient == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only interested in offers which are fully bought/sold
|
||||||
|
if (offer.getState() != GrandExchangeOfferState.BOUGHT && offer.getState() != GrandExchangeOfferState.SOLD)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SavedOffer savedOffer = getOffer(slot);
|
||||||
|
if (!shouldUpdate(savedOffer, offer))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPrice() is the price of the offer, not necessarily what the item bought at
|
||||||
|
int priceEach = offer.getSpent() / offer.getTotalQuantity();
|
||||||
|
|
||||||
|
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
|
||||||
|
grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT);
|
||||||
|
grandExchangeTrade.setItemId(offer.getItemId());
|
||||||
|
grandExchangeTrade.setQuantity(offer.getTotalQuantity());
|
||||||
|
grandExchangeTrade.setPrice(priceEach);
|
||||||
|
|
||||||
|
log.debug("Submitting trade: {}", grandExchangeTrade);
|
||||||
|
grandExchangeClient.submit(grandExchangeTrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfig(int slot, GrandExchangeOffer offer)
|
||||||
|
{
|
||||||
|
if (offer.getState() == GrandExchangeOfferState.EMPTY)
|
||||||
|
{
|
||||||
|
deleteOffer(slot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SavedOffer savedOffer = new SavedOffer();
|
||||||
|
savedOffer.setItemId(offer.getItemId());
|
||||||
|
savedOffer.setQuantitySold(offer.getQuantitySold());
|
||||||
|
savedOffer.setTotalQuantity(offer.getTotalQuantity());
|
||||||
|
savedOffer.setPrice(offer.getPrice());
|
||||||
|
savedOffer.setSpent(offer.getSpent());
|
||||||
|
savedOffer.setState(offer.getState());
|
||||||
|
setOffer(slot, savedOffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@@ -346,7 +476,7 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
final GrandExchangeResult result = CLIENT.lookupItem(itemId);
|
final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId);
|
||||||
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
|
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
|
||||||
geText.setText(text);
|
geText.setText(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.plugins.grandexchange;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import net.runelite.api.GrandExchangeOfferState;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
class SavedOffer
|
||||||
|
{
|
||||||
|
private int itemId;
|
||||||
|
private int quantitySold;
|
||||||
|
private int totalQuantity;
|
||||||
|
private int price;
|
||||||
|
private int spent;
|
||||||
|
private GrandExchangeOfferState state;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user