From 9232830451842f949882756a5201c6722b520a73 Mon Sep 17 00:00:00 2001 From: jenzur Date: Wed, 10 Jul 2019 00:47:24 +0200 Subject: [PATCH] saving some updates --- .../src/main/java/DTO/PlayerDTO.java | 7 +- .../main/java/DataMapper/DBCPDataSource2.java | 43 ++++ .../main/java/DataMapper/DataMapperCalls.java | 54 ++++- .../src/main/java/entity/Player.java | 2 +- .../src/main/java/entity/UrlBanners.java | 8 + .../src/main/java/facade/Facade.java | 203 +++++++++++++++--- .../src/main/java/rest/TimerResource.java | 37 ++-- .../src/main/java/utils/Initialization.java | 8 +- .../src/Datafacade/datafacade.js | 91 +++++--- .../src/Leaderboard/Leaderboard.js | 47 +++- .../racetimer_react/src/MapBoard/MapBoard.js | 74 +++++-- RaceTimer/racetimer_react/src/Maps/Maps.js | 122 ++++++++--- .../racetimer_react/src/Player/Player.js | 77 ++++++- RaceTimer/racetimer_react/src/css/style.css | 52 +++++ 14 files changed, 682 insertions(+), 143 deletions(-) create mode 100644 RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DBCPDataSource2.java diff --git a/RaceTimer/racetimer_endpoints/src/main/java/DTO/PlayerDTO.java b/RaceTimer/racetimer_endpoints/src/main/java/DTO/PlayerDTO.java index 5b5ba278..182b28a6 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/DTO/PlayerDTO.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/DTO/PlayerDTO.java @@ -6,6 +6,7 @@ package DTO; import entity.Player; +import entity.UrlBanners; import static facade.Facade.convertSteamIdToCommunityId; import java.util.ArrayList; import java.util.List; @@ -23,7 +24,7 @@ public class PlayerDTO { private int Rank; private int PlayerPoints; private int Times; - private List UrlBanners = new ArrayList(); + private List UrlBanners = new ArrayList(); public PlayerDTO(String steamID, String name, String Avatar, int Rank, int PlayerPoints, int Times) { this.steamID = steamID; @@ -45,5 +46,9 @@ public class PlayerDTO { this.Rank = player.getRank(); this.PlayerPoints = player.getPlayerPoints(); this.Times = player.getTimesCount(); + List urlBanners = player.getUrlBanners(); + for (UrlBanners urlbanners : urlBanners) { + this.UrlBanners.add(urlbanners.getBadgeUrl()); + } } } diff --git a/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DBCPDataSource2.java b/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DBCPDataSource2.java new file mode 100644 index 00000000..7bbc3348 --- /dev/null +++ b/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DBCPDataSource2.java @@ -0,0 +1,43 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package DataMapper; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.dbcp2.BasicDataSource; + +/** + * + * @author install1 + */ +public class DBCPDataSource2 { + + private static BasicDataSource ds = new BasicDataSource(); + + static { + try { + ds.setDriver(new com.mysql.cj.jdbc.Driver()); + ds.setUrl("jdbc:mysql://151.80.230.149:3306/xenforo?useLegacyDatetimeCode=false&serverTimezone=UTC"); + ds.setUsername("XenforoWebTimer"); + ds.setPassword("FNF#)(EFHFSNj23n4nfdsfbFE"); + ds.setMaxTotal(-1); + ds.setMinIdle(5); + ds.setMaxIdle(-1); + ds.setMaxOpenPreparedStatements(100); + } catch (SQLException ex) { + Logger.getLogger(DBCPDataSource.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public static Connection getConnection() throws SQLException { + return ds.getConnection(); + } + + private DBCPDataSource2() { + } +} diff --git a/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DataMapperCalls.java b/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DataMapperCalls.java index 13d728c2..c37ca985 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DataMapperCalls.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/DataMapper/DataMapperCalls.java @@ -18,6 +18,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @@ -27,11 +29,8 @@ public class DataMapperCalls { public static Map.Entry, Collection> getAllValues() { Collection allPlayers = new ArrayList(); - //remove limitfetch eventually - ConcurrentMap allMapBoards = new MapMaker().concurrencyLevel(4).makeMap(); String sqlQuery = "SELECT * FROM `zetimer_table`"; - int limitfetch = 0; try (Connection con = DBCPDataSource.getConnection()) { try (PreparedStatement ps = con.prepareStatement(sqlQuery)) { try (ResultSet result = ps.executeQuery()) { @@ -39,6 +38,7 @@ public class DataMapperCalls { while (result.next() /*&& limitfetch < 25*/) { int timesCounter = 0; Player player = new Player(result.getString(1), result.getString(2)); + //System.out.println("player dataMapper: " + player.getName() + "\nsteamid: " + player.getSteamID()); int i = 3; while (i < fetchSize) { String columnLabel = result.getMetaData().getColumnLabel(i); @@ -57,7 +57,6 @@ public class DataMapperCalls { } player.setTimesCount(timesCounter); allPlayers.add(player); - limitfetch++; } } } @@ -68,4 +67,51 @@ public class DataMapperCalls { return entry; } + public static ConcurrentMap> getURLBanners() { + ConcurrentMap> playerRelatedUrlBanners = new MapMaker().concurrencyLevel(4).makeMap(); + String sqlXenforoQuery = "SELECT t2.provider_key, t1.user_group_id FROM `xf_user_group_relation` t1, `xf_user_external_auth` " + + "t2 WHERE t1.user_id = t2.user_id AND t2.provider = \"steam\""; + try (Connection con = DBCPDataSource2.getConnection()) { + try (PreparedStatement ps = con.prepareStatement(sqlXenforoQuery)) { + try (ResultSet result = ps.executeQuery()) { + while (result.next()) { + String providerKey = result.getString(1); + int groupID = result.getInt(2); + String steamID = convertCommunityIdToSteamId(Long.valueOf(providerKey)); + Collection getSteamIDBanners = playerRelatedUrlBanners.getOrDefault(steamID, null); + if (getSteamIDBanners == null) { + getSteamIDBanners = new ArrayList(); + } + getSteamIDBanners.add(groupID); + playerRelatedUrlBanners.put(steamID, getSteamIDBanners); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return playerRelatedUrlBanners; + } + + private static String convertCommunityIdToSteamId(long communityId) { + long steamId1 = communityId % 2; + long steamId2 = communityId - 76561197960265728L; + steamId2 = (steamId2 - steamId1) / 2; + return "STEAM_0:" + steamId1 + ":" + steamId2; + } + + private Map.Entry GetMapnameAndStage(String mapName) { + Pattern pattern = Pattern.compile("S(\\d+)"); + Matcher matcher = pattern.matcher(mapName); + String map = ""; + int stage = 1; //0 + if (matcher.find()) { + String group = matcher.group(); + map = mapName.substring(0, mapName.indexOf(group)); + stage = Integer.valueOf(group.substring(1)); + } else { + map = mapName; + } + return new AbstractMap.SimpleEntry(map, stage); + } } diff --git a/RaceTimer/racetimer_endpoints/src/main/java/entity/Player.java b/RaceTimer/racetimer_endpoints/src/main/java/entity/Player.java index 00f3264a..99328554 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/entity/Player.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/entity/Player.java @@ -101,7 +101,7 @@ public class Player implements Serializable { this.timesCount = timesCount; } - public Collection getUrlBanners() { + public List getUrlBanners() { return urlBanners; } diff --git a/RaceTimer/racetimer_endpoints/src/main/java/entity/UrlBanners.java b/RaceTimer/racetimer_endpoints/src/main/java/entity/UrlBanners.java index c6bcd628..49ce01f4 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/entity/UrlBanners.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/entity/UrlBanners.java @@ -26,6 +26,14 @@ import javax.validation.constraints.NotNull; @Entity public class UrlBanners implements Serializable { + public UrlBanners() { + } + + public UrlBanners(String name, String badgeUrl) { + this.name = name; + this.badgeUrl = badgeUrl; + } + private static final long serialVersionUID = 1L; @Id @Basic(optional = false) diff --git a/RaceTimer/racetimer_endpoints/src/main/java/facade/Facade.java b/RaceTimer/racetimer_endpoints/src/main/java/facade/Facade.java index 31515467..24ba0685 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/facade/Facade.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/facade/Facade.java @@ -9,6 +9,7 @@ import com.google.common.collect.MapMaker; import entity.MapBoard; import entity.MapValues; import entity.Player; +import entity.UrlBanners; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -23,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -31,6 +33,7 @@ import java.util.regex.Pattern; import javax.persistence.EntityManager; import javax.persistence.Query; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import utils.PuSelector; @@ -49,13 +52,24 @@ public class Facade { initSetup = 1; } + public int getSpecificFetchMap(String mapname, int stage) { + MapBoard specificMapBoardCache = mapBoardCache.getOrDefault(mapname + "S" + stage, null); + if (specificMapBoardCache == null) { + specificMapBoardCache = mapBoardCache.get(mapname); + } + return specificMapBoardCache.getMapvalues().size(); + } + public List getAllMaps() { List arrnames = new ArrayList(mapBoardCache.keySet()); Collections.sort(arrnames); List arrMaps = new ArrayList(); + System.out.println("arrnames size: " + arrnames.size() + "\n"); for (String str : arrnames) { + System.out.println("getAllMaps str: " + str + "\n"); Map.Entry getMapnameAndStage = GetMapnameAndStage(str); - arrMaps.add(new MapBoardDTO2(getMapnameAndStage.getKey(), getMapnameAndStage.getValue())); + String mapName = getMapnameAndStage.getKey(); + arrMaps.add(new MapBoardDTO2(mapName, getMapnameAndStage.getValue())); } return arrMaps; } @@ -75,7 +89,8 @@ public class Facade { return new AbstractMap.SimpleEntry(map, stage); } - public List getSpecificMap(String mapname, int stage) { + public List getSpecificMap(String mapname, int stage, int iterator) { + int mapPlayerAddiditionCap = 75; List returnlist = new ArrayList(); String mapRetrieved = mapname + "S" + stage; MapBoard mapBoard = mapBoardCache.getOrDefault(mapRetrieved, null); @@ -84,22 +99,49 @@ public class Facade { mapBoard = mapBoardCache.get(mapRetrieved); } List mapvalues = mapBoard.getMapvalues(); + int counter = 0; + Collection playerAvatarsCaching = new ArrayList(); for (MapValues mapvalue : mapvalues) { - String avatar = playerCache.get(mapvalue.getPlayerSteamID()).getAvatar(); - returnlist.add(new MapBoardDTO(mapvalue, playerCache.get(mapvalue.getPlayerSteamID()).getName(), avatar)); + Player getPlayer = playerCache.get(mapvalue.getPlayerSteamID()); + String avatar = getPlayer.getAvatar(); + if (avatar == null) { + playerAvatarsCaching.add(getPlayer); + } + } + updateAvatarsToCache(playerAvatarsCaching); + for (MapValues mapvalue : mapvalues) { + if (counter >= iterator && counter <= iterator + mapPlayerAddiditionCap) { + String avatar = playerCache.get(mapvalue.getPlayerSteamID()).getAvatar(); + returnlist.add(new MapBoardDTO(mapvalue, playerCache.get(mapvalue.getPlayerSteamID()).getName(), avatar)); + } + if (counter > iterator + mapPlayerAddiditionCap) { + break; + } + counter++; } return returnlist; } - public List getPlayerMaps(String steamid) { + public List getPlayerMaps(String steamid, int iterator) { + int playerMapsCapAddition = 35; try { ConcurrentMap playerMaps = playerRelatedMapValuesCache.get(steamid); List playerMapBoardDtos = new ArrayList(); + int counter = 0; for (Entry entries : playerMaps.entrySet()) { - PlayerMapBoardDTO mapBoardDto = new PlayerMapBoardDTO(steamid); - Map.Entry getMapnameAndStage = GetMapnameAndStage(entries.getKey()); - mapBoardDto.addMapValues(entries.getValue(), getMapnameAndStage.getKey(), getMapnameAndStage.getValue()); - playerMapBoardDtos.add(mapBoardDto); + if (counter >= iterator && counter <= iterator + playerMapsCapAddition) { + PlayerMapBoardDTO mapBoardDto = new PlayerMapBoardDTO(steamid); + Map.Entry getMapnameAndStage = GetMapnameAndStage(entries.getKey()); + String mapName = getMapnameAndStage.getKey(); + int stage = (getMapnameAndStage.getValue()); + //System.out.println("getPlayerMaps: " + mapName + " stage: " + stage + "\n"); + mapBoardDto.addMapValues(entries.getValue(), mapName, stage); + playerMapBoardDtos.add(mapBoardDto); + } + if (counter > iterator + playerMapsCapAddition) { + break; + } + counter++; } return playerMapBoardDtos; } catch (Exception ex) { @@ -108,15 +150,34 @@ public class Facade { } public PlayerDTO getPlayer(String steamid) { + if (playerCache.get(steamid).getAvatar() == null) { + Collection playerAvatarsCaching = new ArrayList(); + playerAvatarsCaching.add(playerCache.get(steamid)); + updateAvatarsToCache(playerAvatarsCaching); + } return new PlayerDTO(playerCache.get(steamid)); } public Collection getleaderBoard(int iterator) { - int playerAddiditionCap = 150; + int playerAddiditionCap = 99; + Collection playerAvatarsCaching = new ArrayList(); List players = new ArrayList(playerCache.values()); Collection playersDTO = new ArrayList(); players.sort(Comparator.comparing(Player::getRank)); int counter = 0; + for (Player player : players) { + if (counter >= iterator && counter <= iterator + playerAddiditionCap && player.getAvatar() == null) { + playerAvatarsCaching.add(player); + } + if (counter > iterator + playerAddiditionCap) { + break; + } + counter++; + } + updateAvatarsToCache(playerAvatarsCaching); + players = new ArrayList(playerCache.values()); + players.sort(Comparator.comparing(Player::getRank)); + counter = 0; for (Player player : players) { if (counter >= iterator && counter <= iterator + playerAddiditionCap) { playersDTO.add(new PlayerDTO(player)); @@ -129,8 +190,77 @@ public class Facade { return playersDTO; } - private void addNewPlayerValuesToCache(Collection keyCollection) { + private void addNewPlayerValuesToCache(Collection keyCollection, ConcurrentMap> playerUrlBanners) { + //2 = user, 6 = mapper, 7 = admin, 8 = technical staff, 10 = leader, 12 = vip, 13 = trial admin, 15 = event winner, 19 = discord manager + // 20 NSFW, 21 = Retired admin, 25 = event manager, 11 = GA for (Player player : keyCollection) { + Collection banners = playerUrlBanners.getOrDefault(player.getSteamID(), null); + if (banners != null) { + List urlBanners = new ArrayList(); + for (Integer bannerID : banners) { + String bannerName = ""; + String bannerURL = ""; + switch (bannerID) { + case 2: { + bannerName = "User"; + bannerURL = "https://unloze.com/images/badges/User.png"; + } + case 6: { + bannerName = "Mapper"; + bannerURL = "https://unloze.com/images/badges/Mapper.png"; + } + case 7: { + bannerName = "Admin"; + bannerURL = "https://unloze.com/images/badges/Admin.png"; + } + case 8: { + bannerName = "Technical Staff"; + bannerURL = "https://unloze.com/images/badges/Tech-Staff.png"; + } + case 10: { + bannerName = "Leader"; + bannerURL = "https://unloze.com/images/badges/Leader.png"; + } + case 11: { + bannerName = "Global Admin"; + bannerURL = "https://unloze.com/images/badges/Global-Admin.png"; + } + case 12: { + bannerName = "VIP"; + bannerURL = "https://unloze.com/images/badges/VIP.png"; + } + case 13: { + bannerName = "Trial Admin"; + bannerURL = "https://unloze.com/images/badges/Trial_Admin.png"; + } + case 15: { + bannerName = "Event Winner"; + bannerURL = "https://unloze.com/images/badges/Event-Winner.png"; + } + case 19: { + bannerName = "Discord Manager"; + bannerURL = "https://unloze.com/images/badges/Discord-Manager.png"; + } + case 21: { + bannerName = "Retired Admin"; + bannerURL = "https://unloze.com/images/badges/Retired-Admin.png"; + } + case 25: { + bannerName = "Event Manager"; + bannerURL = "https://unloze.com/images/badges/Event-Manager.png"; + } + default: { + bannerName = ""; + bannerURL = ""; + } + } + if (!bannerName.isEmpty() && !bannerURL.isEmpty()) { + urlBanners.add(new UrlBanners(bannerName, bannerURL)); + } + } + player.setUrlBanners(urlBanners); + } + //System.out.println("playername: " + player.getName() + "\n"); playerCache.put(player.getSteamID(), player); } } @@ -143,26 +273,22 @@ public class Facade { } private void retrieveAvatarFull(String avatarurl) { - //https://steamcommunity.com/profiles/76561198517905428 some nosteamers have no information available on steams rest-endpoints try { URL url = new URL(avatarurl); - //System.out.println("avatarurl: " + avatarurl + "\n"); JSONTokener tokener = new JSONTokener(url.openStream()); JSONObject root = new JSONObject(tokener); JSONObject jsonObject = root.getJSONObject("response"); JSONArray jsonArray = jsonObject.getJSONArray("players"); - int incrementer = 0; - for (; incrementer < jsonArray.length();) { - System.out.println("incrementer: " + incrementer + "\n"); + for (int incrementer = 0; incrementer < jsonArray.length(); incrementer++) { try { String steamID64 = jsonArray.getJSONObject(incrementer).getString("steamid"); String avatar = jsonArray.getJSONObject(incrementer).getString("avatarfull"); String steamID = convertCommunityIdToSteamId(Long.valueOf(steamID64)); playerCache.get(steamID).setAvatar(avatar); - } catch (Exception ex) { - System.out.println("ex: " + ex.getLocalizedMessage() + "\n"); + System.out.println("avatar: " + avatar + "\nname: " + playerCache.get(steamID).getName() + "\n"); + } catch (NumberFormatException | JSONException ex) { + System.out.println("ex: " + ex.getLocalizedMessage() + "\n Nosteamer"); } - incrementer++; } } catch (MalformedURLException ex) { Logger.getLogger(Facade.class.getName()).log(Level.SEVERE, null, ex); @@ -171,32 +297,36 @@ public class Facade { } } - private void updateAvatarsToCache() { + private void updateAvatarsToCache(Collection players) { //http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=262F3F0C6B83E0F263C272C3762002F1&steamids=76561198029832363,76561198003907342 StringBuilder avatarURL = new StringBuilder(); avatarURL.append("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=262F3F0C6B83E0F263C272C3762002F1&steamids="); int incrementer = 0; - for (Player player : playerCache.values()) { + int overallCounter = 0; + int fetchCapacity = 450; + for (Player player : players) { if (incrementer > 0) { avatarURL.append(","); } incrementer++; avatarURL.append(Long.toString(convertSteamIdToCommunityId(player.getSteamID()))); - //550 is too large size for url.openStream(), fetch limit is probably about 100 players best - if (incrementer >= 100 || incrementer >= playerCache.size()) { - retrieveAvatarFull(avatarURL.toString()); + if (incrementer >= fetchCapacity || incrementer + overallCounter >= players.size()) { + final String fullUrl = avatarURL.toString(); + retrieveAvatarFull(fullUrl); + overallCounter += incrementer; + incrementer = 0; avatarURL = new StringBuilder(); avatarURL.append("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=262F3F0C6B83E0F263C272C3762002F1&steamids="); - incrementer = 0; } } + setNonExistingAvatarOnPlayers(players); } - private void setNonExistingAvatarOnPlayers() { - for (Player player : playerCache.values()) { + private void setNonExistingAvatarOnPlayers(Collection players) { + for (Player player : players) { String avatar = player.getAvatar(); if (avatar == null) { - player.setAvatar("https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg"); + playerCache.get(player.getSteamID()).setAvatar("https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg"); } } } @@ -248,7 +378,6 @@ public class Facade { for (MapValues mapvalue : mapvalues) { String steamID = mapvalue.getPlayerSteamID(); int mapPoints = mapvalue.getMapPoints(); - System.out.println("\nmapPoints: " + mapPoints + "\n"); playerCache.get(steamID).addPlayerPoints(mapPoints); } } @@ -285,25 +414,25 @@ public class Facade { public void checkTimeElapse() { Instant current = Instant.now(); long timeElapsed = Duration.between(elapsedTime, current).toMillis(); - System.out.println("timeElapsed: " + timeElapsed + "\n"); - if (timeElapsed >= EXPIRE_TIME_IN_SECONDS || initSetup > 0) { + //perharps 3 mins instead of 30? + if (timeElapsed >= EXPIRE_TIME_IN_SECONDS * 1000 || initSetup > 0) { + //System.out.println("went through \ntimeElapsed: " + timeElapsed + "\nEXPIRE_TIME_IN_SECONDS: " + EXPIRE_TIME_IN_SECONDS * 100); initSetup = 0; elapsedTime = Instant.now(); Entry, Collection> playersMapBoards = DataMapperCalls.getAllValues(); Collection mapBoardCollection = playersMapBoards.getValue(); + ConcurrentMap> playerRelatedUrlBanners = DataMapperCalls.getURLBanners(); playerCache.clear(); mapBoardCache.clear(); playerRelatedMapValuesCache.clear(); addNewMapBoardValuesToCache(mapBoardCollection); - addNewPlayerValuesToCache(playersMapBoards.getKey()); - updateAvatarsToCache(); - setNonExistingAvatarOnPlayers(); + addNewPlayerValuesToCache(playersMapBoards.getKey(), playerRelatedUrlBanners); orderingMapBoardValuesByTime(); setPositionAndMapPoints(); setPlayerPoints(); updatePlayerRanks(); setTimesAsociatedToPeople(); - updateEntitiesPersistence(); + //updateEntitiesPersistence(); } } @@ -319,6 +448,10 @@ public class Facade { for (Player player : players) { System.out.println("player: " + player.getName()); em.persist(player); + List urlBanners = player.getUrlBanners(); + for (UrlBanners urlB : urlBanners) { + em.persist(urlB); + } } for (MapBoard mapboard : mapBoards) { System.out.println("mapboard: " + mapboard.getMapName()); diff --git a/RaceTimer/racetimer_endpoints/src/main/java/rest/TimerResource.java b/RaceTimer/racetimer_endpoints/src/main/java/rest/TimerResource.java index f46a6ceb..70bf0d03 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/rest/TimerResource.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/rest/TimerResource.java @@ -31,6 +31,22 @@ public class TimerResource { facade.checkTimeElapse(); return gson.toJson(facade.getleaderBoard(iterator)); } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("allmaps") + public String getAllMaps() { + facade.checkTimeElapse(); + return gson.toJson(facade.getAllMaps()); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("mapsizecache/{mapname}/{stage}") + public String getSpecifcMapSize(@PathParam("mapname") String mapname, @PathParam("stage") int stage) { + facade.checkTimeElapse(); + return gson.toJson(facade.getSpecificFetchMap(mapname, stage)); + } @GET @Produces(MediaType.APPLICATION_JSON) @@ -42,25 +58,20 @@ public class TimerResource { @GET @Produces(MediaType.APPLICATION_JSON) - @Path("player/maps/{steamid}") - public String retrievePlayerMaps(@PathParam("steamid") String steamid) { + @Path("player/maps/{steamid}/{iterator}") + public String retrievePlayerMaps(@PathParam("steamid") String steamid, @PathParam("iterator") int iterator) { facade.checkTimeElapse(); - return gson.toJson(facade.getPlayerMaps(steamid)); + return gson.toJson(facade.getPlayerMaps(steamid, iterator)); } @GET @Produces(MediaType.APPLICATION_JSON) - @Path("map/{mapname}/{number}") - public String retrieveSpecificMapStages(@PathParam("mapname") String mapname, @PathParam("number") int stage) { + @Path("map/{mapname}/{number}/{iterator}") + public String retrieveSpecificMapStages(@PathParam("mapname") String mapname, @PathParam("number") int stage, + @PathParam("iterator") int iterator) { facade.checkTimeElapse(); - return gson.toJson(facade.getSpecificMap(mapname, stage)); + return gson.toJson(facade.getSpecificMap(mapname, stage, iterator)); } - @GET - @Produces(MediaType.APPLICATION_JSON) - @Path("allmaps") - public String getAllMaps() { - facade.checkTimeElapse(); - return gson.toJson(facade.getAllMaps()); - } + } diff --git a/RaceTimer/racetimer_endpoints/src/main/java/utils/Initialization.java b/RaceTimer/racetimer_endpoints/src/main/java/utils/Initialization.java index 6de84226..25b93e8c 100644 --- a/RaceTimer/racetimer_endpoints/src/main/java/utils/Initialization.java +++ b/RaceTimer/racetimer_endpoints/src/main/java/utils/Initialization.java @@ -8,6 +8,7 @@ package utils; import entity.AdminEditor; import entity.MapBoard; import entity.Player; +import entity.UrlBanners; import facade.Facade; import java.util.Collection; import java.util.List; @@ -27,6 +28,9 @@ public class Initialization { Facade facade = new Facade(); List getAllPlayers = facade.getAllPlayersFromCache(); Collection getAllMapBoards = facade.getAllMapBoardsFromCache(); + //facade.getPlayerMaps("STEAM_0:0:191740833", 0); + // facade.getPlayerMaps("STEAM_0:0:191740833", 25); + facade.getAllMaps(); AdminEditor admin = new AdminEditor("jenz", "1234"); EntityManager em = PuSelector.getEntityManagerFactory("pu").createEntityManager(); //simply cant persist collections/list @@ -37,11 +41,11 @@ public class Initialization { em.createQuery("delete from Player").executeUpdate(); em.createQuery("delete from UrlBanners").executeUpdate(); for (Player player : getAllPlayers) { - System.out.println("player: " + player.getName()); + // System.out.println("player: " + player.getName()); em.persist(player); } for (MapBoard mapboard : getAllMapBoards) { - System.out.println("mapboard: " + mapboard.getMapName()); + // System.out.println("mapboard: " + mapboard.getMapName()); em.persist(mapboard); } em.persist(admin); diff --git a/RaceTimer/racetimer_react/src/Datafacade/datafacade.js b/RaceTimer/racetimer_react/src/Datafacade/datafacade.js index 3bf4d6ae..1899fa8e 100644 --- a/RaceTimer/racetimer_react/src/Datafacade/datafacade.js +++ b/RaceTimer/racetimer_react/src/Datafacade/datafacade.js @@ -1,9 +1,11 @@ import React from 'react'; +import { trackPromise } from 'react-promise-tracker'; const URLleaderboard = "http://localhost:8080/racetimer_endpoints-1.0/api/timers/leaderboard"; const URLPlayer = "http://localhost:8080/racetimer_endpoints-1.0/api/timers/player/"; const URLPlayerMaps = "http://localhost:8080/racetimer_endpoints-1.0/api/timers/player/maps/"; const URLMaps = "http://localhost:8080/racetimer_endpoints-1.0/api/timers/map/"; const URLAllMaps = "http://localhost:8080/racetimer_endpoints-1.0/api/timers/allmaps"; +const URLMapsSize = "http://localhost:8080/racetimer_endpoints-1.0/api/timers/mapsizecache"; function handleHttpErrors(res) { if (!res.ok) { @@ -20,8 +22,6 @@ class DataFacade extends React.Component { }; } - - getLeaderBoardFromCache = async (incrementer) => { const CachedTime = JSON.parse(localStorage.getItem("leaderboardTimer")); const timeExpired = CachedTime ? Date.now() - CachedTime : 0; @@ -36,22 +36,27 @@ class DataFacade extends React.Component { const cachedLeaderBoard = JSON.parse(leaderBoardData); return cachedLeaderBoard; } else { - const players = await fetch(URLleaderboard + "/" + incrementer).then(handleHttpErrors); + const players = await trackPromise(fetch(URLleaderboard + "/" + incrementer).then(handleHttpErrors)); if (leaderBoardData !== null) { const cachedLeaderBoard = JSON.parse(leaderBoardData); + if (players === null) { + return cachedLeaderBoard; + } players.map(e => ( cachedLeaderBoard.push(e) )) localStorage.setItem("leaderboard", JSON.stringify(cachedLeaderBoard)); return cachedLeaderBoard; - } else { + + } else if (incrementer === 0) { localStorage.setItem("leaderboard", JSON.stringify(players)); return players; } } - }; + } - getAllMapsFromCache = async () => { + + getMapCountFromCache = async () => { const CachedTime = JSON.parse(localStorage.getItem("allmapsTimer")); const timeExpired = CachedTime ? Date.now() - CachedTime : 0; //30 mins @@ -64,11 +69,14 @@ class DataFacade extends React.Component { const cachedAllMaps = JSON.parse(allMapsData); return cachedAllMaps; } else { - const allMaps = await fetch(URLAllMaps).then(handleHttpErrors); - localStorage.setItem("allmaps", JSON.stringify(allMaps)); - return allMaps; + const maps = await trackPromise(fetch(URLAllMaps).then(handleHttpErrors)); + localStorage.setItem("allmaps", JSON.stringify(maps)); + return maps; } - }; + } + + + getPlayerFromCache = async (steamID) => { const CachedTime = JSON.parse(localStorage.getItem("initialCachedplayers" + steamID)); @@ -84,13 +92,13 @@ class DataFacade extends React.Component { const player = JSON.parse(playerData); return player; } else { - const player = await fetch(URLPlayer + steamID).then(handleHttpErrors); + const player = await trackPromise(fetch(URLPlayer + steamID).then(handleHttpErrors)); localStorage.setItem(storageString, JSON.stringify(player)); return player; } } - getPlayerTimesFromCache = async (steamID) => { + getPlayerTimesFromCache = async (steamID, incrementer) => { const CachedTime = JSON.parse(localStorage.getItem("initialCachedplayersTimes" + steamID)); const timeExpired = CachedTime ? Date.now() - CachedTime : 0; //30 mins @@ -100,17 +108,45 @@ class DataFacade extends React.Component { } var storageString = "playertimes/" + steamID; var playerTimesData = localStorage.getItem(storageString); - if (playerTimesData) { + if (incrementer === 0 && playerTimesData) { const cachedPlayerTimes = JSON.parse(playerTimesData) return cachedPlayerTimes; } else { - const playertimes = await fetch(URLPlayerMaps + steamID).then(handleHttpErrors); - localStorage.setItem(storageString, JSON.stringify(playertimes)); - return playertimes; + const playertimes = await trackPromise(fetch(URLPlayerMaps + steamID + "/" + incrementer).then(handleHttpErrors)); + if (playerTimesData !== null) { + const cachedPlayerTimes = JSON.parse(playerTimesData); + playertimes.map(e => ( + cachedPlayerTimes.push(e) + )) + localStorage.setItem(storageString, JSON.stringify(cachedPlayerTimes)); + return cachedPlayerTimes; + } else if (incrementer === 0) { + localStorage.setItem(storageString, JSON.stringify(playertimes)); + return playertimes; + } } } - getMapTimesFromCache = async (mapname, stage) => { + getMapTimesFromCacheSize = async (mapname, stage) => { + const CachedTime = JSON.parse(localStorage.getItem("maptimessizecached" + mapname + stage)); + const timeExpired = CachedTime ? Date.now() - CachedTime : 0; + //30 mins + if (!CachedTime || timeExpired > 30 * 60000) { + localStorage.setItem("maptimessizecached" + mapname + stage, JSON.stringify(Date.now())); + localStorage.removeItem("mapsizecache" + mapname + stage); + } + var maptimesCacheSizeData = localStorage.getItem("mapsizecache" + mapname + stage); + if (maptimesCacheSizeData) { + const cachedsize = JSON.parse(maptimesCacheSizeData); + return cachedsize; + } else { + const mapCacheSize = await fetch(URLMapsSize + "/" + mapname + "/" + stage).then(handleHttpErrors); + localStorage.setItem("mapsizecache" + mapname + stage, JSON.stringify(mapCacheSize)); + return mapCacheSize; + } + } + + getMapTimesFromCache = async (mapname, stage, incrementer) => { const CachedTime = JSON.parse(localStorage.getItem("maptimescached" + mapname + stage)); const timeExpired = CachedTime ? Date.now() - CachedTime : 0; //30 mins @@ -119,16 +155,23 @@ class DataFacade extends React.Component { localStorage.removeItem("map/" + mapname + stage); } var mapTimesData = localStorage.getItem("map/" + mapname + stage); - if (mapTimesData) { + if (incrementer === 0 && mapTimesData) { const cachedMapTimes = JSON.parse(mapTimesData); return cachedMapTimes; } else { - const mapTimes = await fetch(URLMaps + mapname + "/" + stage).then(handleHttpErrors); - localStorage.setItem("map/" + mapname + stage, JSON.stringify(mapTimes)); - return mapTimes; + const mapTimes = await trackPromise(fetch(URLMaps + mapname + "/" + stage + "/" + incrementer).then(handleHttpErrors)); + if (mapTimesData !== null) { + const cachedMapTimes = JSON.parse(mapTimesData); + mapTimes.map(e => ( + cachedMapTimes.push(e) + )) + localStorage.setItem("map/" + mapname + stage, JSON.stringify(cachedMapTimes)); + return cachedMapTimes; + } else if (incrementer === 0) { + localStorage.setItem("map/" + mapname + stage, JSON.stringify(mapTimes)); + return mapTimes; + } } } - -} - +}; export default new DataFacade(); \ No newline at end of file diff --git a/RaceTimer/racetimer_react/src/Leaderboard/Leaderboard.js b/RaceTimer/racetimer_react/src/Leaderboard/Leaderboard.js index f2f9859c..4d42b8d0 100644 --- a/RaceTimer/racetimer_react/src/Leaderboard/Leaderboard.js +++ b/RaceTimer/racetimer_react/src/Leaderboard/Leaderboard.js @@ -1,6 +1,23 @@ import React from 'react'; import Facade from '../Datafacade/datafacade'; import { NavLink } from 'react-router-dom'; +import Loader from 'react-loader-spinner'; +import { usePromiseTracker } from "react-promise-tracker"; +const LoadingIndicator = props => { + const { promiseInProgress } = usePromiseTracker(); + return promiseInProgress && +
+ +
+}; class Leaderboard extends React.Component { constructor(props) { @@ -8,13 +25,17 @@ class Leaderboard extends React.Component { this.state = { players: [], breakload: true, + scrollListener: {}, }; + this.scrollListener = this.handleScroll.bind(this); } componentWillMount() { - this.scrollListener = window.addEventListener("scroll", e => { - this.handleScroll(e); - }); + window.addEventListener('scroll', this.scrollListener); + } + + componentWillUnmount() { + window.removeEventListener("scroll", this.scrollListener); } componentDidMount = async () => { @@ -45,18 +66,23 @@ class Leaderboard extends React.Component { this.setState({ breakload: true }) } - render() { return ( +
+
+
+ +

MapBoard

+
+
+
+
    - -

    MapBoard

    -


    {this.state.players.map(e => ( @@ -73,9 +99,9 @@ class Leaderboard extends React.Component { ))} - {!this.state.breakload ?



    - Loading More Players... -

    : ""} + {!this.state.breakload ?

    + Loading Players


    +

    : ""}
@@ -84,4 +110,5 @@ class Leaderboard extends React.Component { } } + export default Leaderboard; \ No newline at end of file diff --git a/RaceTimer/racetimer_react/src/MapBoard/MapBoard.js b/RaceTimer/racetimer_react/src/MapBoard/MapBoard.js index 1147f665..ab630da6 100644 --- a/RaceTimer/racetimer_react/src/MapBoard/MapBoard.js +++ b/RaceTimer/racetimer_react/src/MapBoard/MapBoard.js @@ -1,48 +1,82 @@ import React from 'react'; import Facade from '../Datafacade/datafacade'; import { NavLink } from 'react-router-dom'; +import Loader from 'react-loader-spinner'; +import { usePromiseTracker } from "react-promise-tracker"; +import '../css/style.css'; +const LoadingIndicator = props => { + const { promiseInProgress } = usePromiseTracker(); + return promiseInProgress && +
+ +
+}; + class MapBoards extends React.Component { - constructor(props) { super(props) this.state = { - maps: [] + maps: [], + breakload: false, }; } + componentWillMount = async () => { - const maps = await Facade.getAllMapsFromCache(); + this.setState({ breakload: false }) + const maps = await Facade.getMapCountFromCache(); this.setState({ maps }); + this.setState({ breakload: true }) }; render() { return ( +
+
+
+ +

Leaderboard

+
+
+
+
+
+
-
- -

leaderboard

-
-
-
+
{this.state.maps.map(e => ( -
- - Map: {e.mapname}
- Stage: {e.mapstage}
-
-
-
+
+
+
  • +
    + + Map: {e.mapname}
    + Stage: {e.mapstage}
    +
    +
    +
    +
    +
  • +
    ))} - /
    +
    + {!this.state.breakload ?

    + Loading Maps


    +

    : ""}
    ); } - } export default MapBoards; \ No newline at end of file diff --git a/RaceTimer/racetimer_react/src/Maps/Maps.js b/RaceTimer/racetimer_react/src/Maps/Maps.js index 172a7ed4..5ccd15f9 100644 --- a/RaceTimer/racetimer_react/src/Maps/Maps.js +++ b/RaceTimer/racetimer_react/src/Maps/Maps.js @@ -1,6 +1,25 @@ import React from 'react'; import Facade from '../Datafacade/datafacade'; import { NavLink } from 'react-router-dom'; +import Loader from 'react-loader-spinner'; +import { usePromiseTracker } from "react-promise-tracker"; +import '../css/style.css'; + +const LoadingIndicator = props => { + const { promiseInProgress } = usePromiseTracker(); + return promiseInProgress && +
    + +
    +}; class Maps extends React.Component { @@ -9,57 +28,102 @@ class Maps extends React.Component { this.state = { mapTimes: [], mapName: '', + breakload: true, + scrollListener: {}, + fetchsize: 0, }; + this.scrollListener = this.handleScroll.bind(this); } componentWillMount = async () => { + window.addEventListener('scroll', this.scrollListener); + this.setState({ breakload: false }) const mapname = this.props.match.params.mapname; const stage = this.props.match.params.stage; - const mapTimes = await Facade.getMapTimesFromCache(mapname, stage); + const mapTimes = await Facade.getMapTimesFromCache(mapname, stage, 0); + const fetchsize = await Facade.getMapTimesFromCacheSize(mapname, stage); this.setState({ mapTimes }); this.setState({ mapName: mapname }) + this.setState({ breakload: true }) + this.setState({ fetchsize }); }; + componentWillUnmount() { + window.removeEventListener("scroll", this.scrollListener); + } + + findSecondLast(array) { + return array[array.length - 2]; + } + + handleScroll = () => { + if (this.state.breakload && this.state.fetchsize > this.state.mapTimes.length) { + const player = this.findSecondLast(this.state.mapTimes); + var lastLi = document.getElementById('maps/' + player.steamID); + var lastLiOffset = lastLi.offsetTop + lastLi.clientHeight; + var pageOffset = window.pageYOffset + window.innerHeight; + if (pageOffset > lastLiOffset) { + this.setState({ breakload: false }) + this.loadPlayers(); + } + } + }; + + loadPlayers = async () => { + const mapname = this.props.match.params.mapname; + const stage = this.props.match.params.stage; + const mapTimes = await Facade.getMapTimesFromCache(mapname, stage, this.state.mapTimes.length + 1); + this.setState({ mapTimes }); + this.setState({ breakload: true }) + } + render() { return ( +
    - -

    leaderboard

    -
    - -

    MapBoard

    -
    +
    +
    + +

    leaderboard

    +
    +
    +
    + +

    MapBoard

    +
    +
    +
    -
    +
    -

    -
    - {this.state.mapName}
    -
    -
    - {this.state.mapTimes.map(e => ( -
    -
    - - SteamID: {e.steamID}
    - Name: {e.name}
    -
    -
    - Position: {e.position}
    - Mappoints: {e.mapPoint}
    - Time: 0{e.mapTimeMinutes}:{e.mapTimeSeconds}
    -
    -
    -
    +

    {this.state.mapName}

    +
    +
    + {this.state.mapTimes.map(e => ( +
  • +
    + + SteamID: {e.steamID}
    + Name: {e.name}
    +
    +
    + Position: {e.position}
    + Mappoints: {e.mapPoint}
    + Time: 0{e.mapTimeMinutes}:{e.mapTimeSeconds}
    +
    +
    - ))} +
  • + ))} + {!this.state.breakload ?

    + Loading Players

    +

    : ""} -
    diff --git a/RaceTimer/racetimer_react/src/Player/Player.js b/RaceTimer/racetimer_react/src/Player/Player.js index b68ebe79..75a678e4 100644 --- a/RaceTimer/racetimer_react/src/Player/Player.js +++ b/RaceTimer/racetimer_react/src/Player/Player.js @@ -1,7 +1,24 @@ import React from 'react'; import Facade from '../Datafacade/datafacade'; import { NavLink } from 'react-router-dom'; - +import Loader from 'react-loader-spinner'; +import { usePromiseTracker } from "react-promise-tracker"; +import '../css/style.css'; +const LoadingIndicator = props => { + const { promiseInProgress } = usePromiseTracker(); + return promiseInProgress && +
    + +
    +}; class Player extends React.Component { constructor(props) { super(props) @@ -9,20 +26,68 @@ class Player extends React.Component { player: {}, mapTimes: [], breakload: true, + scrollListener: {}, }; + this.scrollListener = this.handleScroll.bind(this); } componentWillMount = async () => { + window.addEventListener('scroll', this.scrollListener); + this.setState({ breakload: false }) const steamid = this.props.match.params.steamid; const player = await Facade.getPlayerFromCache(steamid); - const mapTimes = await Facade.getPlayerTimesFromCache(steamid); + const mapTimes = await Facade.getPlayerTimesFromCache(steamid, 0); this.setState({ player }); this.setState({ mapTimes }); + this.setState({ breakload: true }) }; + componentWillUnmount() { + window.removeEventListener("scroll", this.scrollListener); + } + + findSecondLast(array) { + return array[array.length - 2]; + } + + handleScroll = () => { + if (this.state.breakload && this.state.player.Times > this.state.mapTimes.length) { + const map = this.findSecondLast(this.state.mapTimes); + var lastLi = document.getElementById("playermaps/" + map.mapname + "/" + map.mapstage); + var lastLiOffset = lastLi.offsetTop + lastLi.clientHeight; + var pageOffset = window.pageYOffset + window.innerHeight; + if (pageOffset > lastLiOffset) { + this.setState({ breakload: false }) + this.loadMaps(); + } + } + }; + + loadMaps = async () => { + const steamid = this.props.match.params.steamid; + const mapTimes = await Facade.getPlayerTimesFromCache(steamid, this.state.mapTimes.length + 1); + this.setState({ mapTimes }); + this.setState({ breakload: true }) + } + render() { return ( +
    +
    +
    + +

    leaderboard

    +
    +
    +
    + +

    MapBoard

    +
    +
    +
    +
    +
    {this.state.mapTimes.map(e => ( -
    +
  • Map: {e.mapname}
    Stage: {e.mapstage}
    @@ -49,8 +114,12 @@ class Player extends React.Component {

    -
  • + ))} + {!this.state.breakload ?

    + Loading Stats

    +

    : ""} +
    diff --git a/RaceTimer/racetimer_react/src/css/style.css b/RaceTimer/racetimer_react/src/css/style.css index df7d0c64..6e168fd4 100644 --- a/RaceTimer/racetimer_react/src/css/style.css +++ b/RaceTimer/racetimer_react/src/css/style.css @@ -7584,4 +7584,56 @@ a.social_bt.google:before { .react-fetch-progress-bar { backgroundColor: red !important; height: 10px; + } + + .rowBoards{display:flex; flex-direction:row;} + + #containerMaps { + width:100%; + text-align:center; +} + +#containerMaps > div { + width: calc(100% / 6); + display: inline-block; + vertical-align: top; + text-align:center; + margin:2%; + padding:20px; +} + + +#containerMaps2 { + width:100%; + text-align:center; +} + +#containerMaps2 > div { + width: calc(100% / 10); + display: inline-block; + vertical-align: top; + text-align:center; + margin:2%; +} + +.centered { + height: 20vh; /* Magic here */ + display: flex; + justify-content: center; + align-items: center; + } + + .rowC{display:flex; flex-direction:row;} + + .flexbox-container { + display: flex; + flex-direction: row; + height: 100vh; + width: 100%; +} + +.myForm { + max-width: 1000px; + display: flex; + flex-wrap: wrap; } \ No newline at end of file