package server; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.sql.Timestamp; import static java.util.concurrent.TimeUnit.*; import config.YamlConfig; import tools.DatabaseConnection; public class ExpLogger { private static final LinkedBlockingQueue expLoggerQueue = new LinkedBlockingQueue<>(); private static final short EXP_LOGGER_THREAD_SLEEP_DURATION_SECONDS = 60; private static final short EXP_LOGGER_THREAD_SHUTDOWN_WAIT_DURATION_MINUTES = 5; public record ExpLogRecord(int worldExpRate, int expCoupon, long gainedExp, int currentExp,Timestamp expGainTime, int charid) {} public static void putExpLogRecord(ExpLogRecord expLogRecord) { try { expLoggerQueue.put(expLogRecord); } catch (InterruptedException e) { e.printStackTrace(); } } static private ScheduledExecutorService schdExctr = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setPriority(Thread.MIN_PRIORITY); return t; } }); private static Runnable saveExpLoggerToDBRunnable = new Runnable() { @Override public void run() { try (Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("INSERT INTO characterexplogs (world_exp_rate, exp_coupon, gained_exp, current_exp, exp_gain_time, charid) VALUES (?, ?, ?, ?, ?, ?)")) { List drainedExpLogs = new ArrayList<>(); expLoggerQueue.drainTo(drainedExpLogs); for (ExpLogRecord expLogRecord : drainedExpLogs) { ps.setInt(1, expLogRecord.worldExpRate); ps.setInt(2, expLogRecord.expCoupon); ps.setLong(3, expLogRecord.gainedExp); ps.setInt(4, expLogRecord.currentExp); ps.setTimestamp(5, expLogRecord.expGainTime); ps.setInt(6, expLogRecord.charid); ps.addBatch(); } ps.executeBatch(); } catch (SQLException sqle) { sqle.printStackTrace(); } } }; private static void startExpLogger() { schdExctr.scheduleWithFixedDelay(saveExpLoggerToDBRunnable, EXP_LOGGER_THREAD_SLEEP_DURATION_SECONDS, EXP_LOGGER_THREAD_SLEEP_DURATION_SECONDS, SECONDS); Runtime.getRuntime().addShutdownHook(new Thread(() -> { stopExpLogger(); })); } private static boolean stopExpLogger() { schdExctr.shutdown(); try { schdExctr.awaitTermination(EXP_LOGGER_THREAD_SHUTDOWN_WAIT_DURATION_MINUTES, MINUTES); Thread runThreadBeforeShutdown = new Thread(saveExpLoggerToDBRunnable); runThreadBeforeShutdown.setPriority(Thread.MIN_PRIORITY); runThreadBeforeShutdown.start(); return true; } catch (InterruptedException e) { e.printStackTrace(); return false; } } static { if (YamlConfig.config.server.USE_EXP_GAIN_LOG) { startExpLogger(); } } }