Added database storage functionality for React data

This commit is contained in:
Rsl1122 2018-05-26 10:09:34 +03:00
parent d2e06711e6
commit 2a06c57c71
7 changed files with 306 additions and 2 deletions

View File

@ -220,6 +220,12 @@
<version>LATEST</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.volmit</groupId>
<artifactId>react</artifactId>
<version>6.549</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>

View File

@ -0,0 +1,77 @@
package com.djrapitops.pluginbridge.plan.react;
import com.djrapitops.plan.system.processing.Processing;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.task.AbsRunnable;
import com.volmit.react.React;
import com.volmit.react.api.GraphSampleLine;
import com.volmit.react.api.SampledType;
import com.volmit.react.util.GMap;
import com.volmit.react.util.M;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
/**
* Task in charge of collecting data from React.
*
* @author Rsl1122
*/
public class DataCollectionTask extends AbsRunnable {
private static final SampledType[] STORED_TYPES = new SampledType[]{
SampledType.ENT,
SampledType.ENTLIV,
SampledType.ENTDROP,
SampledType.ENTTILE,
SampledType.TIU,
SampledType.HOPPER_TICK_USAGE,
SampledType.FLUID_TICK_USAGE,
SampledType.REDSTONE_TICK_USAGE,
SampledType.TICK,
SampledType.TILE_DROPTICK,
SampledType.FLUID_TICK,
SampledType.HOPPER_TICK,
SampledType.ENTITY_DROPTICK,
SampledType.REDSTONE_TICK,
SampledType.REACT_TASK_TIME
};
private final ReactDataTable table;
private final Map<SampledType, List<ReactValue>> history;
public DataCollectionTask(ReactDataTable table) {
super(DataCollectionTask.class.getSimpleName());
this.table = table;
history = new EnumMap<>(SampledType.class);
}
@Override
public void run() {
GMap<SampledType, GraphSampleLine> samplers = React.instance.graphController.getG();
for (SampledType type : STORED_TYPES) {
processType(samplers, type);
}
}
private void processType(GMap<SampledType, GraphSampleLine> samplers, SampledType type) {
GMap<Long, Double> values = samplers.get(type).getPlotBoard().getBetween(M.ms() - 10000, M.ms());
List<ReactValue> storedValues = history.getOrDefault(type, new ArrayList<>());
values.entrySet().stream()
.map(entry -> new ReactValue(type, entry.getKey(), entry.getValue()))
.sorted()
.forEachOrdered(storedValues::add);
if (storedValues.get(0).getDate() < System.currentTimeMillis() - TimeAmount.MINUTE.ms()) {
Processing.submitNonCritical(new ValueStoringProcessor(table, type, storedValues));
history.remove(type);
} else {
history.put(type, storedValues);
}
}
}

View File

@ -0,0 +1,111 @@
package com.djrapitops.pluginbridge.plan.react;
import com.djrapitops.plan.api.exceptions.database.DBInitException;
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement;
import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement;
import com.djrapitops.plan.system.database.databases.sql.statements.Column;
import com.djrapitops.plan.system.database.databases.sql.statements.Select;
import com.djrapitops.plan.system.database.databases.sql.statements.Sql;
import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser;
import com.djrapitops.plan.system.database.databases.sql.tables.Table;
import com.volmit.react.api.SampledType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
/**
* Database Table in charge of storing data from React.
*
* @author Rsl1122
*/
public class ReactDataTable extends Table {
public static final String TABLE_NAME = "plan_react_data";
public ReactDataTable(SQLDB db) {
super(TABLE_NAME, db);
}
@Override
public void createTable() throws DBInitException {
createTable(TableSqlParser.createTable(TABLE_NAME)
.primaryKey(usingMySQL, Col.ID)
.column(Col.DATE, Sql.LONG)
.column(Col.SAMPLED_TYPE, Sql.varchar(30))
.column(Col.MINUTE_AVERAGE, Sql.DOUBLE)
.primaryKeyIDColumn(usingMySQL, Col.ID)
.toString());
}
public void addData(ReactValue value) throws SQLException {
String sql = "INSERT INTO " + tableName + " (" +
Col.SAMPLED_TYPE + ", " +
Col.DATE + ", " +
Col.MINUTE_AVERAGE +
") VALUES (?, ?, ?)";
execute(new ExecStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, value.getType().name());
statement.setLong(2, value.getDate());
statement.setDouble(3, value.getDataValue());
}
});
}
public Map<SampledType, List<ReactValue>> getAllData() throws SQLException {
String sql = Select.all(tableName).toString();
return query(new QueryAllStatement<Map<SampledType, List<ReactValue>>>(sql, 50000) {
@Override
public Map<SampledType, List<ReactValue>> processResults(ResultSet set) throws SQLException {
Map<SampledType, List<ReactValue>> results = new EnumMap<>(SampledType.class);
while (set.next()) {
try {
SampledType type = SampledType.valueOf(set.getString(Col.SAMPLED_TYPE.get()));
long date = set.getLong(Col.DATE.get());
double average = set.getDouble(Col.MINUTE_AVERAGE.get());
ReactValue value = new ReactValue(type, date, average);
List<ReactValue> values = results.getOrDefault(type, new ArrayList<>());
values.add(value);
results.put(type, values);
} catch (NoSuchFieldError ignore) {
/* Ignored, field has been removed and is no longer supported */
}
}
return results;
}
});
}
public enum Col implements Column {
ID("id"),
SAMPLED_TYPE("sampled_type"),
DATE("date"),
MINUTE_AVERAGE("minute_average");
private final String columnName;
Col(String columnName) {
this.columnName = columnName;
}
public String get() {
return columnName;
}
@Override
public String toString() {
return columnName;
}
}
}

View File

@ -0,0 +1,23 @@
package com.djrapitops.pluginbridge.plan.react;
import com.djrapitops.plan.Plan;
import com.djrapitops.plan.data.plugin.HookHandler;
import com.djrapitops.pluginbridge.plan.Hook;
/**
* Hook in charge for hooking into React.
*
* @author Rsl1122
*/
public class ReactHook extends Hook {
public ReactHook(HookHandler hookHandler) {
super("com.volmit.react.ReactPlugin", hookHandler);
}
@Override
public void hook() throws NoClassDefFoundError {
Plan plan = Plan.getInstance();
}
}

View File

@ -0,0 +1,38 @@
package com.djrapitops.pluginbridge.plan.react;
import com.volmit.react.api.SampledType;
/**
* Data container for React data points.
*
* @author Rsl1122
*/
public class ReactValue implements Comparable<ReactValue> {
private final SampledType type;
private final long date;
private final double dataValue;
public ReactValue(SampledType type, long date, double dataValue) {
this.type = type;
this.date = date;
this.dataValue = dataValue;
}
public SampledType getType() {
return type;
}
public long getDate() {
return date;
}
public double getDataValue() {
return dataValue;
}
@Override
public int compareTo(ReactValue o) {
return Long.compare(this.date, o.date);
}
}

View File

@ -0,0 +1,51 @@
package com.djrapitops.pluginbridge.plan.react;
import com.djrapitops.plugin.api.utility.log.Log;
import com.volmit.react.api.SampledType;
import java.sql.SQLException;
import java.util.List;
/**
* Processor in charge of turning values into single numbers.
*
* @author Rsl1122
*/
public class ValueStoringProcessor implements Runnable {
private final ReactDataTable table;
private final SampledType type;
private final List<ReactValue> values;
public ValueStoringProcessor(ReactDataTable table, SampledType type, List<ReactValue> values) {
this.table = table;
this.type = type;
this.values = values;
}
@Override
public void run() {
ReactValue average = avgValue(values);
if (average == null) {
return;
}
try {
table.addData(average);
} catch (SQLException e) {
Log.toLog(this.getClass(), e);
}
}
private ReactValue avgValue(List<ReactValue> values) {
if (values.isEmpty()) {
return null;
}
long date = values.get(0).getDate();
double average = values.stream().mapToDouble(ReactValue::getDataValue).average().orElse(0.0);
return new ReactValue(type, date, average);
}
}

View File

@ -18,8 +18,6 @@ import us.myles.ViaVersion.api.ViaAPI;
*/
public class ViaVersionHook extends Hook {
private static PlayerVersionListener listener;
/**
* Hooks the plugin and registers it's PluginData objects.
* <p>