diff --git a/src/main/java/app/annotations/impl/WaitAfterNextAspect.java b/src/main/java/app/annotations/impl/WaitAfterNextAspect.java index c8f8fe5..ca58cda 100644 --- a/src/main/java/app/annotations/impl/WaitAfterNextAspect.java +++ b/src/main/java/app/annotations/impl/WaitAfterNextAspect.java @@ -16,24 +16,24 @@ import java.util.HashSet; @Aspect @Configuration public class WaitAfterNextAspect { - HashSet wait_steam64 = new HashSet<>(); + HashSet wait_order = new HashSet<>(); @Before("@annotation(app.annotations.interfaces.WaitAfterNext) && args(request,..)") public void before(JoinPoint joinPoint, HttpServletRequest request) { final String order = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(WaitAfterNext.class).order(); - final String steam64 = getSteam64fromCookie(request) + order; + final String hash = new StringBuilder().append(getSteam64fromCookie(request)).append(getIp(request)).append(order).toString(); - if (steam64.isEmpty()) return; - if (wait_steam64.contains(steam64)) throw new WaitRateLimit(); - wait_steam64.add(steam64); + if (hash.isEmpty()) return; + if (wait_order.contains(hash)) throw new WaitRateLimit(); + wait_order.add(hash); } @After("@annotation(app.annotations.interfaces.WaitAfterNext) && args(request,..)") public void after(JoinPoint joinPoint, HttpServletRequest request) { final String order = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(WaitAfterNext.class).order(); - final String steam64 = getSteam64fromCookie(request) + order; - if (steam64.isEmpty()) return; - if (wait_steam64.contains(steam64)) wait_steam64.remove(steam64); + final String hash = new StringBuilder().append(getSteam64fromCookie(request)).append(getIp(request)).append(order).toString(); + if (hash.isEmpty()) return; + if (wait_order.contains(hash)) wait_order.remove(hash); } public String getSteam64fromCookie(HttpServletRequest request) { @@ -51,4 +51,12 @@ public class WaitAfterNextAspect { } return steam64; } + + public String getIp(HttpServletRequest request) { + if (request.getHeader("X-Forwarded-For") == null) { + return ""; + } + + return request.getHeader("X-Forwarded-For").split(",")[0]; + } } diff --git a/src/main/java/app/controllers/StatsController.java b/src/main/java/app/controllers/StatsController.java index 241606e..cb1e939 100644 --- a/src/main/java/app/controllers/StatsController.java +++ b/src/main/java/app/controllers/StatsController.java @@ -10,10 +10,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.time.Instant; import java.util.HashMap; @@ -55,21 +52,29 @@ public class StatsController { } @GetMapping("/graph/peak/of/days") + @WaitAfterNext(order = "graph_peak_of_days") + @CollectStatistic public ResponseEntity> GetPeakOfDays( @RequestParam(required = false, defaultValue = "7") Integer limit, @RequestParam(required = false, defaultValue = "%") String server_id) { if (limit > 31) return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE); - if (!cache.containsKey(Map.of(limit, server_id))) { - cache.put(Map.of(limit, server_id), new HashMap<>(){{put(onlineUpdater.getPeakOfDays(server_id, limit), Instant.now().getEpochSecond());}}); - } - if (Instant.now().getEpochSecond() - cache.get(Map.of(limit, server_id)).values().stream().findFirst().orElse(0L) > limit * 10) { - cache.put(Map.of(limit, server_id), new HashMap<>(){{put(onlineUpdater.getPeakOfDays(server_id, limit), Instant.now().getEpochSecond());}}); - } + return new ResponseEntity<>(onlineUpdater.getPeakOfDays(server_id, limit), HttpStatus.OK); + } - return new ResponseEntity<>(cache.get(Map.of(limit, server_id)).keySet().stream().findFirst().orElse(null), HttpStatus.OK); + @GetMapping("/graph/peak/of/minutes") + @WaitAfterNext(order = "graph_peak_of_minutes") + @CollectStatistic + public ResponseEntity> GetPeakOfMinutes( + @RequestParam(required = false, defaultValue = "5") Integer minutes, + @RequestParam(required = false, defaultValue = "1") Integer limit, + @RequestParam(required = false, defaultValue = "%") String server_id + ) { + if (limit > 31) return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE); + return new ResponseEntity<>(onlineUpdater.getMaxPeakOfFiveMinutes(server_id, limit, minutes), HttpStatus.OK); } + @GetMapping("/reload") @CheckWebAccess @CheckPermitionFlag(flag = "z") diff --git a/src/main/java/app/updates/OnlineUpdater.java b/src/main/java/app/updates/OnlineUpdater.java index 7c1d78c..52fb6bf 100644 --- a/src/main/java/app/updates/OnlineUpdater.java +++ b/src/main/java/app/updates/OnlineUpdater.java @@ -12,8 +12,7 @@ import org.springframework.stereotype.Component; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; -import java.time.Instant; -import java.time.LocalDate; +import java.time.*; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -88,6 +87,8 @@ public class OnlineUpdater extends BaseUpdater { return current_day_max_player_count; } + + public List getMaxPeakOfDays(String server_id, int limit) { return jdbcTemplate_ro.query("SELECT SUM(s.player_count) as player_count, s.fulldate as fl FROM (SELECT max(`player_count`) as player_count, cast(FROM_UNIXTIME(`utime`) as date) as fulldate,`server_id` FROM `servers_online` WHERE `player_count` != 0 and `server_id` like ? GROUP BY cast(FROM_UNIXTIME(`utime`) as date), server_id ORDER BY `fulldate` DESC) s GROUP BY s.fulldate ORDER BY `s`.`fulldate` DESC LIMIT ?", new Object[]{server_id==null||server_id.isEmpty()?"%":server_id, limit}, @@ -100,6 +101,13 @@ public class OnlineUpdater extends BaseUpdater { (rs, rowNum) -> new AvgPeakOfDay(rs)); } + public List getMaxPeakOfFiveMinutes(String server_id, int limit, int minutes) { + long utime = LocalDate.now().minusDays(limit -1).toEpochSecond(LocalTime.MIN, ZoneOffset.ofHours(3)); + return jdbcTemplate_ro.query("select sum(sub.player_count) as player_count, sub.fulldate from (SELECT max(`player_count`) as player_count, FROM_UNIXTIME(`utime`) as fulldate, `utime` as ts, server_id FROM `servers_online` WHERE utime >= ? and `server_id` like ? GROUP BY FROM_UNIXTIME(`utime`) div ?, server_id ORDER BY `ts` DESC) sub GROUP BY sub.fulldate", + new Object[]{utime, server_id==null||server_id.isEmpty()?"%":server_id, minutes * 100}, + (rs, rowNum) -> new StatsOfPeakOfPerFiveMinutes(rs)); + } + public List getPeakOfDays(String server_id, int limit) { List maxPeakOfDays = getMaxPeakOfDays(server_id, limit); List avgPeakOfDays = getAvgPeakOfDays(server_id, limit); @@ -110,6 +118,24 @@ public class OnlineUpdater extends BaseUpdater { return statsOfPeakOfDays; } + public class StatsOfPeakOfPerFiveMinutes { + private final Timestamp timestamp; + private final int max; + + StatsOfPeakOfPerFiveMinutes(ResultSet rs) throws SQLException { + timestamp = rs.getTimestamp("fulldate"); + max = rs.getInt("player_count"); + } + + public LocalDateTime getTimestamp() { + return timestamp.toLocalDateTime(); + } + + public int getMax() { + return max; + } + } + public class StatsOfPeakOfDay { private final Date date; private final int max;