loot tracker: store aggregated drops

This modifies both the service and the client plugin to no longer store
loot per-kill, with the exception of the current sessions kill log. The
amount of loot data returned now from the service defaults to the last
1024 unique events
This commit is contained in:
Adam
2020-01-09 17:35:17 -05:00
committed by Adam
parent bb6ac3a2be
commit 97b4f0d56f
10 changed files with 203 additions and 163 deletions

View File

@@ -32,9 +32,11 @@ import net.runelite.http.api.loottracker.LootRecordType;
class LootResult
{
private int killId;
private Instant time;
private Instant first_time;
private Instant last_time;
private LootRecordType type;
private String eventId;
private int amount;
private int itemId;
private int itemQuantity;
}

View File

@@ -30,6 +30,7 @@ import java.io.IOException;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.loottracker.LootAggregate;
import net.runelite.http.api.loottracker.LootRecord;
import net.runelite.http.service.account.AuthFilter;
import net.runelite.http.service.account.beans.SessionEntry;
@@ -67,7 +68,7 @@ public class LootTrackerController
}
@GetMapping
public Collection<LootRecord> getLootRecords(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count, @RequestParam(value = "start", defaultValue = "0") int start) throws IOException
public Collection<LootAggregate> getLootAggregate(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count, @RequestParam(value = "start", defaultValue = "0") int start) throws IOException
{
SessionEntry e = auth.handle(request, response);
if (e == null)

View File

@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.runelite.http.api.loottracker.GameItem;
import net.runelite.http.api.loottracker.LootAggregate;
import net.runelite.http.api.loottracker.LootRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -41,35 +42,37 @@ import org.sql2o.Sql2o;
@Service
public class LootTrackerService
{
// Table for storing individual LootRecords
private static final String CREATE_KILLS = "CREATE TABLE IF NOT EXISTS `kills` (\n"
+ " `id` INT AUTO_INCREMENT UNIQUE,\n"
+ " `time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),\n"
+ " `accountId` INT NOT NULL,\n"
+ " `type` enum('NPC', 'PLAYER', 'EVENT', 'UNKNOWN') NOT NULL,\n"
+ " `eventId` VARCHAR(255) NOT NULL,\n"
+ " PRIMARY KEY (id),\n"
+ " FOREIGN KEY (accountId) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,\n"
+ " INDEX idx_acc (accountId, time),"
+ " INDEX idx_time (time)"
+ ") ENGINE=InnoDB";
private static final String CREATE_KILLS = "CREATE TABLE IF NOT EXISTS `loottracker_kills` (\n" +
" `id` int(11) NOT NULL AUTO_INCREMENT,\n" +
" `first_time` timestamp NOT NULL DEFAULT current_timestamp(),\n" +
" `last_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),\n" +
" `accountId` int(11) NOT NULL,\n" +
" `type` enum('NPC','PLAYER','EVENT','UNKNOWN') NOT NULL,\n" +
" `eventId` varchar(255) NOT NULL,\n" +
" `amount` int(11) NOT NULL,\n" +
" PRIMARY KEY (`id`),\n" +
" FOREIGN KEY (accountId) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,\n" +
" INDEX idx_acc_lasttime (`accountId` ,`last_time`),\n" +
" UNIQUE INDEX idx_acc_type_event (`accountId`, `type`, `eventId`),\n" +
" INDEX idx_time (last_time)" +
") ENGINE=InnoDB;";
// Table for storing Items received as loot for individual LootRecords
private static final String CREATE_DROPS = "CREATE TABLE IF NOT EXISTS `drops` (\n"
+ " `killId` INT NOT NULL,\n"
+ " `itemId` INT NOT NULL,\n"
+ " `itemQuantity` INT NOT NULL,\n"
+ " FOREIGN KEY (killId) REFERENCES kills(id) ON DELETE CASCADE\n"
+ ") ENGINE=InnoDB";
private static final String CREATE_DROPS = "CREATE TABLE IF NOT EXISTS `loottracker_drops` (\n" +
" `killId` int(11),\n" +
" `itemId` int(11) NOT NULL,\n" +
" `itemQuantity` int(11) NOT NULL,\n" +
" UNIQUE INDEX idx_kill_item (`killId`, `itemId`),\n" +
" FOREIGN KEY (killId) REFERENCES loottracker_kills(id) ON DELETE CASCADE\n" +
") ENGINE=InnoDB;\n";
// Queries for inserting kills
private static final String INSERT_KILL_QUERY = "INSERT INTO kills (accountId, type, eventId) VALUES (:accountId, :type, :eventId)";
private static final String INSERT_DROP_QUERY = "INSERT INTO drops (killId, itemId, itemQuantity) VALUES (:killId, :itemId, :itemQuantity)";
private static final String INSERT_KILL_QUERY = "INSERT INTO loottracker_kills (accountId, type, eventId, amount) VALUES (:accountId, :type, :eventId, 1) ON DUPLICATE KEY UPDATE amount = amount + 1";
private static final String INSERT_DROP_QUERY = "INSERT INTO loottracker_drops (killId, itemId, itemQuantity) VALUES (:killId, :itemId, :itemQuantity) ON DUPLICATE KEY UPDATE itemQuantity = itemQuantity + :itemQuantity";
private static final String SELECT_LOOT_QUERY = "SELECT killId,time,type,eventId,itemId,itemQuantity FROM kills JOIN drops ON drops.killId = kills.id WHERE accountId = :accountId ORDER BY TIME DESC LIMIT :limit OFFSET :offset";
private static final String SELECT_LOOT_QUERY = "SELECT killId,first_time,last_time,type,eventId,amount,itemId,itemQuantity FROM loottracker_kills JOIN loottracker_drops ON loottracker_drops.killId = loottracker_kills.id WHERE accountId = :accountId ORDER BY last_time DESC LIMIT :limit OFFSET :offset";
private static final String DELETE_LOOT_ACCOUNT = "DELETE FROM kills WHERE accountId = :accountId";
private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM kills WHERE accountId = :accountId AND eventId = :eventId";
private static final String DELETE_LOOT_ACCOUNT = "DELETE FROM loottracker_kills WHERE accountId = :accountId";
private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM loottracker_kills WHERE accountId = :accountId AND eventId = :eventId";
private final Sql2o sql2o;
@@ -96,8 +99,8 @@ public class LootTrackerService
{
try (Connection con = sql2o.beginTransaction())
{
// Kill Entry Query
Query killQuery = con.createQuery(INSERT_KILL_QUERY, true);
Query insertDrop = con.createQuery(INSERT_DROP_QUERY);
for (LootRecord record : records)
{
@@ -105,41 +108,26 @@ public class LootTrackerService
.addParameter("accountId", accountId)
.addParameter("type", record.getType())
.addParameter("eventId", record.getEventId())
.addToBatch();
}
.executeUpdate();
Object[] keys = con.getKeys();
killQuery.executeBatch();
Object[] keys = con.getKeys();
if (keys.length != records.size())
{
throw new RuntimeException("Mismatch in keys vs records size");
}
Query insertDrop = con.createQuery(INSERT_DROP_QUERY);
// Append all queries for inserting drops
int idx = 0;
for (LootRecord record : records)
{
for (GameItem drop : record.getDrops())
{
insertDrop
.addParameter("killId", keys[idx])
.addParameter("killId", keys[0])
.addParameter("itemId", drop.getId())
.addParameter("itemQuantity", drop.getQty())
.addToBatch();
}
++idx;
insertDrop.executeBatch();
}
insertDrop.executeBatch();
con.commit(false);
}
}
public Collection<LootRecord> get(int accountId, int limit, int offset)
public Collection<LootAggregate> get(int accountId, int limit, int offset)
{
List<LootResult> lootResults;
@@ -153,7 +141,7 @@ public class LootTrackerService
}
LootResult current = null;
List<LootRecord> lootRecords = new ArrayList<>();
List<LootAggregate> lootRecords = new ArrayList<>();
List<GameItem> gameItems = new ArrayList<>();
for (LootResult lootResult : lootResults)
@@ -162,7 +150,7 @@ public class LootTrackerService
{
if (!gameItems.isEmpty())
{
LootRecord lootRecord = new LootRecord(current.getEventId(), current.getType(), gameItems, current.getTime());
LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount());
lootRecords.add(lootRecord);
gameItems = new ArrayList<>();
@@ -177,7 +165,7 @@ public class LootTrackerService
if (!gameItems.isEmpty())
{
LootRecord lootRecord = new LootRecord(current.getEventId(), current.getType(), gameItems, current.getTime());
LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount());
lootRecords.add(lootRecord);
}
@@ -204,12 +192,12 @@ public class LootTrackerService
}
}
@Scheduled(fixedDelay = 15 * 60 * 1000)
@Scheduled(fixedDelay = 60 * 60 * 1000)
public void expire()
{
try (Connection con = sql2o.open())
{
con.createQuery("delete from kills where time < current_timestamp() - interval 30 day")
con.createQuery("delete from loottracker_kills where last_time < current_timestamp() - interval 30 day")
.executeUpdate();
}
}